k8sでConfigMap/Secretsの更新時に環境変数へ反映するデプロイフローについて
はじめに
k8sの CofnigMap/Secrets を環境変数に設定し、アプリケーション(Deployment)から利用するパターンはよくあると思います
デプロイ時にDeployment、CofnigMap/Secretsをまとめてデプロイすると思いますが、CofnigMap/Secrets のみの更新時にはDeploymentに自動で反映されません
これはアプリケーションが起動時に CofnigMap/Secrets の値を環境変数に設定するため、起動後に CofnigMap/Secrets が更新されても反映されないためです
アプリケーションにも環境変数の更新を反映をさせたい場合は、Deployment と CofnigMap/Secrets を一緒に更新すればよいわけです
そこで、CofnigMap/Secrets を更新した際に、Deploymentにローリングアップデートをかけるデプロイフローを考えてみます
(CI/CDフローでも使えるよう、デプロイ時にエディタを起動して…などは行わないフローにします)
ローリングアップデートについて
前述したとおり、CofnigMap/Secrets のみの更新ではDeploymentが更新されないため反映が行われません
一般的なデプロイフローでは、各種リソースのyamlファイルを用意してデプロイを行うと思いますが、反映が行われない際のデプロイでは以下のようになっているはずです
$ kubectl apply -f .
configmap/my-configmap configured
deployment.apps/my-deployment unchanged
ComfigMapのみがconfigured
となっていて、Deploymentのほうはunchanged
になってますね
では、特にアプリケーション側に変更が入っていない場合にどのようにローリングアップデートをかければよいのか🤔
上記の記事で、Deploymentのローリングアップデートが起こる条件がすごく分かりやすく説明されています
.spec.template
の情報に変更があったとき- 変更はどの値でもよいが、アノテーション(
.spec.template.metadata.annotations
)が一番影響が少ないと思われる
- 変更はどの値でもよいが、アノテーション(
ローリングアップデートを行う
実際にDeploymentのローリングアップデートを行うデプロイフローをいくつかあげてみます
1. デプロイ時に常にローリングアップデート
CofnigMap/Secrets の更新時を問わず、常にローリングアップデートをかける方法です
$ kubectl apply -f . $ kubectl rollout restart <target_deployment>
applyで更新が入る場合、無駄にローリングアップデートが2度行われるので微妙ですね 🤔
2. アノテーションを動的に変更する
ローリングアップデートが起こる条件に当てはまるよう、.spec.template.metadata.annotations
をデプロイのたびに書き換えるフローです
利用するyamlは動的に書き換えられるよう、deployment.yaml.templateなどとしておきます
deployment.yaml.template
(抜粋)
spec: template: metadata: annotations: update_time: ${UPDATE_TIME}
デプロイ時の書き換えはenvsubstを使ってみます
$ UPDATE_TIME=$(date +%s) envsubst < deployment.yaml.template > deployment.yaml $ kubectl apply -f .
↑の例ではデプロイ時にannotations.update_timeに現在時刻を入れてデプロイしてます
spec.template.annotations.update_time
の値がデプロイのたびに書き換わるのでローリングアップデートが行われます 🎉
CofnigMap/Secrets の更新時のみでよければ CofnigMap/Secrets のハッシュ値などを設定しても良いかもしれません
3. Kustomizeを使う
3つ目の方法はKustomizeの configMapGenerator / secretGenerator を使うやりかたです
configMapGenerator/secretGenerator で作成される CofnigMap/Secrets には自動的にハッシュ値のsuffixがつき、参照側も動的に書き換えてくれます
kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - ./deployment.yaml configMapGenerator: - name: my-env literals: - TEST_ENV=hogehoge
deployment.yaml
(抜粋)
spec: template: spec: containers: - envFrom: - configMapRef: name: my-env
上記のファイルを用意し、kubectl kustomize .
を実行すると、
# 抜粋 apiVersion: v1 data: TEST_ENV: hogehoge kind: ConfigMap metadata: name: my-env-c7d2869f5d --- apiVersion: apps/v1 kind: Deployment spec: template: spec: containers: - envFrom: - configMapRef: name: my-env-c7d2869f5d
用意したmy-envに -c7d2869f5d
というsuffixが自動的に付いています
実際にデプロイするには
$ kubectl apply -k .
を実行すれば、上記のyamlの内容がデプロイされます
また、configMapGeneratorの内容を変更し、
@@ -7,4 +7,4 @@ configMapGenerator: - name: my-env literals: - - TEST_ENV=hogehoge + - TEST_ENV=fugafuga
再度 kubectl kustomize .
を実行すると
apiVersion: v1 data: TEST_ENV: fugafuga kind: ConfigMap metadata: name: my-env-9c976df2hh --- apiVersion: apps/v1 kind: Deployment spec: template: spec: containers: - envFrom: - configMapRef: name: my-env-9c976df2hh
-c7d2869f5d
だったsuffixが -9c976df2hh
に変わっています
spec.template.spec.containers
が更新されているため、デプロイ時にローリングアップデートが行われます 🎉
✋注意
Kustomizeでのsuffix付きのリソースはそれぞれ別のリソースとしてデプロイされるため、古くなった CofnigMap/Secrets 自体は残ることになります
--prune
を利用したデプロイを行うようにしたり、利用しなくなった CofnigMap/Secrets の定期的な削除ができるようにしておきましょう
4. Helmを使う
Helmを使っている場合は、公式でローリングアップデートを行うためのTipsが公開されています
Helm | Chart Development Tips and Tricks
この方式は 2. アノテーションを動的に変更する にも記載した、アノテーションに CofnigMap/Secrets のハッシュ値を利用するパターンです
すごくシンプルな以下の構成を例とします
mychart ├── Chart.yaml └── templates ├── configmap.yaml └── deployment.yaml
mychart/templates/configmap.yaml
apiVersion: v1 data: TEST_ENV: hogehoge kind: ConfigMap metadata: name: my-env
mychart/templates/deployment.yaml
(抜粋)
spec: template: metadata: annotations: checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} spec: containers: - envFrom: - configMapRef: name: my-env
annotations.checksum/config
に configmap.yaml のsha256のハッシュ値を設定しています
この状態でドライランをすると
$ helm install my-chart ./mychart --dry-run # 抜粋 # Source: mychart/templates/deployment.yaml apiVersion: apps/v1 kind: Deployment spec: template: metadata: annotations: checksum/config: 3b57b72332cd09882b34fd55bbedec6ccf3ccdf77f8a70fdc41ab518c8ac01d0
checksum/config
にハッシュ値が設定されています
デプロイ後に前回同様 TEST_ENV
の値をhogehoge -> fugafugaに変更してdiffを見ると
$ helm diff upgrade my-chart ./mychart # 抜粋 mychart, my-env, ConfigMap (v1) has changed: # Source: mychart/templates/configmap.yaml apiVersion: v1 data: - TEST_ENV: hogehoge + TEST_ENV: fugafuga ... mychart, mydeploy, Deployment (apps) has changed: spec: template: annotations: - checksum/config: 3b57b72332cd09882b34fd55bbedec6ccf3ccdf77f8a70fdc41ab518c8ac01d0 + checksum/config: f62c80497f97a4b4877958249a1206a3b38bdcb5d5f498df1358ebd3a169c2b7
spec.template.annotations.checksum/config
の値が書き換わっているため、デプロイ時にローリングアップデートが行われます 🎉
まとめ
CofnigMap/Secrets を環境変数に設定して利用する際の、Deploymentのローリングアップデートを行うデプロイフローをいくつかあげてみました
個人的には Kustomize や Helm を利用し、必要に応じて動的にローリングアップデートが行われるフローにするのがよいかと思っています ✋