🐧

Helm ChartをArtifact Registryに保存してCloud Deployから利用する

2022/12/19に公開

こんにちは、クラウドエースの錦木です。
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環境へデプロイをする」 デプロイフローを意識して書いています。
次図のようなイメージです。

alt

Pipelineを作成する際には、gcloud deploy apply を次のように利用します。

gcloud deploy apply --file=deploy.yaml --region=asia-northeast1

Cloud Deployのコンソールでは、次のように見えているはずです。

alt

これで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に書いてあった名前です。
正常に実行できると、次図のようになります。
alt

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環境に正常にデプロイできていれば意図した通りです。
alt

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