Alibaba Cloud Container Registry (ACR) でコンテナイメージのビルドパイプラインを実装する

こんにちは、ソリューションアーキテクトの有馬です。


今回はDocker イメージのビルドから、ビルドしたイメージをContainer Service for Kubernetes (ACK) へデプロイするまでのビルドパイプラインを、Alibaba Cloud Container Registry (ACR) を使用して実装して見たいと思います。

f:id:sbc_sarima:20200327180951p:plain

はじめに


コンテナを使用している環境では、コンテナイメージの保存先としてDocker Hub等のサービスやクラウドベンダーが提供しているマネージドのプロダクトを利用しているかと思います。
Alibaba Cloud でもコンテナイメージをマネージドで利用可能なプロダクト、Alibaba Cloud Container Registry (ACR) があります。

※ Alibaba Cloud Container Registry (ACR) はAlibaba Cloud 国際サイトで利用可能です。
※ 以降はAlibaba Cloud Container Registry を「ACR」と記載します。
※ ブログ内で「イメージ」と記載されている部分は「Docker イメージ」の事を指します。


Alibaba Cloud Container Registry (ACR) の特徴


ACRで提供している主な機能以下のようになっています。

f:id:sbc_sarima:20200331142614p:plain

また、ACRにはDefault Instance EditionとEnterprise Editionがあり、後者は日本リージョンではまだローンチされていない為、今回はDefault Instance Editionを利用します。
Default Instance EditionとEnterprise Editionの違いは以下のドキュメントをご覧頂ければと思います 。
Enterprise Editionはより高速なイメージ転送や、グローバル間での利用に特化した機能をサポートしている事から、複数のリージョンからイメージを使用する等の場合に適しています。

f:id:sbc_sarima:20200326174701p:plain

引用:https://www.alibabacloud.com/help/doc-detail/111958.htm



コンテナイメージのビルドプロセス


コンテナイメージを開発しデプロイするまでのプロセスは、環境によって内容や順序は異なるかとは思いますが、以下のような項目が考えられます。 開発者はDockerfileを作成しコードリポジトリへアップロードします。アップロードされたコードはビルド・テストを経て、最終的に各環境へデプロイするようなプロセスとなるかと思います。

f:id:sbc_sarima:20200330154252p:plain

ACRビルドパイプラインの作成

ビルドパイプライン


では、ここからACRを使用してDocker イメージのビルドからデプロイまでを自動で実行するパイプラインを作成してみたいと思います。
以下は今回作成するビルドパイプラインの構成です。前述の特徴で記載しましたACRの各機能を使用し、ビルドパイプラインを作成していきます。
また、デプロイ先にACKを利用している為、以降の説明ではACKが作成されている事を前提として進めていきます。

f:id:sbc_sarima:20200330185020p:plain

Githubリポジトリの準備


GitHubへDockerfileをアップロードするリポジトリを作成します。
今回はGitHubへ以下の「acr_demo_app」と言うリポジトリ名で作成しました。 f:id:sbc_sarima:20200326175857p:plain

Alibaba Cloud Container Registry (ACR) 設定


次にACR側の設定を実施していきたいと思います。

コードソース設定


ACRでDocker イメージをビルドする際に使用する、Dockerfileが保存されるGitリポジトリの設定を行います。
今回はGitHubを使用していますが、他にもBitbucketやGitLabをコードソースのGitリポジトリとして設定する事が可能です。

Code Source設定画面から「Bind Account」を選択し、連携するGitHubアカウントのOAuth AppsへACRを登録します。 f:id:sbc_sarima:20200326193710p:plain f:id:sbc_sarima:20200326200249p:plain

GitHubでの認証が完了すると、Code SourceのステータスがUnboundからBoundへ変更されました。 f:id:sbc_sarima:20200326200610p:plain


Namespace設定

ACRへNamespaceを作成します。
Namespaceは組織や役割、チームやユーザと言った、ある程度の範囲でコンテナリポジトリをグループ化する機能となります。


