Azure Kubernetes Service (AKS)の構築とAzure DevOpsを使用したCI/CD pipelineの作成

昨年11/9,10に開催された寺田さん(https://twitter.com/yoshioterada)によるMVP受賞者向けAKSハッカソンに参加したご縁で、1/21-25にAKS/Azure DevOpsのワークショップを開催していただきました。

ここでは、AKSクラスタ構築の概要とAKS、Azure DevOpsを利用したCI/CD pipeline構築の一例を紹介したいと思います。なお、Kubernetes,AKS,Azure DevOps全て日々成長を続けていますのでここで紹介する内容は執筆時点での情報なのでご注意下さい。

Azure Kubernetes Service (AKS)

Azure Kubernetes Service (以下、AKS)は、フルマネージドなKubernetesクラスタを提供するサービスです。Kunernetes全体を管理するクラスター マスター(俗にいう管理ノード)は、マネージド Azure リソースとして提供され、このノードには課金されず、Kubernetesクラスタをう構成する各ノード(実態はAzure Vrtual Machine (VM)です)のサイズ、ノード数により課金されます。

azure.microsoft.com

Container Registoryの準備

AKSの構築に先立って、Azure Container Registoryに、アプリのコンテナイメージを用意した状態で作業を開始しました。

AKSの構築

今回のターゲットになるアプリは、Azure Database for PostgreSQLと、Azure Redis Cacheを使用します。Azure Database for PostgreSQLは、どのサイズでもVNetに対応していますが、Redis CacheはプレミアムプランでないとVNet対応機能が使えません。プレミアムプランは今回のアプリ規模にはマッチしないということで、VNetへの配置は諦め、スタンダードプランを利用し、IPアドレスで制限する形にすることにしました。

実際の構築はステージング環境を想定して、MSの寺田さんが公開されている下記を雛形にAzure CLIを使って順次構築していきました。

github.com

構成図

今回は、初期開発ということもあり、配置するアプリケーションもシンプルな構成なので、クラスターも極力シンプルな構成を取る方針で下記のような構成をとりました。

f:id:kaz_29:20190127161049j:plain
構成図

デプロイ

admin

adminに関しては、管理者のみが使用する機能なので、シンプルに特定のブランチが更新されると、Azure DevOpsでビルドが始まり自動でリリースされる方式を取りました。

api

apiに関しては、B/Gデプロイメントに近い以下のような形を取りました。

  • 特定のブランチの更新をトリガーにビルド開始
  • UnitTestを実行
  • ビルド番号をタグとして利用し、ACRにコンテナイメージをプッシュ
  • ビルド番号をコンテナのタグ、セレクタとして指定し、green serviceにapply
  • 担当者にリリース承認メールを送信
  • green側で動作確認後に、担当者がリリース
  • blue serviceのセレクタを新しいビルド番号に更新しapply
  • 問題がなければ古いビルド番号のdeploymentを手動で削除

最後の古いデプロイメントの削除に関しては、ビルド番号がエラーなどで飛んでしまうなど自動化するためにはいくつかハードルがあるため、現状は手動で削除する形をとっています。

Azure DevOps側の詳細については後述します。

今回のワークショップでは、モブプログラミングの様なフォーマットで、定期的にドライバを交代しながら作業を進めました、そのおかげで参加した全員が実際の構築を体感できたので、後半では活発にアドバイスすや意見が出て全員の理解度が上がっていることを体感できました。この形式は今後会社の業務でも取り入れていきたいと思います。

最終的にクラスタの構築は、弊社のイケメンエンジニアたちがTerraformで自動構築できるようにしてくれて、いつでもクラスタを再現できるようになりました。AKSクラスタの構築に関する詳細は近いうちにブログにまとめられるはずなので、公開されたら追記します。

Azure DevOps

Azure DevOpsのオーガニゼーションを作成する

まだ、Azure DevOpsのオーガニゼーションがない場合は、https://dev.azure.comにアクセスし作成します。

dev.azure.com

雛形のDevOps Psojectを作成

今回の扱うアプリはPHP(CakePHP)を使っていますが、現状PHPのテンプレートのデプロイターゲットにはAKSが含まれていません。

今回は初のAzure DevOps/AKSの利用ということで、AKSへのデプロイ方法の参考にするために、Java/SpringのテンプレートをつかってAKSへデプロイするプロジェクトを作成し、それをベースにカスタマイズして行く方法をとりました。

まず、雛形となるテンプレートとしてJavaを選択します。

f:id:kaz_29:20190127162442j:plain

フレームワークは何でもいいのでとりあえずSpringを選択します。

f:id:kaz_29:20190127162510j:plain

デプロイ先はAKSを選択します。

f:id:kaz_29:20190127182454j:plain

Azure DevOpsのプロジェクト名、オーガニゼーションを選択し、AKSクラスタはすでに構築済みなので、Use Existingを選択して、デプロイ先のAKSクラスタを指定します。

f:id:kaz_29:20190127162251j:plain

Doneをクリックすると構築が始まるのでしばらく待ちます。いろいろとデプロイが進みAzure Portalに以下のような画面が現れます。

f:id:kaz_29:20190127162100j:plain

これで実際にAzure DevOpsから、自動デプロイできる環境ができますので、内容を確認して各自の環境に合わせてカスタマイズしていくと良いでしょう。 もともと作成されるpipelineを直接直すのではなく、pipelineを新規に作成、サンプルを参考に構築していくのが良いと思います。

DeployのTIPS

秘匿情報の管理

今回のアプリは、JWKトークンを利用するため、ビルド時に証明書のアクセス権などを設定する必要がありますが、証明書をリポジトリに含めることは避けるべきです。当初、KayValutを使用しようと考えていましたが、Azure DevOpsにはSecure filesという機能があることを発見したのでこの機能を利用してビルド時に証明書を取得することにしました。

Pipelines -> Library に Secure filesタブがあるのでここで証明書ファイルをアップロードします。

f:id:kaz_29:20190127184907j:plain

アップロードしたファイルは、ビルドpipeline内で利用できる Download Secure File タスクを使用してダウンロードすることができます。タスクを実行すると、$(Agent.TempDirectory)以下にダウンロードされますので、Command Lineタスクなどを使用して、所定の場所に移動するなどして利用可能です。

f:id:kaz_29:20190127161900j:plain

共通処理をグルーピング

複数のpiplineで共通の処理をtask groupとしてまとめて再利用することができます。

下記のように、まとめたいtaskを選択して、右クリックして Create task group を選択すると作成することができます。

f:id:kaz_29:20190127183055j:plain

Manage task groupを選択すると、Task groupの内容を編集することができます。

f:id:kaz_29:20190127183124j:plain

deplyment.yamlの更新

テンプレートでは、hemlを利用してデプロイを実施しているのですが、今回はビルド時にdeployment.yamlのタグやバージョンを更新してapployする方式をとっています。

下記のようにsedコマンドを使用して、テンプレート内のVERSIONという文字列を、実行中のビルド番号に置換して実現しています。

sed -i -e "s|VERSION|$(Build.BuildId)|g" /home/vsts/work/1/s/kubernetes/deployment.yaml

deployment.yaml抜粋

apiVersion: apps/v1
kind: Deployment
metadata:
  name: appname-VERSION
spec:
  replicas: 3
  selector:
    matchLabels:
      app: appname
...
  template:
    metadata:
      labels:
        app: appname
        version: vVERSION
        stage: staging
    spec:
      securityContext:
        runAsUser: 33
      imagePullSecrets:
        - name: docker-reg-credential
      containers:
      - name: appname
        image: appnameacr.azurecr.io/appname-api:VERSION
....

service.yaml

apiVersion: v1
kind: Service
metadata:
  labels:
    app: appname
  name: green-service
spec:
  ports:
  - port: 80
    name: http
    targetPort: 8080
  selector:
    app: appnemr
    version: vVERSION
  sessionAffinity: None
  type: ClusterIP

metadataの値は文字列である必要があるため、ビルド番号ではなく v10 の様にプレフィックスをつけています。

変更したyamlファイルをrelease pipelineに引き渡す

前の手順でsedで変更したファイルを、release pipelineで利用するために、Artifactディレクトリにコピーする必要があります。

Copy file taskを利用して、必要なファイルを$(build.artifactstagingdirectory) にコピーすることで、後続のpipelineに受け渡すことができます。

f:id:kaz_29:20190127183214j:plain

Build pipeline

で最終的に、build pipelineはこんな形になりました。 Build jobの前に、UnitTest用のJobを実行し、正常に終了したらbuildに進むように設定しています。

証明書ファイルの展開・コピーと、yamlファイルの更新は、Task group化しています。

f:id:kaz_29:20190127162346j:plain

Release pipeline

Release pipelineはこんな感じになりました。

f:id:kaz_29:20190127183314j:plain

Apply to greenApply to blueは以下のように、Post-deployment approvalsを有効にして、担当者の承認後に進むように設定しました。

f:id:kaz_29:20190127183352j:plain

Apply to green では、deploymment.yamlとgreen_service.yamlDeploy to Kubenetes taskを指定してapplyしています。

f:id:kaz_29:20190127183418j:plain

Apply to blueでは、blue_service.yamlをapplyしています。

f:id:kaz_29:20190127183440j:plain

まとめ

ここまでの環境を設定するのは、かなり大変ですし、いろいろとハマったところもあるので、ワークショップで寺田さんにサポートしてもらえなければ挫折していたかもしれません。本当にありがとうございました。

今まで様々な環境を利用してCI/CD環境を構築/運用してきましたが、その中でもAzure DevOpsは、VSTSで蓄積されたノウハウが詰まっていて凄く良いと感じました。もちろんOSSを使ったアプリでも問題なく使えます。このプロジェクトを通して使い倒してノウハウが溜まったらまたいつか紹介できるようにしたいと思います。

また、Kubernetesを利用する場合でも、環境や思想はそれぞれ異なるので、すべての環境が今回の形で対応できるわけではないでですが、構築を検討している方の参考になると嬉しいです。

実際のアプリの開発は、これからが本番なので気合を入れて開発を進めていきたいと思います。

参考URL