11
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Azure Pipeline + Github使ってタダでCI/CDしちゃおう

Last updated at Posted at 2019-12-15

個人的にも仕事でもOSSの開発コミュニティで活動させてもらっている中で最近触れる機会があったAzure Pipelineについて書いていく。

本記事でカバーする範囲

AzurePipeline(とGithub)を使ったCI/CD環境作成の一例を紹介しながら以下を紹介する

  • Github上のリポジトリへのPullRequestをトリガにAzurePipelineでジョブを走らせるための基本的な流れ
  • Github上のリポジトリでリリースした際にDockerコンテナイメージをDockerHubへPushするための基本的な流れ
  • 【おまけ】 amd64だけじゃなくRaspberry Pi 3B用のコンテナイメージ(arm64v8用イメージ)も同時にビルド&リリースする

環境

  • Github上に公開されたリポジトリをターゲット
  • リポジトリには既にテスト自動化の仕組みが作り込まれている前提
  • 既にGithubのアカウントを持っている
  • 既にAzureのアカウントを持っている(無料枠でAzurePipelineは利用可能)
    • Githubのアカウントと紐付けて利用することも可能

簡単な経緯

冒頭でも触れたとおりOSSコミュニティで活動しているのだが、そこはしっかりした組織(Linux Foundation参加のHyperledger)で管理された比較的しっかりしたプロジェクトの1つ(Hyperledger Explorer)で、OSSに不慣れなしっかりしてない私でもしっかり受け入れてくれる体制が整っていた。たとえばJiraやConfluenceでワークアイテムや情報の共有がされていたり、チャットで気軽にコミュニティメンバーとコミュニケーションが取れたり、CI/CDの環境が提供されていたり、といった具合である。ただソース管理には一部の人にしか馴染みがなさそうなGerritを使っていたり、CICDはJenkins職人の助けを借りないとなかなか手を加えることができないブラックボックス気味の環境だった(あと不安定だったりした)。このへんのとっつきにくさが新しいコントリビューターにとってバリアになっていると組織の人たちも感じていて、コミュニティ内で議論が続けられていた。GitlabやCircleCIなど色々吟味した結果、AzurePipeline/Githubへの移行が決まったわけである。Jenkins/GerritからAzurePipeline/Githubへの移行はコミュニティのメンバーと協力しながら進めたわけだが、その模様をあたかも私の手柄かのようにシェアしようというわけである。とても感動したので、もし「AzurePipelineってなにそれ?」という方がいれば、是非知ってもらいたい、というのがホントのところである。

Azure Pipelineとは

Azure Pipelineとは、Azure DevOpsが提供する機能の1つである。Azure DevOpsには開発フロー全体をサポートするIssue TrackerやKanban Board、ソースリポジトリなどの機能も含まれる。Azure Pipelineは、Azure上でLinux, macOS、Windows向けに様々な言語で開発されたソフトウェアのビルドやテスト、デプロイまで面倒見てくれる。今回はLinuxをターゲットにした場合の流れを紹介するが、他のOSをターゲットに加えるのは非常に簡単である。詳しくはコチラを参照してもらいたい。私が参加しているOSSプロジェクのユーザの大半はlinuxもしくはmacOSのため、linux環境しか持ってない身としては非常に有難い。

パイプラインの設定はWeb上のエディタで可能である(VSCodeライクなキーバインドで操作可能)。予め用意された各種タスクのテンプレートを利用してYAMLファイルの操作ではあるが比較的簡単に設定は行える。

気になる利用料金であるが、ターゲットがOSSであれば、10VMまで1か月あたり時間無制限で並列利用可能とのこと(1job実行あたり60分までの時間制限はアリ)。太っ腹。

簡単な仕組みは、ターゲットとなるGithubのリポジトリにAgentがGithub Appとしてインストールされる。パイプラインの設定はリポジトリ上にYAMLファイルとしてコミットされる。これに基づいてAgentからAzure上のインスタンスが起動されて処理が走るような感じ(最後は想像)。Agentのインストール先にはオプションがいくつか用意されており、自分で管理するインスタンス(クラウドでも実サーバでも構いませんが)のようなSelf-hostedなマシンを利用することも可能です。