「namespace_demo」と言うNamespaceを作成しました。
f:id:sbc_sarima:20200326205908p:plain f:id:sbc_sarima:20200326210223p:plain


イメージリポジトリ作成


Docker イメージを保存するリポジトリを作成します。
先ほど作成したネームスペースを選択し、リポジトリ名を「app」としました。
Repository Typeでプライベートかパブリックで公開先の設定可能です。今回は検証が目的の為Publicを選択しています。

f:id:sbc_sarima:20200327102724p:plain

Code Sourceは先ほど設定したGitHubのユーザとリポジトリが選択可能となっているので、Dockerfileのアップロード先のリポジトリを選択します。
また、自動ビルドを有効にする事で、以降で設定するビルドルールに一致した場合に、Docker イメージのビルドが自動で開始されます。 f:id:sbc_sarima:20200327102731p:plain

GitHubのリポジトリセッティングを見てみると、ACRへのWebhookが作成されました。 f:id:sbc_sarima:20200327133408p:plain


ビルドルール設定


ビルドルールは、対象のソースコードリポジトリのブランチ・タグへイベントがあった場合、イメージのビルドを開始させる為の設定となります。
以下の例では、Dockerfileをアップロードするリポジトリの「master」ブランチへPushイベントがあった場合にビルドが開始されるように設定しています。 また、ビルドが完了したDocker イメージへ「latest」タグが設定されます。

f:id:sbc_sarima:20200327172650p:plain f:id:sbc_sarima:20200327134657p:plain

今回は検証の為簡易的な内容でブランチとイメージタグの設定を行なっていますが、実際の運用では開発ブランチや、ステージング用のブランチ、またイメージタグについてもそれぞれの環境に合わせた設定がされるかと思います。


ビルド確認


ではDockerfileを作成し、GitHubのmasterブランチへPushしてみます。
今回使用するDockerfileではnginxのイメージを使用しています。後ほどイメージをアップデートした際の変化をわかりやすくする為、index.htmlの書き換えを行なっています。

Dockerfile

FROM nginx
RUN echo "<h1>ACR Demo App v1</h1>" > /usr/share/nginx/html/index.html


作成したDockerfileをmasterブランチへPushします。

# git add Dockerfile 
# git commit -m "ACR Demo App v1"
# git push origin master


Build StatusがBuildingになりビルドが開始されました。 f:id:sbc_sarima:20200327141445p:plain


Build Statusが47秒でビルドが完了しました。 f:id:sbc_sarima:20200327141007p:plain


Tagsから確認してみると、latestタグでイメージが作成されている事が確認できます。 f:id:sbc_sarima:20200327142128p:plain

Security ScanとImage Layers


今回の趣旨とは少しずれますが、「Tages」の右側のSecurity Scanから、イメージに対してセキュリティスキャンの実行が可能となっており、脆弱性のレポーティングを確認する事ができます。
こちらのイメージをスキャンしてみると、以下のようにレポーティング表示してくれます。

f:id:sbc_sarima:20200327142849p:plain


また、Image Layersからは、イメージをビルドした際に実行された内容を確認する事ができます。 f:id:sbc_sarima:20200327142732p:plain


トリガーURL取得


ここまでで、GitHubのmasterブランチへDockerfileをPushし、Docker イメージのビルドが自動で実行される事が確認できました。
次にビルドされたイメージを、指定したDeploymentへ継続して更新されるようにトリガーURLの設定をしていきます。 ACRでビルドしたイメージを、ACKへデプロイする為には「Trigger URL」が必要となります。「Trigger URL」とはイメージのデプロイ先であるDeploymentへのリンクとなります。

Deployment作成


まずはACKへDeploymentを作成する為、マニフェストを作成します。 イメージの取得先として、先ほど作成されたイメージのエンドポイントとタグを指定しています。
また、ブラウザからイメージのアップデートを確認する為、ServiceでLoadBalancerを設定しています。

kubernetes manifest

cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    run: app
  name: app
