本記事には広告(アフィリエイトリンク)が含まれます。

Helm v4でアプリをchart化する|CKAD第17回

広告

新卒インフラエンジニア向け「Kubernetes 実践教科書① CKAD アプリケーション開発編」の第17回です。第16回までで、fanclub-api は Pod・Service・StatefulSet から ConfigMap・Secret・RBAC・NetworkPolicy まで、20 以上のマニフェストを kubectl apply で 1 枚ずつ積み上げてきました。今回はこの大量のマニフェストを Helm v4 で 1 つの chart にまとめ、install / upgrade / rollback / uninstall のフルサイクルを実機で回します。fanclub-api を「パッケージ」として一括管理できるようにするのが到達点です。CKAD ドメイン D2(Application Deployment)の中心テーマです。

動作確認バージョン:Helm v4.1.4 / kind v0.31.0(K8s v1.35.0)/ kubectl v1.35.6 / fanclub-backend:0.3.2(再ビルドなし)/ fanclub-frontend:0.1.0 / Chart 版 1.0.0(appVersion 0.3.2)(2026-07-03 実機検証時点)

広告

今ここマップ(全 19 回中の現在地)

現在地は第 6 部「パッケージ管理と HTTPS 公開」の第 17 回、第 6 部の入口です。第 1〜5 部で組み上げたアプリを、ここからパッケージ化して公開まで進めます。

  • 第 1 部 コンテナと Docker(第 1〜4 回)
  • 第 2 部 Kubernetes 基礎(第 5〜6 回)
  • 第 3 部 アプリリソース(第 7〜11 回)
  • 第 4 部 ワークロード戦略(第 12〜14 回)
  • 第 5 部 セキュリティ基礎(第 15〜16 回)
  • 第 6 部 パッケージ管理と HTTPS 公開(第 17〜19 回)← 今ここ

この回のゴール

  • 個別 kubectl apply の限界を理解し、Chart / Release / Values / Repository の 4 概念を説明できる。
  • Helm v4 をバイナリで導入し、fanclub-api の全マニフェストを 1 つの chart にまとめられる。
  • install / upgrade / rollback / uninstall のフルサイクルと、lint / template / history を実機で回せる。

なぜ Helm か

ここまで fanclub-api を構成するマニフェストは、Namespace・ResourceQuota・ConfigMap・Secret・ServiceAccount・Role・Deployment・Service・StatefulSet・DaemonSet・CronJob・NetworkPolicy と 20 枚を超えました。1 枚ずつ kubectl apply -f で管理する方式には、次の限界があります。

  • 適用順序を人間が覚える必要がある:Secret より先に Deployment を当てると起動に失敗するなど、依存を手作業で管理することになる。
  • 一括更新・一括削除がしづらい:イメージのタグを 1 つ上げるだけでも該当ファイルを探して書き換え、消すときは 20 枚を delete して回る。
  • 環境差分をコピーで作りがち:dev と prod で replica 数やリソースだけ違うのに、ほぼ同じマニフェスト一式を 2 セット持つことになる。
  • まとめて元に戻せない:更新して問題が出ても、変更前の状態へワンコマンドで戻す仕組みが無い。

Helm は Kubernetes のパッケージマネージャーで、これらをまとめて解決します。中心になる概念は 4 つです。

  • Chart:関連するマニフェスト群と既定値をまとめたパッケージ。fanclub-api の全リソースを 1 つの chart にする。
  • Values:chart に外から差し込む値(イメージのタグ・replica 数・リソース量など)。環境差分はここだけ変える。
  • Release:chart をクラスタに install した「インスタンス」。同じ chart から名前違いで複数の Release を作れる。Release はリビジョンを持ち、更新のたびに番号が増え、過去へ戻せる。
  • Repository:chart を配布する置き場。公開 chart を helm repo add で取り込める(本回は自作 chart をローカルディレクトリから直接使う)。
