個人 k3s クラスタを Git と Kustomize で育てる
2026-06-19

個人 k3s クラスタを Git で育てる

個人で k3s クラスタを運用していると、最初は小さな YAML だけで十分に見える。

「まずはアプリを 1 つ動かす」 「外からアクセスしたくなったら Ingress を足す」 「データを消したくないから PVC を足す」 「Secret はあとでちゃんと整理する」

そんなふうに始めても、動かすアプリが増えると、だんだん記憶だけでは管理できなくなる。どのアプリに DB が必要だったか。どの設定が本番用で、どれが検証用だったか。どの YAML を適用すれば、同じ構成をもう一度作れるのか。

そこで、自分の k3s クラスタでは Kubernetes の manifest を Git で管理している。

この記事では、そのリポジトリの考え方を紹介する。最初からきれいに設計されたサンプルではなく、個人運用の中で少しずつ育ってきた構成だ。だからこそ、これから自分のクラスタを Git 管理したい人にとって、現実的なヒントになると思う。

なお、この記事では実 IP アドレス、実ノード名、ドメイン、Secret の中身、鍵、kubeconfig などは扱わない。公開してよい構成の考え方だけに絞って書く。

なぜ Git で管理するのか

Kubernetes は便利だが、アプリを動かすための YAML はすぐに増える。

たとえば 1 つの Web アプリでも、実際には次のようなリソースが必要になる。

  • アプリ本体の Deployment
  • アプリにアクセスするための Service
  • 外部公開するための Ingress
  • データを保存する PVC
  • 設定を渡す ConfigMap
  • パスワードやトークンを扱う Secret
  • DB や Redis などの周辺コンポーネント

これらを手元のメモや一時ファイルだけで管理していると、あとから必ず困る。

Git に置いておくと、いつ、なぜ変更したのかを追える。前の状態に戻せる。別の環境に同じ構成を適用しやすくなる。個人クラスタでも、この安心感はかなり大きい。

ディレクトリ構成

今回の構成は、大きく baseoverlays に分かれている。

projects/
  base/
    <app>/
      kustomization.yaml
      namespace.yaml
      deployment-*.yaml
      service-*.yaml
      charts/

  overlays/
    dev/
      <app>/
      01_configMap/
      02_settings/
      base/

    prod/
      kustomization.yaml
      <app>/
      01_configMap/
      02_settings/
      base/

base には、アプリの基本形を置く。

たとえば Forgejo なら、アプリ本体、DB、Redis、runner など、どの環境でも共通して必要になる manifest が base/forgejo にまとまっている。

overlays には、環境ごとの差分を置く。

たとえば同じ Forgejo でも、検証用の dev と普段使う prod では、公開方法や保存先、Secret の渡し方が変わることがある。そうした違いを overlays/dev/forgejooverlays/prod/forgejo に分けている。

Kustomize では、このように共通部分を base に置き、環境ごとの変更を overlay として重ねられる。この考え方は、個人クラスタでもかなり使いやすい。

base はアプリの基本形

Forgejo の base は、ざっくり次のような構成になっている。

namespace: forgejo

resources:
  - ./namespace.yaml
  - ./deployment-db.yaml
  - ./deployment-forgejo.yaml
  - ./deployment-redis.yaml
  - ./deployment-runner.yaml

ここには「Forgejo というアプリを動かすための基本セット」が入っている。

アプリ本体だけではなく、PostgreSQL、Redis、runner も同じディレクトリに置いている。こうしておくと、Forgejo の構成を確認したいときに、関連する manifest をまとめて追える。

Grafana や Directus も同じように、アプリごとのディレクトリに manifest をまとめている。1 アプリ 1 ディレクトリに近い形にしておくと、「このアプリの設定はどこにある?」で迷いにくい。

また、一部のアプリでは Helm chart を base/<app>/charts に置いている。リポジトリは重くなりやすいが、使っている chart のバージョンを固定しやすい。個人運用では、最新を追い続けることよりも「前と同じものをもう一度動かせる」ことが大事な場面も多い。

overlay は環境ごとの調整

base だけでは、実際のクラスタでは足りないことが多い。

たとえば、外部からアクセスするための Ingress、データを保存する PVC、環境ごとの ConfigMap、Secret の参照、特定の Pod だけに入れたい変更などは、環境によって変わりやすい。

Forgejo の prod overlay は、base を読み込んだうえで、prod 用に必要な manifest を追加している。

resources:
  - ../../../base/forgejo
  - ../01_configMap
  - ./externalsecret.yaml
  - ./ingress-traefik.yaml
  - ./configmap-forgejo.yaml
  - ./local-hostpath-pvc.yaml

ここでは base/forgejo に、共通 ConfigMap、Secret の参照、Ingress、PVC などを重ねている。

この分け方にしておくと、アプリの基本形を壊さずに、環境ごとの事情を足せる。たとえば「検証環境では別の設定で動かしたい」「本番環境では永続化したい」といった変更を、overlay 側に閉じ込められる。

個人クラスタでも、この分離は効いてくる。小さな環境では dev/prod を厳密に分けないこともあるが、それでも「これは共通」「これはこの環境だけ」という境界を作っておくと、あとから直しやすい。

01_configMap は共通設定

overlays/dev/01_configMapoverlays/prod/01_configMap には、複数アプリで使う共通の ConfigMap を置いている。

configMapGenerator:
  - name: configmap-uid-gid
    literals:
      - PUID="<uid>"
      - PGID="<gid>"