spec:
  replicas: 1
  selector:
    matchLabels:
      run: app
  template:
    metadata:
      labels:
        run: app
    spec:
      containers:
      - image: registry-intl-vpc.ap-northeast-1.aliyuncs.com/namespace_demo/app:latest
        imagePullPolicy: Always
        name: app
---
apiVersion: v1
kind: Service
metadata:
  labels:
    run: app
  name: app
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    run: app
  type: LoadBalancer
EOF


作成されたPodと、LoadBalancerのEXTERNAL-IPを確認します。

# kubectl get pod
NAME                  READY   STATUS    RESTARTS   AGE
app-5f79d7c56-qnrrm   1/1     Running   0          2s

# kubectl get svc -l run=app
NAME   TYPE           CLUSTER-IP     EXTERNAL-IP    PORT(S)        AGE
app    LoadBalancer   172.21.12.19   47.245.8.224   80:30581/TCP   45s


ブラウザからEXTERNAL-IPを表示します。
先ほど作成したイメージでコンテナが起動している事がわかります。 f:id:sbc_sarima:20200327154245p:plain

ACKのデプロイメントから、今回作成した「app」を選択し、「Trigger URL」の設定を行います。
少し下の方に「トリガーの作成」の項目があるので、そちらから「再デプロイ」を選択し設定します。 f:id:sbc_sarima:20200327154950p:plain

以下のように作成されたトリガーリンクが、ACRで使用するTrigger URLとなります。 f:id:sbc_sarima:20200327155406p:plain

トリガー設定


ACRのコンソールに戻り、先ほど取得したトリガーリンクを「Trigger URL」へ設定します。
ここで選択可能なトリガーの条件ですが、「イメージ作成時に毎回デプロイする」、「イメージのタグを正規表現でフィルタリングしマッチした場合デプロイする」、「指定したイメージのタグにマッチした場合デプロイする」の3種類のトリガーが選択可能です。
今回はイメージタグに「latest」が指定されたイメージをデプロイする設定としています。

f:id:sbc_sarima:20200327160424p:plain

ここでは先ほど作成したDeploymentを指定しトリガーを設定していますが、別のDeploymentのトリガーを設定する事で、複数のDeploymentへのイメージを更新する事も可能です。

ビルド・デプロイ確認


では最後にイメージを更新し、DeploymentのPodが更新される事を確認したいと思います。

先ほどのDockerfileの表示する文字列をv1からv2へ変更します。

FROM nginx
RUN echo "<h1>ACR Demo App v2</h1>" > /usr/share/nginx/html/index.html


GitHubのmasterブランチへ再度Pushします。

# git add Dockerfile 
# git commit -m "ACR Demo App v2"
# git push origin master


ビルドの実行が開始され成功しています。 f:id:sbc_sarima:20200327163756p:plain


ReplicaSetを確認してみると、新しいReplicaSetが作成されている事がわかります。

# kubectl get rs    
NAME            DESIRED   CURRENT   READY   AGE
app-5f79d7c56   0         0         0       56m
app-696c68bf8   1         1         1       64s


EXTERNAL-IPへブラウザから接続すると、v2へ更新されたイメージでPodが起動されている事が確認できました。 f:id:sbc_sarima:20200327164224p:plain

まとめ


Docker イメージのビルドから、デプロイを実行するビルドパイプラインをACRを使用して作成してみました。
ACRと連携させる為の設定や、ACKの設定等がいくつかあり、多少複雑な印象があったかとは思いますが、1度設定してしまえば継続して実行可能な環境を構築する事が可能となっています。
また、ビルドルールとトリガーを併用する事で、異なるネームスペースやクラスタ、リージョンへのデプロイを柔軟に振り分けたりするような使い方もできるのではないでしょうか。

f:id:sbc_sarima:20200331112616p:plain

先日配信されました「Alibaba Cloud Academy Day Online Conference」のセッションの中でも、ACRを使用したDevOpsソリューションを動画で見る事ができるので、こちらも参考になればと思います。

resource.alibabacloud.com

最後までお読みいただきありがとうございました。
次回はContainer Service for Kubernetes (ACK) と各プロダクト間の連携方法についてご紹介できればと思います。