Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

kustomizeをいい感じに使う方法

 kustomizeをいい感じに使う方法

社内勉強会での発表資料を外部公開向けに一部加工したものになります。

gree_tech

January 24, 2024
Tweet

More Decks by gree_tech

Other Decks in Technology

Transcript

  1. Table of Contents Table of Contents kustomize とは ありがちな問題 kustomize

    の基本 オススメ構成 (案) 加工方法の種類 tips まとめ
  2. kustomize とは kustomize とは k8s のマニフェストを加工するツール k8s のリソースはマニフェスト (yaml) として記述される

    複数環境がある時にマニフェストを複製すると多重管理になる 共通部分と差分に分けることで、管理しやすく&わかりやすく
  3. マニフェストの肥大化 マニフェストの肥大化 $ find . -name '*.yaml' | xargs wc

    -l | tail -n1 24261 total 環境やリソースが増えて記述が増えるのは仕方ないが… どこに何があるか分かりにくい あちこちに同じ記述がある というケースがある
  4. Kustomization Kustomization NamePrefix string `json:"namePrefix,omitempty" yaml:"namePrefix,omitempty"` NameSuffix string `json:"nameSuffix,omitempty" yaml:"nameSuffix,omitempty"`

    Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"` CommonLabels map[string]string `json:"commonLabels,omitempty" yaml:"commonLabels,omitempty"` Labels []Label `json:"labels,omitempty" yaml:"labels,omitempty"` CommonAnnotations map[string]string `json:"commonAnnotations,omitempty" yaml:"commonAnnotations,omitempty"` PatchesStrategicMerge []PatchStrategicMerge `json:"patchesStrategicMerge,omitempty" yaml:"patchesStrategicMerge,omitempty"` PatchesJson6902 []Patch `json:"patchesJson6902,omitempty" yaml:"patchesJson6902,omitempty"` Patches []Patch `json:"patches,omitempty" yaml:"patches,omitempty"` Images []Image `json:"images,omitempty" yaml:"images,omitempty"` ImageTags []Image `json:"imageTags,omitempty" yaml:"imageTags,omitempty"` Replacements []ReplacementField `json:"replacements,omitempty" yaml:"replacements,omitempty"` Replicas []Replica `json:"replicas,omitempty" yaml:"replicas,omitempty"` SortOptions *SortOptions `json:"sortOptions,omitempty" yaml:"sortOptions,omitempty"` Resources []string `json:"resources,omitempty" yaml:"resources,omitempty"` Components []string `json:"components,omitempty" yaml:"components,omitempty"` Crds []string `json:"crds,omitempty" yaml:"crds,omitempty"` ConfigMapGenerator []ConfigMapArgs `json:"configMapGenerator,omitempty" yaml:"configMapGenerator,omitempty"` SecretGenerator []SecretArgs `json:"secretGenerator,omitempty" yaml:"secretGenerator,omitempty"` HelmGlobals *HelmGlobals `json:"helmGlobals,omitempty" yaml:"helmGlobals,omitempty"` HelmCharts []HelmChart `json:"helmCharts,omitempty" yaml:"helmCharts,omitempty"` GeneratorOptions *GeneratorOptions `json:"generatorOptions,omitempty" yaml:"generatorOptions,omitempty"` Configurations []string `json:"configurations,omitempty" yaml:"configurations,omitempty"` Generators []string `json:"generators,omitempty" yaml:"generators,omitempty"` Transformers []string `json:"transformers,omitempty" yaml:"transformers,omitempty"` Validators []string `json:"validators,omitempty" yaml:"validators,omitempty"`
  5. Kustomization Kustomization k8s リソース、それらの生成・加工についての記述 構成要素は resource, generator, transformer (+ validator)

    あらゆる生成・加工は という扱い 最も有名な builtin plugin が PatchTransformer patches, patchesStrategicMerge 等は簡易記法 Kustomization は他の Kustomization を継承して使うことができる よくある使い方は、リソースを記述する base と 環境ごとの差分を patch する overlay の層に分けるパターン プラグイン
  6. Kustomization のレイヤイメージ Kustomization のレイヤイメージ ディレクトリを Kustomization の単位 (1 つの層) として扱う

    # ==> base/kustomization.yaml <== apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - ./deployment.yaml - ./service.yaml # ==> overlay/kustomization.yaml <== apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - ../base/ patches: # 旧 patchesStrategicMerge - path: ./deployment.patch.yaml
  7. Component Component 再利用できる Kustomization Kustomization から読み込んで使う base はもともと再利用できるので、overlay を再利用するイメージ 語弊はあるが、patch

    等を使い回せると思ってもらえれば 用途の例 複数の overlay で共通の patch を切り出す 複数の base で共通の resource 記述の一部を切り出す オプショナルな従属リソースを base/overlay から切り出す
  8. Component Component # ==> xxxx/kustomization.yaml <== apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization

    resources: - ./deployment.yaml components: - ../component/ # ==> component/kustomization.yaml <== apiVersion: kustomize.config.k8s.io/v1alpha1 kind: Component patches: # 旧 patchesStrategicMerge - path: ./deployment.patch.yaml
  9. 評価順 評価順 Kustomization 内は resources → generators → components →

    transformers v5.0 以前は generator と component の順番が逆だった v5.3 時点では、順序制御する手段はない resource/component で他 Kustomization 等の指定があれば再帰的に ※ kustomize v5.1 のアップデートに合わせて後日変更しました
  10. 評価順 評価順 つまり… Kustomization の base 側から順に評価が確定する Component は参照元 Kustomization

    のタイミングで Kustomization 内は resources → generators → components → transformers
  11. 評価順の例 0 評価順の例 0 images を base と overlay それぞれで設定した場合

    # ==> base/kustomization.yaml <== images: - name: api newName: asia.gcr.io/xxxx-dev/api newTag: 012345678901234567890123456789 # ==> overlay/kustomization.yaml <== images: - name: api newName: asia.gcr.io/xxxx-prod/api newTag: 012345678901234567890123456789
  12. 評価順の例 1 評価順の例 1 configMapGenerator と patch # ==> base/kustomization.yaml

    <== configMapGenerator: - name: sample-cm literals: - foo=1 # どれが優先される? # ==> overlay/kustomization.yaml <== resources: - ../base/ patches: - path: ./sample-cm.patch.yaml configMapGenerator: - name: sample-cm behavior: merge literals: - foo=3 # どれが優先される? # ==> overlay/sample-cm.patch.yaml <== apiVersion: v1 kind: ConfigMap metadata: name: sample-cm data: foo: '2' # どれが優先される?
  13. 評価順の例 2 評価順の例 2 configMapGenerator と commonLabels apiVersion: kustomize.config.k8s.io/v1beta1 kind:

    Kustomization commonLabels: app: api # これは反映される? configMapGenerator: - name: sample-cm literals: - foo=1 options: disableNameSuffixHash: true
  14. 評価順の例 3 評価順の例 3 Kustomization で configMapGenerator、Component で commonLabels #

    ==> ./base/kustomization.yaml <== apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - ./sample-cm1.yaml components: - ../component/ configMapGenerator: - name: sample-cm2 literals: - foo=2 options: disableNameSuffixHash: true # ==> ./base/sample-cm1.yaml <== apiVersion: v1 kind: ConfigMap metadata: name: sample-cm1 data: foo: '1' # ==> ./component/kustomization.yaml <== apiVersion: kustomize.config.k8s.io/v1alpha1 kind: Component commonLabels: some-label-added-by-component: xxxx # 反映される?
  15. 評価順の例 4 評価順の例 4 Kustomization で commonLabels、Component で replacement #

    ==> ./base/kustomization.yaml <== apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization commonLabels: app: <!! patch me !!> configMapGenerator: - name: sample-cm # ==> ./overlay/kustomization.yaml <== apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization commonLabels: app: api resources: - ../base/ components: - ../component/ # ==> ./component/kustomization.yaml <== apiVersion: kustomize.config.k8s.io/v1alpha1 kind: Component replacements: - source: kind: ConfigMap fieldPath: metadata.name targets: - select: kind: ConfigMap fieldPaths: - data.name options: create: true - source: kind: ConfigMap fieldPath: metadata.labels.app targets: - select: kind: ConfigMap fieldPaths: - data.app
  16. base/overlay/component 構成 base/overlay/component 構成 base や 各overlay の中でモジュール分割する ❌ prod/base,

    ❌ api/base 開発系/本番系で分けるパターンも見かけるが… 開発環境前提になっているなら分けずに直す 放置すると後から手を入れるのは難しい overlay の肥大化回避が目的なら後述の方法で ワークロード毎に分ける案もあるが… component や overlay の共通リソースが 綺麗に配置できない
  17. base base モジュール単位で分ける 必要なものを overlay で選択して使うイメージ ワークロードを中心に、周辺リソースを追加 詰め込み過ぎると、overlay に resource

    が増えた り、$delete する必要が出てくる 依存のないリソースが同居している場合は注意 迷ったら分割! → 複数の base を overlay で参照できる。統合も簡単 (overlays に合わせて bases が自然?)
  18. 中間レイヤ 中間レイヤ base と overlay の 2 層ではなく、その間にもう 1 層作るパターン

    適度にグルーピングできそうなら導入はあり 本番系と開発系でそれぞれ似ていて、たくさんある場合など component でも実現できるので、メリデメは検討 適用する component が多い場合など、目的があれば 採用するなら overlays/dev/_base のような構造? _ を付けているのは表示順と、AppSet で除外しやすいように
  19. overlay overlay base 同様にモジュール単位で 基本は参照先の base ごとに Kustomization を分ける 例:

    overlays/dev/dev1/api で bases/api を参照 CD ツールを使っていれば不都合はない Argo CD だと Application が増えるが、 ApplicationSet で回避可 手動デプロイ運用の場合、1 つ上の Kustomization で まとめても component の使い回しが効くので
  20. component component bases、overlays と並べるように配置する 用途例 汎用的なサイドカー・init コンテナ (fluentd, exporter, sysctl

    等) affinity/anti-affinity label は replacement で (component と transformer の順序注意) Argo Rollouts 等の別種のリソースへの差し替え 再利用しなくても、overlay モリモリ回避策として
  21. ファイル名 ファイル名 適切にモジュール分割していれば、kind そのままでも十分 (foo/deployment.yaml, bar/serviceaccount.yaml) resource 以外のファイルは <name>.<type>.yaml が分かりやすい

    xxxx.patch.yaml, xxxx.replacement.yaml, xxxx.transformer.yaml, xxxx.configuration.yaml など ものによっては resource と patch どちらか判別しにいことも
  22. ファイル名 ファイル名 依存の強いものは 1 ファイルにまとめるのも手。アンカーも有用 ただし詰め込み過ぎは NG 可読性の低下だけでなく、kubectl convert しにくくなる等も

    アンカーは一時期使えなくなっていたけど、v4.4 あたりで復活 kind: List items: - apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: ingress annotations: networking.gke.io/managed-certificates: &cert-name certs spec: rules: - host: &domain1 dev1.example.com http: paths: ... - host: &domain2 dev2.example.com http: paths: ... - apiVersion: networking.gke.io/v1 kind: ManagedCertificate metadata: name: *cert-name spec: domains: - *domain1 - *domain2
  23. namePrefix, nameSuffix ({Prefix,Suffix}Transformer) namePrefix, nameSuffix ({Prefix,Suffix}Transformer) 全リソースの名前に prefix, suffix を付ける

    むやみに使わない (一部ケースを除いて) 必要になるなら設計が悪いかも リソース名がわかりにくくなる & 横断処理しにくくなる 使い道もある 同じ環境 (ns) に同じ base からなる別リソースを作る時 kustomization は小さく AWS/GCP 側に同名の実体が作られるようなリソース (ないかも?) 使うならターゲットを絞るのがオススメ
  24. commonLables, labels (LabelTransformer) commonLables, labels (LabelTransformer) 全リソースにラベルを付ける モジュール単位が適切なら、 selector のラベル付けを任せるのも

    labels は selector への適用を制御可 deployment の selector は immutable → apiVersion: apps/v1 kind: Deployment metadata: name: pint spec: template: spec: containers: - name: pint image: pint ports: - name: pint containerPort: 8081 commonLabels: app: pint apiVersion: apps/v1 kind: Deployment metadata: labels: app: pint # ← name: pint spec: selector: matchLabels: app: pint # ← template: metadata: labels: app: pint # ← spec: containers: - name: pint image: pint ports: - containerPort: 8081 name: pint
  25. patches, patchesStrategicMerge, patchesJson6902 patches, patchesStrategicMerge, patchesJson6902 パッチする patchesStrategicMerge, patchesJson6902 は

    deprecated patches を使う 今までの patch ファイルは (基本的に) そのまま使える # 一番古い形式 (removed) patches: - ./xxxx.yaml # よくある形式 (deprecated, v1で削除) patchesStrategicMerge: # or patchesJson6902 - ./xxxx.yaml # 現在の形式 patches: # patchesStrategicMerge, patchesJson6902 形式ともに可 - path: ./xxxx.yaml # inline で書く時は "patch:"
  26. patches, patchesStrategicMerge, patchesJson6902 patches, patchesStrategicMerge, patchesJson6902 マージ方式 (旧 patchesStrategicMerge) 直感的

    通常、同名リソースを対象にするが、target 指定も可 component 化する時に重要 意味単位での YAML ドキュメントの分割がおすすめ パス指定方式 (旧 patchesJson6902) やや書きづらい マージパッチが target 指定できるようになり、登場頻度は低下 複数のフィールドを対象にしたい時などに有用 name や kind の書き換えの時はこっちを使う必要あり (余談) コンテナ名はむやみに変えない方が patch を再利用しやすい
  27. images (ImageTagTransformer) images (ImageTagTransformer) コンテナイメージ名・タグを一括置換する # kustomization.yaml images: - name:

    api newName: asia.gcr.io/xxxx/api newTag: 012345678901234567890123456789 kustomization.yaml の更新は kustomize edit image で可能 CR で使うなら configuration を書く # kustomization.yaml configurations: - ./images_cronworkflow.configuration.yaml # images_cronworkflow.configuration.yaml images: - kind: CronWorkflow path: spec/workflowSpec/templates[]/container/image
  28. configMapGenerator (ConfigMapGenerator) configMapGenerator (ConfigMapGenerator) ConfigMap を生成する デフォルトでランダムな suffix が付く 参照箇所も合わせて変更される

    → apply するとワークロードも更新され、pod が入れ替わる suffix を付けないオプション (disableNameSuffixHash) もある ビルド単位の外から参照される場合に envFrom と相性◦ <ワークロード名>-env みたいな cm を作って参照させる kustomization.yaml に環境特有の値を寄せられる
  29. replacement (ReplacementTransformer) replacement (ReplacementTransformer) 特定の Kustomization に依存しない書き方が良い component と合わせて使うのも良い メイン側に合わせてパラメータを変えたい時

    便利だけど、評価順を理解していないとハマることも component に含めると、transformer の実行前に置換される component から出す or 1 層増やして対応 例: component 内の replacement でラベルを参照しているが、   ラベルは commonLabel で設定している場合
  30. helmCharts (HelmChartInflationGenerator) helmCharts (HelmChartInflationGenerator) 例: fargate 環境用に patch が必要となるチャート helmCharts:

    - name: pyroscope repo: https://pyroscope-io.github.io/helm-chart version: 0.2.92 includeCRDs: true releaseName: pyroscope valuesInline: persistence: enabled: true ... ingress: enabled: true className: alb annotations: alb.ingress.kubernetes.io/scheme: internet-facing ... alb.ingress.kubernetes.io/certificate-arn: '<!! arn:aws:acm:ap-northeast-1:xxxxxxxx:certificate/xxxxxxxx !!>' alb.ingress.kubernetes.io/security-groups: '<!! sg-xxxxxxxx, sg-xxxxxxxx !!>' hosts: [] # - host: pyroscope.example.com # paths: # - path: / # pathType: Prefix resources: - ./pv.yaml patches: - path: ./deployment.patch.yaml - path: ./pvc.patch.yaml
  31. helmCharts (HelmChartInflationGenerator) helmCharts (HelmChartInflationGenerator) helmfile でよくない?という話もあるけど… argocd との相性が良い argocd app

    にも直接書けるが、間に kustomize をかませる 1 層増やすことで手動実行もできるように helmfile が使えないので実質一択 プラグインを書けば使えるが微妙 monitoring unit で使っているのは kustomize 化予定
  32. helmCharts (HelmChartInflationGenerator) helmCharts (HelmChartInflationGenerator) (余談) values を kustomize で merge

    patch できれば更にいいのに… helm/helmfile と同様に複数ファイルで乗り切るか、 kustomize 特有の手法としては KRM function (プラグイン) もある。 巨大 values はどうやってもつらい。kube-prometheus-stack…
  33. kustomization.yaml の自動修正 kustomization.yaml の自動修正 kustomize edit fix で適切な形式に変換できる bases →

    resources patchesStrategicMerge → patches patchesJson6902 → patches vars → replacement commonLabels → labels
  34. Kustomization の apiVersion と kind Kustomization の apiVersion と kind

    省略せずにちゃんと書く (とか言いながら、忘れてる時もあった) いちおうなくても動く 頻繁にバージョンが変わるわけじゃない 今のところだいたい kustomization kustomize init で kustomization.yaml を作るのがオススメ # ==> kustomization.yaml <== apiVersion: kustomize.config.k8s.io/v1beta1 # コレ kind: Kustomization # コレ $ kustomize init $ cat kustomization.yaml apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization
  35. CR の merge patch CR の merge patch CR を適切に加工するためにはスキーマを与える必要がある

    associative list をパッチすると丸ごと上書きされる 等 openapi フィールドに指定 を上書きすることに注意 c.f. assoviative list の patch k8s では kustomize は なフィールド []map[string]string デフォルトのスキーマ リソース/フィールド毎に決まっている merge key を使って結合を行う
  36. component 内で環境依存の値を使う component 内で環境依存の値を使う overlay 側で patch するのも手だが、わかりにくくなる Kustomization が

    Component に依存することになる replacement の使用を検討 適切な値が取れるリソースがない場合、source は configmap を使う component 内の resource として作成し、local-config: true を付け ておく overlay 側の configMapGenerator で上書きする (behavior: merge) generator は transformer (replacement) より先に動作するので…
  37. まとめ まとめ kustomize のマニフェストは kustomization のレイヤできている kustomization は resource/transformer/generator でできている

    評価順がポイント 設計とても大事。よく考えてから書く 加工方法 (transformer, generator) いろいろ おすすめ構成あるよ