たとえば LinuxServer 系の container image では、プロセスをどの UID/GID で動かすかを環境変数で渡すことがある。同じ設定を複数アプリで使うなら、各アプリの YAML に毎回書くより、共通の ConfigMap としてまとめたほうが分かりやすい。

01_configMap という名前は少し運用メモっぽいが、役割ははっきりしている。複数アプリで使い回す小さな設定置き場だ。

02_settings は Secret 管理の変遷

02_settings には、Secret を参照するための manifest や、Secret 管理方式に関する設定を置いている。

Secret 管理は、個人クラスタでも悩みやすい。最初は Kubernetes Secret で始めることもあるが、その中身を Git に置くのは危ない。次に SealedSecret を使うと、暗号化された Secret を Git で扱いやすくなる。さらに運用が進むと、ExternalSecret を使って外部の Secret store から値を同期したくなる。

このリポジトリにも、その変遷が残っている。理想形だけを見れば整理したい部分はあるが、これは失敗というより、運用が少しずつ成熟してきた跡でもある。

大事なのは、Secret の中身を Git や記事に出さないことだ。この記事でも Secret ファイルの内容は見ず、どの方式で参照しているかだけを扱っている。

クラスタ共通の部品もある

アプリごとの manifest とは別に、クラスタ全体で使う部品もある。

たとえば reflector や replicator のように、特定のアプリ専用ではなく、クラスタ全体の運用を助けるコンポーネントがある。こうしたものは overlays/dev/baseoverlays/prod/base から共通部品として参照している。

このあたりは、今後もう少し名前を整理すると読みやすくなりそうだ。アプリ用の base と、クラスタ基盤用の base が同じ名前になっているため、初見では少し迷いやすい。

この構成で良かったこと

この構成の一番の良さは、アプリ単位で探せることだ。

Forgejo のことを見たいなら Forgejo のディレクトリを見る。Grafana のことを見たいなら Grafana のディレクトリを見る。アプリごとに manifest がまとまっているので、運用中に「どこを直せばいいのか」が分かりやすい。

次に、環境差分を overlay に逃がせることも大きい。

Ingress、PVC、Secret、ConfigMap、Deployment への小さな patch は、クラスタや環境に依存しやすい。これらを base に直接混ぜると、検証用と本番用の違いが見えにくくなる。overlay に置いておけば、どこが環境ごとの差分なのかが残る。

そして、Git の履歴が運用ログになる。

アプリのバージョンを上げた。PVC を追加した。Secret 管理を変えた。Ingress の設定を変えた。こうした変更が commit として残るので、未来の自分が読み返せる。個人運用では、この「未来の自分に説明できる」ことがかなり重要だ。

まだ整理したいところ

一方で、まだ整理したいところもある。

まず、dev と prod を同じ手順で確認できるようにしたい。

Kustomize では、たとえば次のように実行すると、指定したディレクトリの manifest をまとめて出力できる。

kubectl kustomize projects/overlays/prod

これは「実際にクラスタへ反映する前に、どんな YAML ができるか確認する」ために便利だ。prod ではこのようにまとめて確認しやすい形になっているが、dev はアプリごとのディレクトリを個別に見る形が中心になっている。

将来的には、dev も prod も同じように kubectl kustomize で確認できる形にそろえたい。そうすると、手元での確認や CI での検証がしやすくなる。

Secret 管理も、少しずつ方針をそろえたい。

raw Secret、SealedSecret、ExternalSecret が混ざっていると、初めて読む人には「どの方式を使えばいいのか」が分かりにくい。最終的には ExternalSecret のような仕組みに寄せると、Git には参照だけを置き、実際の値は外部の Secret store で管理できる。

また、複数アプリで繰り返し出てくる設定も整理したい。UID/GID の ConfigMap、local hostPath の PVC、node affinity のような設定は、アプリごとに似た形で増えやすい。共通部品としてまとめられれば、あとから変更するときに楽になる。

最後に、アプリとクラスタ基盤を分けたい。Forgejo や Grafana のようなアプリと、cert-manager、Traefik、Sealed Secrets、External Secrets、Longhorn のような基盤コンポーネントは、役割が違う。ディレクトリ上でも分けておくと、初めて読む人にも構造が伝わりやすくなる。

小さく始めて、あとから育てる

個人 k3s クラスタの manifest 管理は、最初から完璧でなくていい。

最初は 1 つのアプリを YAML にする。次に Git に置く。環境差分が出てきたら overlay を作る。Secret 管理がつらくなったら、SealedSecret や ExternalSecret に移る。共通設定が増えたら、部品として切り出す。

大事なのは、運用を頭の中だけに置かないことだ。

Git に残しておけば、あとから読める。差分を見られる。戻せる。同じような構成をもう一度作れる。個人クラスタでも、これは十分に価値がある。

今回の構成は、まだ整理途中の部分を含んでいる。けれど、それも含めて実運用らしい。Kubernetes の manifest は、完成品として最初から存在するというより、動かしながら少しずつ育っていくものだと思っている。

次回

次回は、Kustomize の base / overlays をもう少し具体的に見る。

どこまでを base に置き、どこからを overlay に分けるのか。Forgejo などの実例を使いながら、個人 k3s クラスタで扱いやすい分け方を整理していく。

個人 k3s クラスタを Git と Kustomize で育てる
https://notes.midnightstops.com/posts/28/
作者
Author
公開日
2026-06-19