CI環境の作成(PullRequestからテスト実行まで)

ターゲットとなるGithub上のリポジトリを決める

先に触れたOSSコミュニティでの活動先であるHyperledger/expolorerを自身のアカウントにクローンして使用することにする。何もGithub上からターゲットを選ばなければならない訳ではない。

Azure DevOpsへログイン

今回は自身のGithubアカウントを利用してAzure DevOps(Azure Pipelineを含むサービス)を利用する。
image.png
https://azure.microsoft.com/en-au/services/devops/

サービスにログイン後、新たなプロジェクトを作成する。

image.png

プロジェクト作成の際に公開/非公開の設定やバージョン管理ツール(PipelineのVCSではなくDevOpsのVCS)の指定等が可能です。

image.png

サイドバーからPipelinesを選択して、パイプライン作成ウィザードを開始する。

image.png

ターゲットとなるリポジトリの場所を指定する。ここでGithubを選択すると、Githubのアクセス認証にリダイレクトされる。

image.png

AzureにGithubへのアクセス許可を与えるとAzure Pipeline上で自身のアカウント上に持つリポジトリの一覧が見えるようになる。そこからターゲットとなるリポジトリを選択する。

image.png

リポジトリを選択すると前述したエージェントアプリのインストール許可ダイアログが現れるので、これをターゲットのリポジトリにのみ許可する。
image.png

ここからはパイプラインの設定です。各種テンプレートからCIに必要なタスクを選ぶ。

image.png

今回のターゲットはReactで開発されたBlockchain用の可視化ツールなのでNode.js環境を選択する。

image.png

YAMLファイルをアシスタントツールを使いながらWeb上で編集する。YAMLファイルのインストール先、ファイル名はデフォルトで設定されていますが、以下のスクリーンショット内#1のところで変更可能。各ステップは直接YAMLを修正するか、#2のSettingリンクをクリックしてアシスタントツールの助けを借りて修正することも可能。

image.png

タスクを追加する場合はアシスタントツールから選択することで可能である。

image.png

最終的にazure-pipelines.ymlファイルは以下のようになる。

# Node.js
# Build a general Node.js project with npm.
# Add steps that analyze code, save build artifacts, deploy, and more:
# https://docs.microsoft.com/azure/devops/pipelines/languages/javascript

name: $(SourceBranchName)-$(Date:yyyyMMdd)$(Rev:.rrr)

trigger:
- master

pool:
  vmImage: 'ubuntu-latest'

steps:
- task: NodeTool@0
  inputs:
    versionSpec: '8.11'
  displayName: 'Install Node.js'

- task: UsePythonVersion@0
  inputs:
    versionSpec: '2.7'
    addToPath: true
    architecture: 'x64'

- script: pip install virtualenv
  displayName: Install Virtualenv

- script: |
    npm install
    npm run e2e-test-sanitycheck:ci
  displayName: Run Sanity Checks
  
- script: |
    npm install
    npm run e2e-gui-test:ci
  displayName: Run GUI Tests

本YAMLファイルのキーとなるポイントは以下の通り。

  • masterブランチに対する変更に対して本パイプラインをトリガする。どういった条件、タイミングでパイプラインをトリガするか、はtriggerの設定で柔軟にカスタマイズ可能である。詳しくはコチラを参照
  • ビルドおよびテストを実行するプラットフォームをlinux/ubuntuに指定

もしアシスタントツール内にしっくりくるテンプレートがない場合、マーケットプレイスから取得、追加することも可能。
image.png

利用可能なタスクは以下から参照可能。またマーケットプレイスから追加も可能である。
https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks

image.png

編集が完了したらSave and runを実行すると、azure-pipeline.ymlファイルがリポジトリ上にコミットされる。

image.png

Azure PipelineのDashboardを確認すると新規パイプラインが作成されて、無事に成功していることが分かる。40分近くかかってるが。

image.png

各ステップの詳細ログも参照可能。

image.png

このパイプラインの結果はGithub上で自動的に参照されており、トリガをもたらしたコミットをGithub上から参照すると下記の通りグリーンのチェックマークが見える。労せずしてソース管理とCI環境間の相互参照ができている。

