Helm ChartをArtifact Registryに保存してCloud Deployから利用する
こんにちは、クラウドエースの錦木です。
Cloud Deployが利用するskaffoldがHelm Chartを利用できることと、Artifact RegistryがHelm Chartを保存できることを知りました。
これらを組み合わせれば、マニフェストの管理及びそのデプロイパイプラインに新たな可能性を見出だせる気がするため、とりあえず触ってみようという趣旨です。
Cloud DeployからArtifact Registryに保存したHelm Chartを利用して、
GKEで起動したKubernetesクラスタにアプリケーションをデプロイするパイプラインを構築し、サンプルコードを提供するのがこの記事の目的です。
記事中のコードはGitHubに公開していますので、よろしければ参照してください。
特に断りがない限り、記載のコマンドは全てこのrepositoryのルートディレクトリで実行しています。
Helm Chartの用意
Artifact Registryに保存し、KubernetesクラスタにデプロイするためのHelm Chartを用意します。
話を簡単にするために、なるべく単純なChartを用意しましょう。
helm create nginx
とすることでHelm Chartの雛形を用意できるので、これを利用しても良いです。
今回はこれを更に単純にしたものを使っています。
Artifact RegistryへHelm Chartを保存する
続いて、このHelm ChartをArtifact Registryへ保存しましょう。
基本的には、ドキュメントに記載のことをそのままやっているだけです。
まずはrepositoryを作成します。
名前はなんでも良く、ここではifrit
とします。
gcloud artifacts repositories create ifrit --repository-format=docker --location=asia-northeast1
この時repositoryのIDはasia-northeast1-docker.pkg.dev/<PROJECT_ID>/ifrit
となります。
次に、Helm Chartをパッケージとしてまとめます。
helm package chart/ --version=0.1.0
すると、nginx-0.1.0.tgz
というファイルが作成されます。
nginx
の部分は、chart/Chart.yaml
中のname
プロパティの値です。
続いて、helmがrepositoryへpushできるように、Artifact Registryに対して認可を得ます。
gcloud auth print-access-token | helm registry login -u oauth2accesstoken \
--password-stdin https://asia-northeast1-docker.pkg.dev
ここまでできれば、helm push
によってrepositoryへHelm Chartを保存できるようになります。
helm push nginx-0.1.0.tgz \
oci://asia-northeast1-docker.pkg.dev/<PROJECT_ID>/ifrit
Cloud Deployの用意
Cloud Deployでは、Delivery Pipeline
(以後 Pipeline)という単位でデプロイを管理します。
次のようなマニフェストファイルをdeploy.yaml
という名前で用意し、gcloud
コマンドによってPipelineを作成します。
apiVersion: deploy.cloud.google.com/v1
kind: DeliveryPipeline
metadata:
name: helm-deploy-gke
description: main application pipeline
serialPipeline:
stages:
- targetId: gke-dev
profiles: [dev]
- targetId: gke-prod
profiles: [prod]
---
apiVersion: deploy.cloud.google.com/v1
kind: Target
metadata:
name: gke-dev
description: GKE development environment
gke:
cluster: projects/<PROJECT_ID>/locations/asia-northeast1/clusters/<CLUSTER_NAME>`
---
apiVersion: deploy.cloud.google.com/v1
kind: Target
metadata:
name: gke-prod
description: GKE production environment
gke:
cluster: projects/<PROJECT_ID>/locations/asia-northeast1/clusters/<CLUSTER_NAME>`
このマニフェストファイルは 「dev環境で動作検証ができたらprod環境へデプロイをする」 デプロイフローを意識して書いています。
次図のようなイメージです。
Pipelineを作成する際には、gcloud deploy apply
を次のように利用します。
gcloud deploy apply --file=deploy.yaml --region=asia-northeast1
Cloud Deployのコンソールでは、次のように見えているはずです。
これでCloud Deployの用意ができました。
Let's Deploy
Cloud DeployがGKEやCloud Runへコンテナをデプロイする時に利用するものがSkaffoldの定義ファイルです。
GitHub repositoryに公開しているskaffold.yaml
をここにも貼っておきます。
apiVersion: skaffold/v2beta29
kind: Config
metadata:
name: helm-deploy-gke
profiles:
- name: dev # targetId`gke-dev`に記載のprofilesと一致
deploy:
helm:
releases:
- name: dev
remoteChart: oci://asia-northeast1-docker.pkg.dev/<PROJECT_ID>/ifrit/nginx
version: 0.1.0
valuesFiles:
- values.develop.yaml
- name: prod # targetId`gke-prod`に記載のprofilesと一致
deploy:
helm:
releases:
- name: prod
remoteChart: oci://asia-northeast1-docker.pkg.dev/<PROJECT_ID>/ifrit/nginx
version: 0.1.0
valuesFiles:
- values.prod.yaml
ここに書かれていることをなんとなく頭に入れてから、deploy.yaml
に注目してください。
Cloud Deployは、デプロイ時にtargetId
を指定できます
(何も指定しない場合はserialPipeline.stages
に書かれたもののうち1番最初のものをターゲットに指定します)。
つまり、 gcloud deploy releases create
によってデプロイを実行する時は、オプションパラメータ--to-target
を指定しない限りはtargetId gke-dev
が最初のデプロイターゲットになります。
そして、そこにはskaffoldのdev
プロファイルをデプロイすると書かれています。
skaffoldの dev
プロファイルはHelm Chartをリモートから取り出すことと、そのURL及びバージョンが記載されています。
それは先程Helm ChartをpushしたArtifact Registryであることがすぐにわかります。
また、デプロイ時にChartで利用するvaluesファイルがvaluesFiles
によって指定されています。
デフォルトではHelm Chart内のvalues.yaml
が利用されますが、これらの値を上書きしたい場合に各環境のvaluesファイルを用意します。
早速dev環境にコンテナをデプロイしてみましょう。
Cloud Deployでは、次のようにreleaseを作成することでデプロイが実施されます。
gcloud deploy releases create v0-1-0 --delivery-pipeline=helm-deploy-gke --region=asia-northeast1
helm-deploy-gke
というのは、deploy.yaml
に書いてあった名前です。
正常に実行できると、次図のようになります。
kubectlでも確認します。
$ kubectl get all -o wide -n develop
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/nginx-7b6646767d-96dsv 1/1 Running 0 50m 10.23.0.30 gk3-crystal-nap-18i3t0dg-48c645fb-l8cs <none> <none>
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service/nginx ClusterIP 10.23.131.24 <none> 80/TCP 50m app=nginx,release=dev
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
deployment.apps/nginx 1/1 1 1 50m nginx nginx:stable-alpine app=nginx,release=dev
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
replicaset.apps/nginx-7b6646767d 1 1 1 50m nginx nginx:stable-alpine app=nginx,pod-template-hash=7b6646767d,release=dev
図中のPromote
というボタンに注目してください。
dev環境へのデプロイとHelm Chartによるテストが成功したことによって、prod環境へリリースする準備が整いました。
それぞれの環境差異はvaluesファイルによって吸収される想定で、prod環境はprod環境用のvaluesファイルを用意しています。
早速Promote
ボタンを押してprod環境へデプロイしましょう。
次図のようにprod環境に正常にデプロイできていれば意図した通りです。
kubectlでも確認します。
$ kubectl get all -o wide -n production
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/nginx-56756d94b8-84b7n 1/1 Running 0 13m 10.23.0.66 gk3-crystal-nap-18i3t0dg-9ca595f7-bhlt <none> <none>
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service/nginx ClusterIP 10.23.129.175 <none> 80/TCP 13m app=nginx,release=prod
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
deployment.apps/nginx 1/1 1 1 13m nginx nginx:stable-alpine app=nginx,release=prod
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
replicaset.apps/nginx-56756d94b8 1 1 1 13m nginx nginx:stable-alpine app=nginx,pod-template-hash=56756d94b8,release=prod
残された課題
Cloud Deploy, Artifact Registry, Helm を組み合わせることにより、デプロイフロー、マニフェスト管理、アプリケーションバージョン管理を実現できそうなことがなんとなくわかりました。
これらを実際の運用フローに採用しようとした場合にどのような課題が出てきて、どう解決するのが良さそうかはまだまだ想像もできません。
Cloud Deployは観測範囲ではあまり採用事例を見かけないのですが、個人的には好きなプロダクトのうちの1つですので、積極的に活用していきたいです。
Discussion