Helm の概念図。左に chart(templates と values.yaml)があり、install 時に Values を差し込んでレンダリングし、右のクラスタに Release として展開される。Release は Namespace・Deployment・Service・StatefulSet などの K8s リソースの集合になる。
図1:chart に Values を差し込んで Release としてクラスタへ展開する

Helm v4 の導入

以降の作業はすべて、作業端末 k8s-ops に一般ユーザー developer で SSH した状態で行います。まず Helm v4 を入れます。バージョンを固定したいので、配布スクリプト(get.helm.sh/get_helm.sh)ではなくバージョン指定のバイナリを直接取得します。配布スクリプトは Helm v3 系の導入用で、v4 のピン留めには使いません。取得と展開は developer のホーム(~)で行い、バイナリを全ユーザー共通の /usr/local/bin に置くところだけ sudo を使います。実行コマンド:

$ curl -sSLO https://get.helm.sh/helm-v4.1.4-linux-amd64.tar.gz
$ tar xzf helm-v4.1.4-linux-amd64.tar.gz
$ sudo install -m 0755 linux-amd64/helm /usr/local/bin/helm
$ helm version

実行結果(例):v4.1.4 が入り、対応する Kubernetes クライアントが v1.35 であることも確認できます。

version.BuildInfo{Version:"v4.1.4", GitCommit:"05fa37973dc9e42b76e1d2883494c87174b6074f", GitTreeState:"clean", GoVersion:"go1.25.9", KubeClientVersion:"v1.35"}