image.png

Pipelineの構成

# Pipeline
stages:
- stage: A
  jobs:
  - jab: 1
    steps:
      ...
  - jab: 2
    steps:
      ...
- stage: B
  jobs:
  - jab: 1
    steps:
      ...
  - jab: 2
    steps:
      ...     

今回の例ではstepsをシーケンシャルに記載した構成だが、処理内容に基づいて、stageやjobといったより大きな括りでステップをまとめることもできる。今回の例では1つのVMインスタンスがシーケンシャルにstepを処理していくが、これを処理内容毎(例えば、ビルドやテスト、デプロイ等)にstageやjobで分割すると複数のVMで並列処理される(stage/job間に指定する依存関係にも依るが)。今回は1つのPipelineあたりの上限である60分に迫るくらいの処理内容だったが、並列処理可能な複数の処理(Run Sanity ChecksRun GUI Tests)を別々のjobで処理すれば、所要時間を減らせる。ただし、複数のjob間で同一のローカルビルドしたコンテナイメージを使用するようなケースでは、jobごとに都度コンテナイメージをビルドしなおすか、docker registryにpushする等の対応が必要である(前述したAgentをSelf-hostedマシンにインストールした場合には本制約は生じない)。

image.png

試しにPull Requestを作成してみる

以下の通りREADME.mdファイルをGithub上で少し修正してPullRequestを出してみる。
image.png

それをトリガにしてCIのパイプラインがトリガされたことがPullRequest上からも分かる。リポジトリのポリシー設定によって、このCIパイプラインのPassをマージの必要条件にすれば(あとReviewerによる承認も)、継続的インテグレーション環境の出来上がりである。
image.png

CD環境の作成(Tag付けからDocker HubへのPUSHまで)

ここで事前準備としてDocker Hubにアクセスするための秘匿情報をLibraryに保存する。保存したこの秘匿情報をパイプラインから参照する。Webからの作成手順は以下のとおりである。
image.png

前回と同じ手順でPipelineのReview画面まで進む。Configuration画面では以下のStarter pipelineを選択すること、hello-worldなパイプラインが用意される。
image.png

PipelineのReview画面で初期設定を下記のYAMLで全て上書きする。前回と異なる主なポイントは以下。

  • v*のパタンにマッチするタグが付けられたら本パイプラインがトリガされるように設定
    • 前回のパイプラインでは、trigger: masterとしていたので、masterブランチに対するあらゆる変更に対して当該のパイプラインがトリガされる。くわしくはコチラを参照
  • PullRequestではトリガされないように設定
  • Docker Hubにアクセスするための認証情報にアクセスするためのタスクを追加
  • YAMLファイル名をazure-pipeline-release.yamlにリネーム
  • 登録時にはSave and runのドロップダウンからSaveを選択
    • コミット時にも以下の通りPipelineのスキップ指示である[skip ci]をコミットメッセージ内に挿入。くわしくはコチラを参照
      image.png
# Copyright the Hyperledger Fabric contributors. All rights reserved.
#
# SPDX-License-Identifier: Apache-2.0

name: RELEASE-$(Date:yyyyMMdd)$(Rev:.rrr)
trigger:
  tags:
    include:
      - v*
pr: none

variables:
  DOCKERHUBID: 'nekia'

jobs:
- job: Release
  pool:
    vmImage: ubuntu-16.04
  steps:
  - task: DownloadSecureFile@1
    name: mySecureFile
    inputs:
      secureFile: 'passwd.txt'
  - script: 'cat $(mySecureFile.secureFilePath) | docker login --username $(DOCKERHUBID) --password-stdin'
    displayName: Login to Docker
  - script: ./build_docker_image.sh
    displayName: Build Docker Images
  - script: docker tag hyperledger/explorer $(DOCKERHUBID)/explorer:$(git describe --abbrev=0 --tags | cut -d 'v' -f 2)
    displayName: Tag Explorer Image
  - script: docker tag hyperledger/explorer-db $(DOCKERHUBID)/explorer-db:$(git describe --abbrev=0 --tags | cut -d 'v' -f 2)
    displayName: Tag Explorer DB Image
  - script: docker push $(DOCKERHUBID)/explorer
    displayName: Push Explorer Latest Image
  - script: docker push $(DOCKERHUBID)/explorer-db
    displayName: Push Explorer DB Latest Image
  - script: docker push $(DOCKERHUBID)/explorer:$(git describe --abbrev=0 --tags | cut -d 'v' -f 2)
    displayName: Push Explorer Versioned Image
  - script: docker push $(DOCKERHUBID)/explorer-db:$(git describe --abbrev=0 --tags | cut -d 'v' -f 2)
    displayName: Push Explorer DB Versioned Image

