Kustomizeのreplacementsを使ってマニフェストファイルをちょっとDRYに書く
はじめに
最近はECK (Elastic Cloud on Kubernetes) を使ってKubernetes上にElastic Stack環境を構築するお仕事をしています。
Elastic Stackのプロダクト群 (Elasticsearch, Kibana, Beats, Logstash) のバージョンは同一にするのが望ましいので各リソースのマニフェストファイルに同一バージョンを指定するわけですが、同じ記述を複数のマニフェストファイルに書かなければいけないため冗長です。
そこでKustomizeの出番なわけですが、ECKのようなCustom Resourceに対応するには一工夫が必要になります。
やり方はいくつかあると思いますが、今回はKustomizeのreplacementsという機能を使ってみたのでご紹介したいと思います。
replacementsとは
replacementsはソースに指定されたリソースの値をターゲットのフィールドにコピーする機能になります。
百聞は一見にしかずということで本家ドキュメントのExampleを例に説明します。
まずは以下のようなJob, Pod, Secretがあるとします。
apiVersion: batch/v1
kind: Job
metadata:
name: hello
spec:
template:
spec:
containers:
- image: myimage
name: hello
env:
- name: SECRET_TOKEN
value: SOME_SECRET_NAME
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- image: busybox
name: myapp-container
restartPolicy: OnFailure
---
apiVersion: v1
kind: Secret
metadata:
name: my-secret
そして、今回のお題は
- JobにPodと同じspec.restartPolicyを設定する
- Jobのenv(SECRET_TOKEN)のvalue(SOME_SECRET_NAME)をSecret名(my-secret)で置き換える
というものになります。
kutomization.yamlは以下のようになります。
replacements
の部分がreplacementの設定になります。path
を指定して外部ファイルに記述することもできますし、インラインで記述することもできます。
具体的に何をやっているかはコメントやドキュメントを参考にしてください。
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- resources.yaml
- job.yaml
replacements:
# 外部ファイルに設定を記述
- path: my-replacement.yaml
# インラインで設定を記述
- source: # ソースの設定
kind: Secret # ソースのkindはSecret
name: my-secret # ソースのnameはmy-secret
# コピーする値を明示的に指定しなければ、デフォルトではmetadata.nameがコピー元の値になる
targets: # ターゲットの設定 (複数可)
- select: # ターゲット0の選択
name: hello # ターゲット0のnameはhello
kind: Job # ターゲット0のkindはJob
fieldPaths: # コピー先のフィールド (複数可)
- spec.template.spec.containers.[name=hello].env.[name=SECRET_TOKEN].value # コピー先のフィールドパス
source: # ソースの設定
kind: Pod # ソースのkindはPod
name: my-pod # ソースのnameはmy-pod
fieldPath: spec.restartPolicy # コピーする値はspec.restartPolicyの値
targets: # ターゲットの設定 (複数可)
- select: # ターゲット0の選択
name: hello # ターゲット0のnameはhello
kind: Job # ターゲット0のkindはJob
fieldPaths: # コピー先のフィールド (複数可)
- spec.template.spec.restartPolicy # コピー先のフィールドパス
options: # オプション
create: true # リソースにフィールドがなければ作成
kustomizeすると以下のような結果になります。
Jobにreplacementsで設定された値がコピーおよび作成されていることを確認してください。
apiVersion: v1
kind: Secret
metadata:
name: my-secret
---
apiVersion: batch/v1
kind: Job
metadata:
name: hello
spec:
template:
spec:
containers:
- env:
- name: SECRET_TOKEN
value: my-secret # this value is copied from my-secret
image: myimage
name: hello
restartPolicy: OnFailure # this value is copied from my-pod
---
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- image: busybox
name: myapp-container
restartPolicy: OnFailure
実践
それではECKの各リソースのバージョンをkustomizeのreplacementsを使ってDRYに書いてみたいと思います。
サンプルをGitHubリポジトリにあげていますので、興味のある方はご自身の環境で試してみてください。
今回はElastic Stackバージョン管理用のConfigMapを新規作成することにしました。
Elastic Stackの各マニフェストファイルは、このConfigMapの値をバージョンとして使用します。
apiVersion: v1
kind: ConfigMap
metadata:
name: stack-version
data:
version: 8.5.3
kustomize.yamlは以下のようになります。
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: default
resources:
- stack_version.yaml
- elasticsearch.yaml
- kibana.yaml
- elasticsearch_monitoring.yaml
- kibana_monitoring.yaml
- filebeat.yaml
- metricbeat.yaml
- packetbeat.yaml
- stack_monitoring.yaml
- logstash.yaml
replacements:
- source:
kind: ConfigMap
name: stack-version
fieldPath: data.version
targets:
- select:
kind: Elasticsearch
fieldPaths:
- spec.version
options:
create: true
- select:
kind: Kibana
fieldPaths:
- spec.version
options:
create: true
- select:
kind: Beat
fieldPaths:
- spec.version
options:
create: true
- select:
kind: Deployment
name: logstash
fieldPaths:
- spec.template.spec.containers.[name=logstash].image
options:
delimiter: ":"
index: 1
logstashのみ書き方が異なります。
これはlogstashがECKのCustom Resourceで定義されていないので、普通のDeploymentとして作成しているためです。
apiVersion: apps/v1
kind: Deployment
metadata:
name: logstash
spec:
replicas: 1
selector:
matchLabels:
app: logstash
strategy: {}
template:
metadata:
labels:
app: logstash
spec:
containers:
- image: docker.elastic.co/logstash/logstash:VERSION
name: logstash
resources: {}
env:
- name: XPACK_MONITORING_ELASTICSEARCH_HOSTS
value: "[http://elasticsearch-es-http:9200]"
タグのバージョン番号に関してはreplacementsで置き換える前提なので、"VERSION"という文字列を設定しています。
そしてreplacementsが行っているのは、logstashのimageを:(コロン)で区切って、2番目の要素の値("VERSION")をConfigMapのバージョン番号("8.5.3")に置き換えるという意味になります。
おわりに
従来はバージョンアップグレードするのにすべてのマニフェストファイルを編集する必要がありましたが、kustomizeのreplacementsを使えばバージョン管理用のConfigMapのみを編集するだけでOKになりました。
ちょっとしたことではありますが、エンジニアたるものDRYに行きたいものです。
それでは、この記事がどなたかのお役に立てれば幸いです。
Discussion