/usr/local/bin/helmsudo install で置いたので root 所有のシステム共通コマンドになりますが、この後に作る chart のファイル群はすべて developer が自分のホームに置く一般ユーザー所有のファイルです(root は不要)。また Helm は、第6回から使ってきた kubectl同じ kubeconfig(~/.kube/configを読むので、追加設定なしで同じ kind クラスタを操作します。

Helm v3 は 2026 年 11 月でセキュリティ修正が終わるため、新規に学ぶなら v4 が前提です。v3 からの主な破壊的変更は次の 3 点です。実務で v3 の資料を見ながら v4 を触ると食い違うので、頭に入れておきます。

  • OCI レジストリが既定の配布方式:v3 で必要だった環境変数 HELM_EXPERIMENTAL_OCI=1 は廃止され、OCI 関連コマンドがそのまま使える。
  • プラグイン互換の変化:v3 向けプラグインの多くは v4 で動かず、v4 対応版が要る。
  • Go モジュールパスの変更helm.sh/helm/v3 から helm.sh/helm/v4 へ。Helm を Go から呼ぶツールは追従が要る。

chart の構造

chart は決まったディレクトリ構造を持ちます。fanclub-api 用に fanclub-chart を作ります。最小の骨格は次の 3 要素です。

  • Chart.yaml:chart のメタデータ。名前・chart 自身のバージョン(version)・中身のアプリのバージョン(appVersion)を持つ。
  • values.yaml:Values の既定値。テンプレートから {{ .Values.* }} で参照する。
  • templates/:K8s マニフェストのテンプレート群。Go テンプレート記法で values.yaml の値を差し込む。

この chart は第18回・第19回でも使い続けるので、developer のホーム直下に fanclub-chart/ として作ります。まずディレクトリだけ用意します(これ以降のファイルはすべて developer が一般ユーザーとして作成します。root は不要です)。実行コマンド:

$ mkdir -p ~/fanclub-chart/templates

以降、Chart.yamlvalues.yaml~/fanclub-chart/ 直下に、各マニフェストは ~/fanclub-chart/templates/ の中に置きます。

まず Chart.yaml です。version(chart のバージョン)と appVersion(同梱アプリのバージョン)は別物です。本 chart のバージョンは 1.0.0、appVersion は fanclub-backend の完走タグ 0.3.2 にします。chart を直したら version を上げ、アプリのイメージを差し替えたら appVersion を上げる、という使い分けです。

apiVersion: v2
name: fanclub-api
description: fanclub-api 三層アプリ(Frontend / Backend / PostgreSQL)を一括管理する Helm chart
type: application
version: 1.0.0
appVersion: "0.3.2"

次に values.yaml です。環境で変えたい値(namespace・イメージのタグ・replica 数・リソース量)と、第18回で有効化する Gateway API のトグルを外に出します。gateway.enabledfalse にしておくと、Gateway 関連のテンプレートは出力されません。

namespace: fanclub

backend:
  replicaCount: 1
  image:
    repository: k8s-registry:5000/fanclub-backend
    tag: "0.3.2"
  resources:
    requests:
      cpu: "250m"
      memory: "512Mi"
    limits:
      cpu: "1000m"
      memory: "768Mi"

frontend:
  replicaCount: 1
  image:
    repository: k8s-registry:5000/fanclub-frontend
    tag: "0.1.0"

db:
  image:
    repository: postgres
    tag: "18"
  storage: 1Gi

gateway:
  enabled: false
  host: fanclub.local

fanclub-api を chart 化する

テンプレートの元ネタは、第7〜16回で developer のホームに作ってきた各マニフェスト(backend-deploy.yaml / db-statefulset.yaml / fanclub-config.yaml / np-*.yaml など)です。これらを ~/fanclub-chart/templates/ にリソース単位で置き直し、次の 2 つの機械的な変更を加えれば chart になります。

  • 各リソースの metadata.namespace{{ .Values.namespace }} に置き換える(fanclub 名前空間へまとめるため)。
  • 環境で変えたい値(イメージのタグ・replica 数・リソース量・PVC 容量)を {{ .Values.* }} 参照にする。

加えて、Frontend だけは第8回以来 Pod で動かしてきたので、この機に Deployment(frontend-deployment.yaml)へ書き換えて Backend と形式をそろえます。fanclub-chart の全体構成は次のとおりです(templates/ 配下の 21 ファイル)。第11回で足した CronJob・DaemonSet、第16回の NetworkPolicy まで、すべてこの chart に収めます。

  • fanclub-chart/Chart.yamlvalues.yaml
  • templates/ 土台:namespace.yaml / resourcequota.yaml / limitrange.yaml
  • templates/ 設定:configmap.yaml / secret.yaml / serviceaccount.yaml / role.yaml / rolebinding.yaml
  • templates/ DB:db-statefulset.yaml / db-service.yaml / db-migrate-job.yaml
  • templates/ アプリ:backend-deployment.yaml / backend-service.yaml / frontend-deployment.yaml / frontend-service.yaml
  • templates/ バッチ・ログ:cronjob.yaml / daemonset.yaml
  • templates/ 通信制御:networkpolicy.yaml
  • templates/ 公開(第18回で有効化):gateway.yaml / httproute.yaml / certificate.yaml

移植のポイントは、ハードコードしていた値を {{ .Values.* }} に置き換えることです。代表として Backend の Deployment を見ます。イメージ・replica 数・リソース量・namespace を Values 参照にしています(第12回で作った 3 Probe と第15回の SecurityContext はそのまま維持)。実機で使っている backend-deployment.yaml は次のとおりです。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: fanclub-backend
  namespace: {{ .Values.namespace }}
  labels:
    app: fanclub-backend
spec:
  replicas: {{ .Values.backend.replicaCount }}
  selector:
    matchLabels:
      app: fanclub-backend
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  template:
    metadata:
      labels:
        app: fanclub-backend
    spec:
      serviceAccountName: fanclub-backend
      automountServiceAccountToken: false
      initContainers:
      - name: wait-for-db
        image: busybox:1.37
        command: ["sh","-c","until nslookup fanclub-db.{{ .Values.namespace }}.svc.cluster.local >/dev/null 2>&1; do echo waiting; sleep 2; done; echo resolved"]
      - name: log-shipper
        image: busybox:1.37
        restartPolicy: Always
        command: ["sh","-c","echo sidecar; tail -F /var/log/app/app.log 2>/dev/null || sleep infinity"]
        volumeMounts:
        - name: applog
          mountPath: /var/log/app
      containers:
      - name: backend
        image: {{ .Values.backend.image.repository }}:{{ .Values.backend.image.tag }}
        ports:
        - containerPort: 8080
        envFrom:
        - configMapRef:
            name: fanclub-config
        - secretRef:
            name: fanclub-db-secret
        securityContext:
          runAsNonRoot: true
          runAsUser: 10001
          readOnlyRootFilesystem: true
          allowPrivilegeEscalation: false
          capabilities:
            drop: ["ALL"]
        startupProbe:
          httpGet:
            path: /health/started
            port: 8080
          failureThreshold: 30
          periodSeconds: 10
        livenessProbe:
          httpGet:
            path: /health/live
            port: 8080
          periodSeconds: 10
          failureThreshold: 3
        readinessProbe:
          httpGet:
            path: /health/ready
            port: 8080
          periodSeconds: 10
          failureThreshold: 3
        resources:
          requests:
            memory: {{ .Values.backend.resources.requests.memory | quote }}
            cpu: {{ .Values.backend.resources.requests.cpu | quote }}
          limits:
            memory: {{ .Values.backend.resources.limits.memory | quote }}
            cpu: {{ .Values.backend.resources.limits.cpu | quote }}
        volumeMounts:
        - name: applog
          mountPath: /var/log/app
        - name: payara-tmp
          mountPath: /opt/payara/tmp
      volumes:
      - name: applog
        emptyDir: {}
      - name: payara-tmp
        emptyDir: {}

先に触れた frontend-deployment.yaml も同じ要領で、imagereplicas{{ .Values.frontend.* }} 参照にします。これで Backend・Frontend とも replica 数を Values 側でそろえて制御できます。

第18回で有効化する Gateway をトグルで無効化する

Gateway API のリソース(gateway.yaml / httproute.yaml / certificate.yaml)は chart に含めますが、第17回時点ではまだ Gateway API の CRD を入れていないため、そのまま install すると「未知のリソース種別」で失敗します。そこで {{- if .Values.gateway.enabled }} で囲み、gateway.enabled: false のあいだは出力しないようにします。第18回で CRD を入れてから --set gateway.enabled=true で有効化します。gateway.yaml の冒頭はこの形です。

{{- if .Values.gateway.enabled }}
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: fanclub-gateway
  namespace: {{ .Values.namespace }}
spec:
  gatewayClassName: traefik
  listeners:
  - name: https
    protocol: HTTPS
    port: 443
    hostname: {{ .Values.gateway.host | quote }}
    tls:
      mode: Terminate
      certificateRefs:
      - kind: Secret
        name: fanclub-tls
{{- end }}

DB マイグレーションはフックにする

第11回で作った DB マイグレーション Job は、Helm フックにします。フックにしない Job は、内容を変えて helm upgrade すると「Job は変更不可」で失敗しがちです。helm.sh/hook: post-install,post-upgrade を付けると、install と upgrade のたびに Helm が Job を作り直し、完了を待ってから処理を進めます。マイグレーションは DB が起動してから走る必要があるので、先頭に pg_isready の待ち合わせを入れています。

apiVersion: batch/v1
kind: Job
metadata:
  name: fanclub-db-migrate
  namespace: {{ .Values.namespace }}
  annotations:
    "helm.sh/hook": post-install,post-upgrade
    "helm.sh/hook-weight": "5"
    "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
spec:
  backoffLimit: 3
  template:
    metadata:
      labels:
        app: fanclub-batch
    spec:
      restartPolicy: Never
      containers:
      - name: migrate
        image: {{ .Values.db.image.repository }}:{{ .Values.db.image.tag }}
        envFrom:
        - configMapRef:
            name: fanclub-config
        - secretRef:
            name: fanclub-db-secret
        command:
        - sh
        - -c
        - |
          set -e
          until PGPASSWORD="$DB_PASSWORD" pg_isready -h "$DB_HOST" -U "$DB_USER" >/dev/null 2>&1; do
            echo "waiting for db"; sleep 2
          done
          PGPASSWORD="$DB_PASSWORD" psql -h "$DB_HOST" -U "$DB_USER" -d "$DB_NAME" -v ON_ERROR_STOP=1 \
            -c "ALTER TABLE members ADD COLUMN IF NOT EXISTS updated_at TIMESTAMP" \
            -c "INSERT INTO members (name,email,plan) VALUES ('鈴木花子','hanako@example.com','standard'),('佐藤一郎','ichiro@example.com','free') ON CONFLICT (email) DO NOTHING"

Pod テンプレートに app: fanclub-batch というラベルを付けた点に注目してください。この理由は、次の NetworkPolicy の移植で分かります。

NetworkPolicy を移植すると、バッチが DB に届かなくなる

第16回の NetworkPolicy(default-deny + 隣接層の許可 6 枚)をそのまま networkpolicy.yaml に移すと、マイグレーション Job とレポート CronJob が DB に接続できなくなります。実際、この状態で helm install すると、post-install フックの Job が waiting for db を延々と出したまま完了せず、タイムアウトします。

Error: INSTALLATION FAILED: failed post-install: resource Job/fanclub/fanclub-db-migrate not ready. status: InProgress, message: Job in progress
context deadline exceeded

原因は明快です。第16回の許可ルールは、DB への通信を app: fanclub-backend のラベルを持つ Pod だけに開けていました。マイグレーション Job やレポート CronJob の Pod にはそのラベルが無いため、default-deny-all により DB への Egress も、DB 側の Ingress も塞がれます。「アプリ本体は通信できるのに、バッチ処理だけ DB に届かない」——NetworkPolicy を締めた現場でよく起きる詰まり方です。

解決は、バッチ用の経路を明示的に開けることです。Backend の Service セレクタ(app: fanclub-backend)を汚さないよう、バッチには専用ラベル app: fanclub-batch を付け(先ほどの Job のラベルがこれです)、次の 2 点を networkpolicy.yaml に足します。

  • app: fanclub-batch の Pod から DB への Egress を許可する allow-egress-batch-to-db を新設する。
  • DB 側の Ingress 許可 allow-db-from-backend の送信元に、app: fanclub-batch を追加する。

該当箇所は次のとおりです(DNS への Egress は第16回の allow-dnspodSelector: {} で全 Pod に効いているので、バッチもそのまま名前解決できます)。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-db-from-backend
  namespace: {{ .Values.namespace }}
spec:
  podSelector:
    matchLabels:
      app: fanclub-db
  policyTypes: ["Ingress"]
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: fanclub-backend
    - podSelector:
        matchLabels:
          app: fanclub-batch
    ports: [{protocol: TCP, port: 5432}]
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-egress-batch-to-db
  namespace: {{ .Values.namespace }}
spec:
  podSelector:
    matchLabels:
      app: fanclub-batch
  policyTypes: ["Egress"]
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: fanclub-db
    ports: [{protocol: TCP, port: 5432}]

レポート CronJob の Pod テンプレートにも同じ app: fanclub-batch を付けておきます。これで default-deny を保ったまま、バッチ経路だけを最小限に開けられます。

lint と template で事前確認する

クラスタへ当てる前に、chart を静的に確認します。helm lint は構文と推奨事項をチェックし、helm template は Values を差し込んだ実際に生成される YAML を手元で確認できます。なお、以降の helm コマンドは chart を ./fanclub-chart の相対パスで指すので、developer のホーム(~)で実行します(cd ~/fanclub-chart の中では相対パスがずれるので注意してください)。実行コマンド:

$ helm lint ./fanclub-chart

実行結果(例):エラー 0 件です(icon の推奨は情報レベルなので無視して問題ありません)。

==> Linting ./fanclub-chart
[INFO] Chart.yaml: icon is recommended

1 chart(s) linted, 0 chart(s) failed

次に helm template で、生成されるオブジェクトの種類と数を確認します。gateway.enabledfalse なので Gateway・HTTPRoute・Certificate は出力されないはずです。実行コマンド:

$ helm template fanclub ./fanclub-chart | grep -E "^kind:" | sort | uniq -c

実行結果(例):ConfigMap 3・Deployment 2(Backend / Frontend)・Service 3・NetworkPolicy 7・StatefulSet 1 など、想定どおりの一式が出ます。NetworkPolicy が第16回の 6 枚より 1 多い 7 枚なのは、先ほど足したバッチ用の allow-egress-batch-to-db が含まれるためです。Gateway 系は 0 件で、トグルが効いています。

      3 kind: ConfigMap
      1 kind: CronJob
      1 kind: DaemonSet
      2 kind: Deployment
      1 kind: Job
      1 kind: LimitRange
      1 kind: Namespace
      7 kind: NetworkPolicy
      1 kind: ResourceQuota
      1 kind: Role
      1 kind: RoleBinding
      1 kind: Secret
      3 kind: Service
      1 kind: ServiceAccount
      1 kind: StatefulSet

install する

chart は専用の namespace fanclub にまとめてデプロイします。ここまで default に個別適用してきたリソースは、chart 管理へ移すので先に削除します。二重に起動させないためと、kind の CPU 予算(2 vCPU)を空けるためです。ConfigMap や ServiceAccount には app ラベルが無く一括セレクタで取りこぼすので、名前を明示して確実に消します(テンプレートの元にした ~/*.yaml はホームに残るため、消えて困るものはありません)。実行コマンド:

$ kubectl delete deployment/fanclub-backend statefulset/fanclub-db pod/fanclub-frontend \
    daemonset/fanclub-logcollector cronjob/fanclub-report --ignore-not-found
$ kubectl delete service/fanclub-backend service/fanclub-frontend service/fanclub-db --ignore-not-found
$ kubectl delete configmap/fanclub-config configmap/fanclub-frontend-config configmap/fanclub-db-init \
    secret/fanclub-db-secret serviceaccount/fanclub-backend --ignore-not-found
$ kubectl delete role/fanclub-backend-reader rolebinding/fanclub-backend-reader-binding --ignore-not-found
$ kubectl delete networkpolicy --all
$ kubectl delete pvc/data-fanclub-db-0 --ignore-not-found

掃除ができたら install します。chart 内の namespace.yamlfanclub を作り、各リソースは namespace: fanclub を宣言しているので、実体は fanclub に作られます。実行コマンド:

$ helm install fanclub ./fanclub-chart --timeout 5m

実行結果(例):STATUS: deployedREVISION: 1 で install が完了します。post-install フックのマイグレーションもこの中で完了しています。

NAME: fanclub
LAST DEPLOYED: Fri Jul  3 12:51:35 2026
NAMESPACE: default
STATUS: deployed
REVISION: 1
DESCRIPTION: Install complete
TEST SUITE: None

Release の情報自体は現在の default に記録されますが(NAMESPACE: default はこの意味)、アプリの実体は fanclub です。Pod の状態を見ます。実行コマンド:

$ kubectl get pods -n fanclub

実行結果(例):Backend(2/2=サイドカー込み)・DB・Frontend・ログコレクタがすべて Running です。

NAME                                READY   STATUS    RESTARTS   AGE
fanclub-backend-6896d48bd9-6kxzh    2/2     Running   0          31s
fanclub-db-0                        1/1     Running   0          31s
fanclub-frontend-7c98b748bc-g9b59   1/1     Running   0          31s
fanclub-logcollector-47tqs          1/1     Running   0          31s

NetworkPolicy 下で 3 層が通るかを、DB 参照を伴う /api/members で確認します。Frontend Pod から Backend を叩きます。実行コマンド:

$ kubectl exec -n fanclub deploy/fanclub-frontend -- \
    wget -qO- http://fanclub-backend:8080/api/members

実行結果(例):マイグレーションフックが投入した会員 2 件の JSON が返り、Frontend → Backend → DB が chart 一式で通っています。先ほど PVC も削除したため DB は初期化されており、schema.sql(テーブル作成)とマイグレーションフック(この 2 件の投入)で作り直された状態です。これまでの回で入れた会員データは引き継がれない点に注意してください(学習環境のため作り直しで問題ありません)。

[{"createdAt":"2026-07-03T03:49:05.855174","email":"hanako@example.com","id":1,"name":"鈴木花子","plan":"standard"},{"createdAt":"2026-07-03T03:49:05.855174","email":"ichiro@example.com","id":2,"name":"佐藤一郎","plan":"free"}]

フルサイクル運用

install した Release を、値を変えて更新し、問題があれば戻し、最後に消す——この一連が Helm の要です。まず upgrade です。Frontend の replica を 1 から 2 に増やします(Backend を増やすと kind の CPU 予算を超えて Pending になるため、軽い Frontend で試します)。値は --set でその場だけ上書きできます。実行コマンド:

$ helm upgrade fanclub ./fanclub-chart --set frontend.replicaCount=2

実行結果(例):REVISION: 2 に上がります。

Release "fanclub" has been upgraded. Happy Helming!
NAME: fanclub
STATUS: deployed
REVISION: 2
DESCRIPTION: Upgrade complete

Frontend が 2 つに増えたことを確認したら、rollback で 1 つ前(リビジョン 1)へ戻します。rollback は「戻す」操作自体も新しいリビジョンとして記録されます。実行コマンド:

$ helm rollback fanclub 1

実行結果(例):戻しが成功し、Frontend は 1 replica に戻ります。

Rollback was a success! Happy Helming!

ここまでの履歴を helm history で見ます。実行コマンド:

$ helm history fanclub

実行結果(例):install(リビジョン 1)→ upgrade(2)→ rollback(3)と、変更が積み重なって記録されています。リビジョン 3 は「1 の状態に戻したもの」です。

REVISION  STATUS      CHART              APP VERSION  DESCRIPTION
1         superseded  fanclub-api-1.0.0  0.3.2        Install complete
2         superseded  fanclub-api-1.0.0  0.3.2        Upgrade complete
3         deployed    fanclub-api-1.0.0  0.3.2        Rollback to 1
Helm のリビジョン遷移図。install でリビジョン1が deployed になり、upgrade でリビジョン2へ、rollback to 1 でリビジョン3が生まれる。過去のリビジョンは superseded になり、いつでも rollback で戻せることを矢印で示す。
図2:install・upgrade・rollback とリビジョンの遷移

最後に uninstall です。Release に属するリソースがまとめて削除されます。chart には namespace.yaml も含まれるので、fanclub namespace ごと消えます。実行コマンド:

$ helm uninstall fanclub

実行結果(例):1 コマンドで一式が片付きます。20 枚以上を kubectl delete で消して回っていた手間が、これ 1 行になりました。

release "fanclub" uninstalled

次回に備えて、chart をもう一度クリーンに install しておきます(helm install fanclub ./fanclub-chart)。ただし uninstall の直後に再 install するときは 1 点注意があります。この chart は namespace.yamlfanclub namespace 自体も作るため、uninstall でその namespace が削除されますが、削除は非同期で、DB の PVC(volumeClaimTemplates 由来で Helm 管理外のため残存)などが片付くまで Terminating がしばらく続きます。この Terminating 中に再 install すると、namespace 作成が競合して INSTALLATION FAILEDcannot reuse a name や namespace not found)になります。kubectl get ns fanclubNotFound になるのを待ってから再 install してください。これで fanclub-api は Helm 管理下の 1 つの Release として扱えるようになりました。

やってみよう

  1. helm lint ./fanclub-charthelm template fanclub ./fanclub-chart を実行し、生成される YAML に Gateway・HTTPRoute・Certificate が含まれないこと(トグル無効)を確認する。
  2. helm install fanclub ./fanclub-chart を実行し、kubectl get pods -n fanclub で 4 つの Pod が Running になること、/api/members が会員 JSON を返すことを確認する。
  3. --set frontend.replicaCount=2helm upgrade し、Frontend が 2 つに増えることとリビジョンが 2 になることを確認する。
  4. helm rollback fanclub 1 で戻し、helm history fanclub で install → upgrade → rollback の 3 リビジョンが並ぶことを確認する。
  5. helm uninstall fanclub で一式が消えることを確認したのち、再度 helm install して元に戻す。

理解度チェック

次の各文が正しいか(○)誤りか(×)を判断してください。解答は下にまとめています。

  1. Chart は関連マニフェストと既定値をまとめたパッケージで、install するとクラスタ上に Release ができる。
  2. Chart.yamlversion は同梱アプリのバージョンを表し、appVersion は chart 自身のバージョンを表す。
  3. helm template は Values を差し込んだ後の YAML を手元で確認でき、クラスタには何も適用しない。
  4. helm rollback で過去のリビジョンへ戻すと、その戻し操作は新しいリビジョンとして履歴に追加される。
  5. values.yaml の値は helm install / upgrade 時に --set で上書きできる。
  6. default-deny の NetworkPolicy 下では、アプリ本体に許可があればマイグレーション Job も追加設定なしで DB に接続できる。
  7. Helm v4 では OCI レジストリが既定の配布方式で、HELM_EXPERIMENTAL_OCI=1 は不要になった。

解答

  • 1. ○:chart は install により Release としてクラスタへ展開される。
  • 2. ×:逆。version が chart 自身、appVersion が同梱アプリのバージョン。
  • 3. ○:template はレンダリング結果を出すだけで、クラスタへは適用しない。
  • 4. ○:rollback も 1 つの操作として新リビジョンに記録される(本回では 3 になった)。
  • 5. ○:--set key=value で個別に上書きできる。
  • 6. ×:バッチ Pod には app: fanclub-backend が無いため、専用の許可(app: fanclub-batch の Egress と DB Ingress)を足さないと届かない。
  • 7. ○:v4 で OCI が既定になり、実験フラグは廃止された。

まとめ

本記事では、20 枚以上に増えた fanclub-api のマニフェストを Helm v4 の chart にまとめ、パッケージとして扱えるようにしました。Chart / Values / Release / Repository の 4 概念を押さえ、ハードコードしていた値を {{ .Values.* }} に置き換え、環境で変えたい値だけを values.yaml に外出ししました。Gateway API のリソースは gateway.enabled のトグルで無効化し、DB マイグレーションは post-install / post-upgrade フックにしました。NetworkPolicy を移植するとバッチが DB に届かなくなる詰まりは、専用ラベル app: fanclub-batch と許可 2 枚で解きました。lint / template で事前確認し、install / upgrade / rollback / history / uninstall のフルサイクルを実機で回して、20 枚以上の手作業を 1 コマンドに置き換えられることを確認しました。

次回予告

次回(第18回)は、chart にトグルで仕込んでおいた Gateway API を有効化します。Gateway API の CRD を導入し、Traefik をゲートウェイ実装に、cert-manager で TLS 証明書を発行して、ブラウザから https://fanclub.local へ HTTPS でアクセスできる状態を作ります。第16回で保留した「外部 → Frontend」の NetworkPolicy 許可も、このとき足して 4 層のホワイトリストを完成させます。

シリーズ一覧

第1部:コンテナと Docker

第2部:Kubernetes 基礎

第3部:アプリリソース

第4部:ワークロード戦略

第5部:セキュリティ基礎

第6部:パッケージ管理 + HTTPS 公開

広告
kubernetes
スポンサーリンク