Azure Pipelineの一覧画面に新しいパイプラインが作成されているのを確認。
image.png

動作確認のため、Github上から以下の通りリリース(タグ付け)してみる。git CLIでtag付けすることで動作確認することも可能。リリース用のYAMLファイルで指定した通り、タグ名をv*のパタンで指定することだけ注意が必要。ここではv0.5.0-demoを使用。
image.png

その結果、以下の通りRelease用のパイプラインがトリガされ、10分弱で無事成功していることが確認できる。

image.png

Docker Hub上にも期待通りlinux/amd64向けのコンテナが指定したTagでPUSHされていることが確認できる。
image.png

おまけ

正直、ここまでの手順は一度CI/CD等の環境をご自身で作成された経験をお持ちの方なら特段目新しいものではない気がする。そんな方でも本投稿から何かしら持ち帰って頂けるよう、最後にオマケとして、あまり大きく取り上げられてない機能?をご紹介する。使う機会は非常に限られるとは思うが。

今回例として取り上げた本リポジトリとは別に、個人的にOSSなBlockchainプラットフォームであるHyperledger FabricのノードコンテナイメージをRaspberry Pi上で動かしたりすることがある。そのためにlinux/arm64v8用の自作コンテナイメージを作ったりするのだが、Raspberry Pi上でビルド環境構築してビルドしてPUSHして等々、色々面倒くさい。この手間をついでAzure Pipelineにお願いしてしまおうと思う。

ポイントはココに書かれている通りなのだが、要はQEMUを使って実現する。

まずはRaspberry Pi用のDockerfileとリリースパイプラインを定義したYAMLファイルを用意する。
Dockerfileの差分は以下の1行のみ。ベースイメージ(nodeやpostgresコンテナイメージ)をarm64v8ベースに切り替えるだけ。arm64v8アーキテクチャのコンテナがPipelineのJobインスタンス上で動くようになる。自身のDockerfileでベースとしているイメージ(nodeやpostgres,ubuntuなど)をココにあるようなarm64v8ベースに切り替えてやる、というわけだ。

  • 追記 今回例として使用したプロジェクトのコンテナイメージはalpineベースのnodeコンテナイメージをベースに作成しているが、これだとarmベースにアーキテクチャを切り替えた場合、docker build中のnpmコマンドがたびたび固まる事象が発生。そこでベースにするnodeコンテナイメージを少しサイズ大きめになるが無印のもの(Debianベース)に変えることで問題を回避。
$ diff -u5 Dockerfile Dockerfile-rpi3 
--- Dockerfile	2019-11-23 23:21:08.775743476 +1100
+++ Dockerfile-rpi3	2019-12-15 13:42:18.649681471 +1100
@@ -1,11 +1,11 @@
 # Copyright Tecnalia Research & Innovation (https://www.tecnalia.com)
 # Copyright Tecnalia Blockchain LAB
 #
 # SPDX-License-Identifier: Apache-2.0
 
-FROM node:8.15.0-alpine
+FROM arm64v8/node:8.15.0
 
 # default values pf environment variables
 # that are used inside container
 
 ENV DEFAULT_WORKDIR /opt

$ diff -u5 postgres-Dockerfile postgres-Dockerfile-rpi3 
--- postgres-Dockerfile	2019-11-23 23:21:08.851781477 +1100
+++ postgres-Dockerfile-rpi3	2019-12-15 13:43:40.394533490 +1100
@@ -1,11 +1,11 @@
 # Copyright Tecnalia Research & Innovation (https://www.tecnalia.com)
 # Copyright Tecnalia Blockchain LAB
 #
 # SPDX-License-Identifier: Apache-2.0
 
