昨年11/9,10に開催された寺田さん(https://twitter.com/yoshioterada)によるMVP受賞者向けAKSハッカソンに参加したご縁で、1/21-25にAKS/Azure DevOpsのワークショップを開催していただきました。
本日はCloud Developer Advocate 🥑@yoshioterada 氏によるMVP受賞者向けAKSハッカソンを開催中!様々な受賞カテゴリーのMVP受賞者9名のパッションが非常に熱い品川です!#Kubernetes #MVPBuzz pic.twitter.com/rVMbIQZSm5
— Rie Moriguchi (@Rie_Moriguchi) 2018年11月10日
ここでは、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)です)のサイズ、ノード数により課金されます。
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を使って順次構築していきました。
構成図
今回は、初期開発ということもあり、配置するアプリケーションもシンプルな構成なので、クラスターも極力シンプルな構成を取る方針で下記のような構成をとりました。

デプロイ
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にアクセスし作成します。
雛形のDevOps Psojectを作成
今回の扱うアプリはPHP(CakePHP)を使っていますが、現状PHPのテンプレートのデプロイターゲットにはAKSが含まれていません。
今回は初のAzure DevOps/AKSの利用ということで、AKSへのデプロイ方法の参考にするために、Java/SpringのテンプレートをつかってAKSへデプロイするプロジェクトを作成し、それをベースにカスタマイズして行く方法をとりました。
まず、雛形となるテンプレートとしてJavaを選択します。

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

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

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

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

これで実際にAzure DevOpsから、自動デプロイできる環境ができますので、内容を確認して各自の環境に合わせてカスタマイズしていくと良いでしょう。 もともと作成されるpipelineを直接直すのではなく、pipelineを新規に作成、サンプルを参考に構築していくのが良いと思います。
DeployのTIPS
秘匿情報の管理
今回のアプリは、JWKトークンを利用するため、ビルド時に証明書のアクセス権などを設定する必要がありますが、証明書をリポジトリに含めることは避けるべきです。当初、KayValutを使用しようと考えていましたが、Azure DevOpsにはSecure filesという機能があることを発見したのでこの機能を利用してビルド時に証明書を取得することにしました。
Pipelines -> Library に Secure filesタブがあるのでここで証明書ファイルをアップロードします。

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

共通処理をグルーピング
複数のpiplineで共通の処理をtask groupとしてまとめて再利用することができます。
下記のように、まとめたいtaskを選択して、右クリックして Create task group を選択すると作成することができます。

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

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に受け渡すことができます。

Build pipeline
で最終的に、build pipelineはこんな形になりました。 Build jobの前に、UnitTest用のJobを実行し、正常に終了したらbuildに進むように設定しています。
証明書ファイルの展開・コピーと、yamlファイルの更新は、Task group化しています。

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

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

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

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

まとめ
ここまでの環境を設定するのは、かなり大変ですし、いろいろとハマったところもあるので、ワークショップで寺田さんにサポートしてもらえなければ挫折していたかもしれません。本当にありがとうございました。
今まで様々な環境を利用してCI/CD環境を構築/運用してきましたが、その中でもAzure DevOpsは、VSTSで蓄積されたノウハウが詰まっていて凄く良いと感じました。もちろんOSSを使ったアプリでも問題なく使えます。このプロジェクトを通して使い倒してノウハウが溜まったらまたいつか紹介できるようにしたいと思います。
また、Kubernetesを利用する場合でも、環境や思想はそれぞれ異なるので、すべての環境が今回の形で対応できるわけではないでですが、構築を検討している方の参考になると嬉しいです。
実際のアプリの開発は、これからが本番なので気合を入れて開発を進めていきたいと思います。
参考URL
- Azure Kubernetes Service (AKS) | Microsoft Azure
- Azure Database for PostgreSQL | Microsoft Azure
- Azure Cache for Redis | Microsoft Azure
- Azure DevOps Services | Microsoft Azure
- k8s-Azure-Container-Service-AKS--on-Azure/Kubernetes-Workshop9.md at master · yoshioterada/k8s-Azure-Container-Service-AKS--on-Azure · GitHub
- Task Groups in Azure Pipelines and Team Foundation Server - Azure Pipelines | Microsoft Docs