-FROM postgres:10.4-alpine
+FROM arm64v8/postgres:10.4-alpine
 
 # default database name for HLF Explorer db connection
 ENV DATABASE_DATABASE 	fabricexplorer
 
 # default username for HLF Explorer db connection

パイプラインでは、docker build前(ここではbuild_docker_image*.sh実行前)にmultiarch/qemu-user-staticを使ってホスト環境とは異なるアーキテクチャ用コンテナイメージの実行可能状態にする。

$ diff -u5 azure-pipelines-release.yml azure-pipelines-release-rpi3.yml 
--- azure-pipelines-release.yml	2019-12-15 13:37:36.320587461 +1100
+++ azure-pipelines-release-rpi3.yml	2019-12-15 14:41:30.946233554 +1100
@@ -21,12 +21,12 @@
     name: mySecureFile
     inputs:
       secureFile: 'passwd.txt'
   - script: 'cat $(mySecureFile.secureFilePath) | docker login --username $(DOCKERHUBID) --password-stdin'
     displayName: Login to Docker
-  - script: ./build_docker_image.sh
-    displayName: Build Docker Images
+  - script: ./build_docker_image_rpi3.sh
+    displayName: Build Docker Images for arm64v8
   - script: docker tag hyperledger/explorer $(DOCKERHUBID)/explorer:$(git describe --abbrev=0 --tags | cut -d 'v' -f 2)
     displayName: Tag Explorer Image
   - script: docker tag hyperledger/explorer-db $(DOCKERHUBID)/explorer-db:$(git describe --abbrev=0 --tags | cut -d 'v' -f 2)
     displayName: Tag Explorer DB Image
   - script: docker push $(DOCKERHUBID)/explorer
$ diff -u5 build_docker_image.sh build_docker_image_rpi3.sh 
--- build_docker_image.sh	2019-12-10 12:46:30.913925688 +1100
+++ build_docker_image_rpi3.sh	2019-12-15 14:40:58.354233554 +1100
@@ -18,16 +18,18 @@
 	echo ""
 }
 
 function deploy_build_database(){
 	echo "Building Hyperledger Fabric Database image..."
-	docker build -f postgres-Dockerfile --tag $FABRIC_EXPLORER_DB_TAG .
+	docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
+	docker build -f postgres-Dockerfile-rpi3 --tag $FABRIC_EXPLORER_DB_TAG .
 }
 
 function deploy_build_explorer(){
 	echo "Building Hyperledger Fabric explorer image..."
-	docker build --tag $FABRIC_EXPLORER_TAG .
+	docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
+	docker build -f Dockerfile-rpi3 --tag $FABRIC_EXPLORER_TAG .
 }
 
 banner
 
 deploy_build_explorer

で改めてGithub上でリリースしてやると無事にRaspberry Pi用リリースパイプラインもトリガされた。が、QEMUを噛ましているせいか、あまりにも処理が遅くて1Jobあたり60分の制約に引っ掛かりパイプラインがタイムアウトするという結果に終わった。今後何かしら手立てが打てたら続報お伝えしたいと思う。見切り発車でゴメンナサイ。 Docker Hub上にも、armアーキテクチャなイメージがPUSHされている。

image.png

最後に

非常にながくなりましたが、MicrosoftのOSS Loveな姿勢は非常に徹底していて、近頃のオープンな活動ぶりには個人的に好感が持てます(上からですみません)。Azure DevOpsの開発上についてもMicrosoft内部の3 week sprintの様子を公開していて可視性が高いです。
今回シェアしたこのような情報は、OSSコミュニティに身を置いたことで得られた恩恵の1つといえます。もちろんGive and takeではありますが。仕事ではなかなか触れることのできない様々な良い機会/経験をOSS活動は与えてくれます。是非皆さんも気軽にOSS活動に足を突っ込んでみることをおすすめしたいです。

11
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?