ようこそ!
Tazuna ドキュメントへようこそ。
Tazuna は、マルチクラスタ Kubernetes 環境のブートストラップライフサイクルを管理するための CLI ツールです。
tazuna.yaml に「どのクラスタへ、どのマニフェストを、どの順で適用するか」を宣言的に記述し、
その内容を apply / destroy / state といったコマンドで一貫して運用できます。
このドキュメントについて
このドキュメントは、Tazuna を初めて触る人から、CI に組み込んで継続的に運用する人、 そして Tazuna 本体に手を入れる人までを対象に、次の流れで構成しています。
- はじめかた — Tazuna を手元で初めて動かせる状態にするまで。
- 概念 — Tazuna が解こうとしている問題と、その設計思想・アーキテクチャ。「なぜそうなっているか」を扱います。
- ガイド —
tazuna.yamlを書くなど、実際に手を動かすためのタスク単位の手順。「何を、どの順で、どのコマンドで行うか」を扱います。 - 運用 —
destroyの運用、drift モニタリング、CI パイプラインなど、継続的に使う局面の指針。 - リファレンス — 入力ファイル・CLI・内部データ構造の仕様。フィールド・型・デフォルト・例を規約書として参照できます。
- コントリビュート — 開発環境・テスト・ドキュメント・リリースなど、Tazuna に変更を入れる人向けの案内。
どこから読むか
- まだ Tazuna に触れたことがなければ、はじめかた から順に進むのがおすすめです。
- 設計の背景や用語を先に押さえたい場合は 概念 から。
- 特定のコマンドやフィールドの仕様だけを調べたい場合は リファレンス を辞書的に参照してください。
はじめかた
このセクションは、Tazuna を初めて手元で動かせる状態にするまでを通します。
ここを通したあと、実際の tazuna.yaml の書きかたは
ガイド - 最初の tazuna.yaml を書く に進んでください。
ゴール:
- 自分のマシンに
tazunaバイナリが入っている tazuna versionが動く- どんなクラスタ・どんな外部ツールが前提なのか把握できている
1. インストール
tazuna は単一バイナリです。以下のいずれかの方法で入れます。
リリースバイナリを使う
GitHub の Releases から、
お使いの OS / arch のアーカイブをダウンロードし、tazuna を PATH に置きます。
# 例(macOS arm64 / Linux amd64 などのアーカイブを展開後)
mv tazuna /usr/local/bin/
tazuna version
CI で固定バージョンを使いたい場合や、再現性を担保したい場合はこの方法を推奨します。
go install を使う
Go 1.x の toolchain がある場合は、ソースから直接ビルドできます。
go install github.com/pepabo/tazuna@latest
@latest の代わりに @v0.x.y でバージョンを固定できます。
バイナリは $(go env GOBIN)(未設定なら $(go env GOPATH)/bin)に入ります。
ソースから直接ビルドする
リポジトリを clone した状態から自分でビルドする場合は次のとおりです。
make build # ./tazuna が生成される
make install # /usr/local/bin にインストール(sudo を使う)
2. 動作確認
インストール後、何も設定せずに次のコマンドが通ることを確認します。
tazuna version
tazuna --help
tazuna version の出力は次のような形式です(実際の値は環境によって変わります)。
tazuna v0.1.0 (commit abc1234, built 2026-05-25T03:21:00Z, darwin/arm64)
ローカルビルドの場合は version / commit / built がそれぞれ dev / none /
unknown になります(tazuna version を参照)。
3. 前提を揃える
tazuna がクラスタに対して動作するためには、いくつかの前提が必要です。
すべて必須ではありません。下の表の「必須」だけまず揃えればよく、
1Password / git は使う機能に応じて任意で揃えます。
| 依存 | 必須? | 説明 |
|---|---|---|
| Kubernetes クラスタ | ◯(apply / destroy / state ... を使うとき) | コントロールプレーンの用意は Tazuna の範囲外です。手元で試すなら KinD / minikube、リモートなら EKS / GKE / AKS / kubeadm などで構いません。 |
kubeconfig の current-context | ◯(同上) | kubectl config current-context で、入れたい先のクラスタを指していることを確認します。kubectl get nodes が通る状態にしておきます。 |
kubectl | -(推奨) | Tazuna 自身は使いませんが、kubeconfig 操作や反映結果の確認で使います。 |
kustomize / helmfile / helm バイナリ | -(不要) | Tazuna は Go ライブラリとして組み込んでいるため、外部バイナリのインストールは不要です。 |
1Password CLI (op) | -(type: genesissecret や helmfile.vars の from: op を使うときのみ) | op コマンドが PATH にあり、サービスアカウントで認証されていることが前提です。 |
git | -(任意) | tazuna state sync 時に _metadata.gitCommitHash を埋めるために使います。リポジトリ外で実行した場合や git が無い場合は、エラーにせず空文字で記録されます。 |
クラスタの選び方や kubeconfig の扱いについては、ガイドの
前提 でも触れています。
4. 次に進む
ここまでで tazuna が手元で動く状態になりました。
- ガイド - 最初の tazuna.yaml を書く で、
実際に
tazuna.yamlを 1 枚書いてapplyするところまで進めます。 - 仕様だけを引きたいときは リファレンス を参照してください。
- 「なぜそうなっているか」が知りたい場合は 概念 を参照してください。
概念
このセクションでは、Tazuna がどのような問題を解こうとしているのか、 そしてそのためにどのような設計を採用しているのかを順を追って説明します。
「動かし方」よりも「なぜそのような形になっているか」を中心に書いているため、 具体的なコマンド一覧や CLI フラグについては リファレンス、 具体的な手順については ガイド を参照してください。
読み進め方
おすすめの読み順は次のとおりです。
- 設計思想と想定ユースケース — Tazuna が何のために存在し、 どんな現場で使われることを想定しているかを最初に押さえます。
- 全体アーキテクチャ —
tazunaバイナリの中に どんなコンポーネントが入っていて、どのように協調するかを俯瞰します。 - 用語集 — このセクションで使われる用語の定義をまとめています。
tazuna.yaml のスキーマや各 Manifest backend、State / マルチクラスタ /
Secret 連携の挙動など、より具体的な仕様は リファレンス を参照してください。
途中で分からない言葉が出てきた場合は、まず用語集を参照してください。
設計思想と想定ユースケース
Tazuna は「マルチクラスタ Kubernetes のブートストラップライフサイクルを管理する CLI」です。 ここでは、なぜそういうツールが必要になるのか、Tazuna が何を肩代わりし、何は肩代わりしないのか、 という設計上のスタンスを整理します。
解こうとしている問題
Kubernetes クラスタは、API サーバが立ち上がっただけでは実用には使えません。 そこから「自分たちのクラスタ」と呼べる状態にするまでには、
- CNI / Ingress / cert-manager のような インフラ層のアドオン
- ArgoCD / Flux のような デプロイ基盤そのもの
- 各種オペレータや CRD
といったレイヤを、正しい順序で、依存関係を保ちながら クラスタに入れる必要があります。
これを手作業や 複雑な運用手順書、シンプルなシェルスクリプトで代用すると、
- どこまで適用したか分からなくなる(=「state がない」)
- クラスタのブートストラップ手順が古くなる
といった問題が積み上がります。Tazuna はここに 単一の宣言的な設定ファイル と 統一された CLI を持ち込み、ブートストラップという「特定の段階」だけを明示的に扱います。
Kubernetesクラスタをイミュータブルに運用するアイデア
Tazuna の背景にある考え方のひとつが、Kubernetes クラスタそのものを イミュータブル(不変)なリソースとして扱う という発想です。 ここでいうイミュータブルとは、「動いているクラスタを継ぎ足しで直していく」のをやめて、 クラスタは常に同じ手順で作り直せる状態にしておく ことを指します。
ここで「不変」と言っているのは クラスタの土台レイヤ の話です。 Deployment で動いているアプリケーションの Pod が新しいイメージに置き換わったり、 HPA でレプリカ数が変化したりすることを mutate と呼んでいるわけではありません。 対象にしているのは、CNI / Ingress / cert-manager / ArgoCD といった インフラアドオンや、それらが依存する CRD やオペレータといった、 クラスタを「クラスタとして成立させている」基盤レイヤです。 アプリケーションレイヤは、その上で GitOps によって自由に mutate されてかまいません。
長期間運用していると、クラスタには次のような変更が少しずつ溜まっていきます。
- 障害対応のなかで誰かが
kubectl applyした暫定マニフェスト - バージョン調査のために手で入れ替えた CRD やオペレータ
- 手元の
helm installで入った add-on
これらが積み重なると、「実際に動いているクラスタ」と「コードで宣言したクラスタ」が 徐々にずれていく(コンフィグレーションドリフト)状態になります。 こうなるとクラスタを作り直すコストが跳ね上がり、DR / リージョン追加 / Kubernetes バージョンアップといった「クラスタごと入れ替えたい」場面で動けなくなります。
イミュータブルに運用するというのは、この状況を裏返して、
- クラスタの中身は すべて宣言された設定から再生成できる ことを前提にする
- ブートストラップ後の add-on レイヤは、必要なら 一度クラスタを捨てて作り直しても同じになる
- 手で入れたものは「いつ消えても良いもの」と割り切るか、宣言側に取り込む
という運用スタイルを選ぶことです。アプリケーションレイヤであれば、これは ArgoCD や Flux のような GitOps ツールがすでに担保しています。 一方で、その GitOps ツール自身を含む「ブートストラップ層」 は、 従来は手順書とシェルスクリプトに頼りがちで、イミュータブルさが最も崩れやすい場所でした。
Tazuna は、このブートストラップ層をイミュータブル運用の枠に乗せるための部品として位置付けています。
tazuna.yamlという 単一の宣言的な設定ファイル に CNI / Ingress / cert-manager / ArgoCD などの構成順序を書き切ることで、クラスタの初期状態を コードから一意に再生成できるようにします。tazuna applyは、その宣言と実クラスタの差分を埋める操作です。 「新規クラスタの初日」と「既存クラスタへの追従」を 同じコマンド で扱うので、 作り直したクラスタも既存クラスタも、最終的に同じ宣言に収束します。stateによって「いま何が入っているか」を持ち、context_matchesで どのクラスタに対する宣言なのかを縛ることで、 「別のクラスタに間違って適用する」「適用したかどうか分からない」 を仕組みで防ぎます。- ブートストラップが終わったあとのアプリケーション運用は ArgoCD / Flux に渡します。 ここでイミュータブル運用のバトンがアプリケーションレイヤに引き継がれ、 ブートストラップ層と継続的デリバリ層の両方 が宣言から再現可能になります。
なお Tazuna は「クラスタを毎回作り直して運用すること」を強制するわけではありません。 実際にイミュータブルに運用する(クラスタごと作り直して切り替える)スタイルも 想定の中に入っていますが、より重視しているのは、その一歩手前の性質、すなわち 「Kubernetes クラスタが任意のタイミングで壊れたとしても、保証された手順で 自動的に再構築できる」 状態を常に保てることです。
この性質さえあれば、
- 普段は同じクラスタを使い続けて運用する
- DR や大きなバージョンアップのタイミングだけ、別のクラスタを丸ごと立てて切り替える
- 検証用の使い捨てクラスタを必要なときに立ち上げる
といった選択肢を そのときの状況に応じて選べる ようになります。
Tazuna は、その「保証された再構築手順」を tazuna.yaml というコードと
tazuna apply という一つのコマンドに集約することで、
イミュータブル運用を選べる状態を維持し続ける ための土台を提供します。
Tazuna が肩代わりしないこと
意図的に踏み込まない領域もあります。
- 継続的デリバリ — ArgoCD や Flux の代替ではありません。Tazuna の役目は、 そうしたツールをクラスタに 入れるまで です。入ったあとは ArgoCD/Flux に渡します。
- マニフェストの中身を書く — kustomize の overlay、helmfile の構成、Helm chart の値は、 既存の各ツールの作法で書きます。Tazuna はそれらを 呼び出して結果をクラスタへ流す だけです。
- コントロールプレーンの作成 —
kubeadm/kops/ マネージドサービスのクラスタ自体は前提です。 Tazuna はkubeconfigを介して既存クラスタへ接続します。 - Secret 管理基盤そのもの — Secret の格納先の参照を宣言しますが、 Tazuna 自身は秘密を保管しません。
- GitOps のロールバック・履歴管理 —
stateは「いま何が入っているか」を表すもので、 歴史的なバージョン管理は git に任せます。
想定ユースケース
具体的に Tazuna が嬉しい場面はおおむね次のようなときです。
- 新規クラスタを立ち上げる初日 —
tazuna apply1 発で、 CNI からデプロイ基盤までを所定の順序で入れたい。 - Kubernetesクラスタの構築手順が妥当であることを自動検証する
- 同じ役割のクラスタを複数立てる — staging / production / dr といった
類似クラスタを、ほぼ同じ
tazuna.yamlで立ち上げたい。
次は 全体アーキテクチャ で、これらをどんな部品で実現しているかを見ます。
全体アーキテクチャ
このページでは Tazuna を構成する主なコンポーネントと、
それらが tazuna apply のときにどう協調するかを俯瞰します。
ここでは責務の境界だけを扱います。具体的なディレクトリ構成や Go パッケージの分割方針は意図的に触れません。
レイヤ図
おおまかには次の 3 層構造です。
+--------------------------------------------------+
| CLI |
| apply / build / check / destroy / state ... |
+--------------------------------------------------+
|
v
+--------------------------------------------------+
| Runner |
| - load tazuna.yaml / expand includes |
| - verify context_matches / filter by tags |
| - dispatch each manifest to a Manager |
+--------------------------------------------------+
|
+-------------+-------------+
v v
+---------------------+ +---------------------+
| Manager | | Test plugin |
| | | wait-until / |
| kustomize / | | exist-nonexist |
| helmfile / | +---------------------+
| oras / |
| genesissecret / |
| parallel |
+---------------------+
|
v
+---------------------+
| Kubernetes cluster |
+---------------------+
各 manifest は 1 つの Manager を介してクラスタに反映されます。 適用前後の検証は Test plugin に切り出されており、 manifest 単位でも tazuna.yaml 全体でも実行できます。
主要コンポーネント
Tazuna は内部的に次のコンポーネントが組み合わさって動きます。 ここでは各コンポーネントが「何を入力に取り、何を出力するか」という責務だけを示します。
CLI
サブコマンド(apply, build, check, destroy, state list, state diff,
state sync, secret-to-genesissecret, version など)の入り口です。
フラグの解釈と Runner の組み立てだけを担当し、ロジック自体は持ちません。
Runner
Tazuna 全体のオーケストレータです。次を担当します。
tazuna.yamlのロードincludesの展開tazuna.yaml起点の相対パスを実行時パスへの変換--tagsによるフィルタ- 各 manifest を対応する Manager へ渡す
- 適用後の Test plugin の実行
Runner は manifest type の種類を知りません。 「どの type に対してどの Manager を使うか」というマップだけを持ち、 それ以外は Manager 側に委ねます。
Manager
manifest type ごとの「実際の適用方法」を実装するコンポーネントです。 すべての Manager は次の 3 つの操作を提供します。
- Apply — その manifest をクラスタへ反映する
- Destroy — その manifest が入れたものをクラスタから取り除く
- Build — クラスタには触らず、適用したら何が入るかだけを生成する
Runner はこの 3 操作だけを介して manifest type を均一に扱います。 個別のバックエンドの責務分担は リファレンス を参照してください。
Validator
tazuna.yaml のロード直後に走るスキーマ・パス整合性検証です。
apply も check も最初にここを通り、不正な YAML や
存在しない path を クラスタに触る前に 弾きます。
Context guard
tazuna.yaml の context_matches を読み、現在の kubeconfig context 名が
そのパターン(複数の正規表現)に合致しているかを検証します。
合致しなければ apply / destroy はここで終了し、クラスタには一切触れません。
State store
Tazuna が「自分が入れたリソースの指紋」をクラスタに記録するための仕組みです。
保存先はクラスタ内の ConfigMap で、state list / state diff / state sync は
ここを起点に動きます。
Secret provider
GenesisSecret および helmfile の vars.op から参照される、
「シークレットの取得元」を抽象化したコンポーネントです。
現状は 1Password 向けの実装が組み込まれています。
Test plugin
manifest 適用後(または tazuna.yaml 全体の適用後)に走らせる検証の仕組みです。
組み込みで次の 2 種が利用できます。
wait-until— 指定リソースが存在 / Ready / Available になるまで待つexist-nonexist— 指定リソースが存在 / 非在 であるべきことを表明する
Hint
helmfile の vars が取りうる値の型・フォーマット
(hostname / URL / email / IP / CIDR / UUID / semver / datetime など)を
宣言的に検証するための補助コンポーネントです。
Prompt
破壊的操作の Yes/No 確認といった対話 I/O を抽象化するコンポーネントです。 非対話モードやテスト時に振る舞いを差し替えるためのものです。
tazuna apply のときの流れ
ここでは「どのコンポーネントが何をするか」の観点で並べておきます。
- CLI がフラグを解釈し、Runner を組み立てる。
- Validator が
tazuna.yamlを読み、スキーマとpathの存在を検証する。 spec.context_matchesがあれば Context guard が kubeconfig を検証する。- Runner が
includesを展開し、manifests[].pathを実行時パスへ変換する。 manifestsを順に走査し、--tagsで除外されないものを 対応する Manager に渡す。- 各 Manager は内部で kustomize / helmfile / oras pull / 1Password 取得 などを呼び出し、 結果をクラスタへ反映する。State store に指紋が書き込まれるのもここ。
- manifest 単位 / 全体の Tests があれば Test plugin が走る。
tazuna state sync はこの 1〜4 までを使ったうえで、
各 Manager の Build 結果から State diff を組み、追加分・変更分だけを apply します。
用語集
このセクションで頻出する用語の定義をまとめます。 より詳しい仕様は リファレンス を参照してください。
Tazuna 固有の用語
tazuna.yaml
Tazuna に対する唯一の入力ファイル。apiVersion: tazuna.pepabo.com/v1,
kind: Tazuna を持ち、spec.manifests[] に「適用したい manifest 群」を宣言する。
Manifest
tazuna.yaml 内の manifests[] の 1 エントリのこと。
name / type / path を持ち、type ごとに対応する Manager が処理する。
Kubernetes における「マニフェスト」(YAML ファイル)とは指す対象が違う点に注意。
Manifest type
Manifest の処理方法を指定する文字列。
kustomize / helmfile / genesissecret / parallel / oras の 5 種類。
Manager
ある Manifest type に対する処理を担うコンポーネント。
Apply(クラスタへの反映)/ Destroy(取り外し)/ Build(クラスタに触らない生成)の
3 つの操作を提供し、Runner はこの 3 つを介してすべての backend を均一に扱う。
Runner
Tazuna の中心オーケストレータ。tazuna.yaml のロード、includes 展開、--tags フィルタ、
Manager の呼び出し、Test plugin の起動などをまとめて担当する。
Test plugin
Manifest 適用の前後で行いたい検証を表現する仕組み。
組み込みで wait-until(Ready/存在まで待つ)と exist-nonexist(存在/非在の表明)がある。
spec.manifests[].tests か spec.tests に書く。
State
Tazuna が「自分が入れたリソース」を追跡するための記録。
クラスタ内 tazuna namespace の ConfigMap (tazuna-state-<manifest-name>) に保存される。
State key
State の 1 エントリを指すキー文字列。
namespaced なら {manifest}/{group}/{version}/{kind}/{namespace}/{name}、
cluster-scoped なら {manifest}/{group}/{version}/{kind}/{name}。
ContentHash
State の各エントリが持つ SHA-256 ハッシュ値。
リソース YAML から metadata.resourceVersion / uid / creationTimestamp /
generation / managedFields / selfLink と status を除いて計算する。
このハッシュの一致/不一致が state diff の判定基準。
Diff type
tazuna state diff がリソースごとに付ける分類。
added / modified / removed / always-sync の 4 種類。
always-sync
GenesisSecret 由来 Secret のように、差分計算をスキップして毎回同期する扱いの Diff type。 ContentHash で変化を判定できない / させない対象に使う。 1Password 側で値が更新されてもクラスタ側のハッシュは変わらないため、 ContentHash を使わずに毎回 Provider に問い合わせる形で同期する設計になっている。 利用例と運用上の扱いは GenesisSecret スキーマ - State と always-sync と Drift モニタリング を参照。
GenesisSecret
1Password に保管された秘密情報から、Kubernetes Secret を 生成 するための宣言。
Kubernetes CRD ではなく、Tazuna が読む YAML スキーマ。
type: genesissecret の manifest として tazuna.yaml から参照する。
Provider (SecretProvider)
GenesisSecret が秘匿情報を取り出す元を抽象化したインターフェース。
現状は 1Password (op) 向けの実装が組み込まれている。
context_matches
tazuna.yaml の spec.context_matches。
現在の kubeconfig context 名がマッチすべき正規表現の配列で、
誤クラスタへの apply を防ぐためのガード。
context_match_mode
context_matches の評価方式。or(デフォルト)または and。
includes
manifests[] のエントリで、別ファイルの tazuna.yaml を読み込み、
その manifests[] を展開するための仕組み。ネストは不可。
Tag (manifest tag)
manifests[].tags に書く文字列。tazuna apply --tags foo,bar のように
適用対象を絞り込むときに使う。複数タグは OR で評価される。
Manifest path
manifests[].path。tazuna.yaml 自身の置かれているディレクトリ起点の相対パスとして書く。
Tazuna は実行時に cwd 起点へ変換する。
tazuna.hint.yaml
helmfile の vars が取りうる値の型・フォーマット制約を宣言するヒントファイル。
pkg/hint/ で読まれる。
Kubernetes 側の用語(補足)
ここに挙げるのは Tazuna 内で頻出する Kubernetes 標準用語の短い定義です。
kubeconfig
クラスタ接続情報(cluster / user / context)をまとめた YAML。
Tazuna はここから current-context を読み、そのクラスタへ操作を行う。
context (kubeconfig context)
「どの cluster にどの user で繋ぐか」を 1 名前にまとめた kubeconfig の要素。
context_matches が正規表現でチェックするのはこの context 名。
GVK (Group/Version/Kind)
Kubernetes リソースの種別を一意に特定する 3 つ組。 Tazuna の State key も GVK を含む。
namespaced / cluster-scoped
リソースが namespace に属するか属さないか。 State key の長さ(5 パートか 6 パート)に反映される。
ConfigMap
任意の key-value をクラスタに保存するための組み込みリソース。 Tazuna の State の保存先として使われる。
外部ツール
kustomize
Kubernetes manifest の overlay / patch 機構。
type: kustomize の Manager から呼び出される。
helmfile
複数の Helm release を 1 YAML から束ねるツール。
type: helmfile の Manager から呼び出される。
Helm
Helm chart を扱うパッケージマネージャ。helmfile から内部的に使われる。
ORAS / OCI artifact
OCI registry に Kubernetes manifest のようなコンテナ以外の成果物を置く規格。
type: oras で pull し、delegate に指定した helmfile / kustomize に処理を委譲する。
1Password
Tazuna が GenesisSecret や helmfile.vars.op で参照する Secret の格納先。
取得は op コマンド経由。
ガイド
このセクションでは、Tazuna を使って実際に手を動かすための手順をまとめます。 概念 が「なぜそうなっているか」を扱うのに対し、 ここでは「何を、どの順で、どのコマンドで行うか」をタスク単位で示します。
各ガイドは独立して読めるように書いていますが、まだ Tazuna に触れたことがない場合は、 順番に通すと無理なく進められます。コマンドの細かい挙動やフラグの一覧は リファレンス を参照してください。
入門
新しく Tazuna を導入したいときに最初に通すグループです。
- 最初の tazuna.yaml を書く —
1 つの Kubernetes クラスタに kustomize で書いた add-on を 1 つ入れるところまでを、
tazuna.yamlの最初の 1 枚からtazuna applyまでひと通り通します。
これ以降のテーマ(複数 manifest の順序付け、--tags による絞り込み、
State の確認、GenesisSecret、CI 連携など)は、ここで作った tazuna.yaml を
徐々に拡張していく形で順次追加していきます。それまでの間、各テーマの
仕様 は以下のリファレンスから引けます。
--tagsの評価:tazuna.yaml- tags- State の確認: State の内部構造 /
tazuna state list - GenesisSecret: GenesisSecret スキーマ
- CI 連携: CI パイプライン
最初の tazuna.yaml を書く
このガイドは、これから Tazuna を導入する人が 最初の tazuna.yaml を書き、
1 つの Kubernetes クラスタに 1 つのアドオンを入れるところまでを通すための手順です。
ここでは題材として、kustomize で書いた小さな Deployment を 1 つ、
Tazuna 経由でクラスタに入れます。実運用ではここに ingress-nginx や cert-manager、
ArgoCD などが並びますが、最初の 1 枚を理解するためには Manifest は 1 つあれば十分です。
このガイドを終えると、次の状態になっています。
- 自分のリポジトリに
tazuna.yamlと kustomize ディレクトリが 1 セットある tazuna checkでそのtazuna.yamlが妥当だと確認できるtazuna buildでクラスタに触れずに「何が入るか」を確認できるtazuna applyでその内容がクラスタに反映されている
前提
Kubernetes クラスタを 1 つ用意する
Tazuna はクラスタの作成そのものは行いません。コントロールプレーンの準備は前提です。 試すだけであれば、手元で動かせる軽量なクラスタで十分です。
- 手元で完結させたい場合: KinD や minikube で 1 ノードのクラスタを立てる
- リモートでまず触ってみたい場合: EKS / GKE / AKS などのマネージドクラスタ、
または
kubeadmで立てた検証用クラスタ
kubectl get nodes が Ready を返す状態になっていれば、どれを選んでも構いません。
tazuna バイナリを用意する
リリースページからバイナリを取得して PATH に置くか、go install で導入します。
詳細は はじめかた を参照してください。
tazuna version が動けば準備完了です。
kubeconfig の current-context を確認する
Tazuna は kubeconfig の現在の context が指すクラスタに対して動きます。 入れたい先のクラスタに current-context が向いていること を、手を動かす前に必ず確認します。
kubectl config current-context
kubectl get nodes
複数クラスタを行き来する環境では、これを取り違えるのが最も典型的な事故の入口です。
context を取り違えても気付けるようにする仕組みとして context_matches がありますが、
最初の 1 枚では使わずに進めます(後続のガイドで扱います)。
作るもの
このガイドでは、次のようなディレクトリ構成を作ります。
my-cluster/
├── tazuna.yaml
└── kustomize/
└── nginx/
├── kustomization.yaml
└── deployment.yaml
tazuna.yaml が「何を入れるか」を宣言し、kustomize/nginx/ がその実体です。
このガイドではこの 2 階層だけを覚えておけば十分です。
1. kustomize ディレクトリを作る
まず、Tazuna が呼び出す側、つまり kustomize で書いた「入れたいもの」を用意します。
ここでは練習用に、nginx という Deployment を 1 つだけ持つ最小構成にします。
my-cluster/kustomize/nginx/kustomization.yaml:
resources:
- deployment.yaml
my-cluster/kustomize/nginx/deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: default
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.27-alpine
ports:
- containerPort: 80
この時点で、Tazuna を使わなくても kubectl apply -k my-cluster/kustomize/nginx
で同じものをクラスタに入れることができます。Tazuna はあくまでこれを
宣言的に管理するための一段上の層 として乗せるだけ、と捉えておくと理解しやすくなります。
2. tazuna.yaml を書く
次に、Tazuna に対する「唯一の入力ファイル」である tazuna.yaml を書きます。
my-cluster/tazuna.yaml:
apiVersion: tazuna.pepabo.com/v1
kind: Tazuna
spec:
manifests:
- name: nginx
type: kustomize
path: ./kustomize/nginx
最初は次の 3 つを押さえれば動かせます。
name— この Manifest の識別子。State やログでこの名前が使われます。 半角英数字とハイフン・アンダースコアで付けます。type— Tazuna がどのバックエンドでこの Manifest を扱うか。 ここではkustomizeを指定します。helmfileやorasといった選択肢もあります (Manifest type 参照)。path— 実体のあるディレクトリ。tazuna.yaml自身の置かれているディレクトリ起点 の相対パスで書きます。
path の起点が「コマンドを実行した cwd」ではなく「tazuna.yaml 自身の場所」である点には注意してください。
リポジトリのどこから tazuna を呼び出しても結果が変わらないように、こちらに合わせています。
3. check で妥当性を確認する
ファイルを書き終えたら、まずクラスタには触れずに tazuna check で tazuna.yaml を検証します。
cd my-cluster
tazuna check
ok と出れば、次の検査をすべて通っています。
- YAML としてパースできる
nameが必須でユニーク、使える文字種に収まっているpathの指す場所が実際に存在する
ここで失敗するものは、すべて クラスタに触る前に 落とせます。 CI で最初に通す対象として組み込みやすいコマンドでもあります。
4. build でクラスタに触らず中身を見る
次に、tazuna build を使って「tazuna apply したら何が入るか」を、
クラスタには一切触れずに stdout に書き出します。
tazuna build
kustomize build 相当の Kubernetes manifest が出力されます。
今回の例では先ほど書いた Deployment/nginx がそのまま出てくるはずです。
build はクラスタへの接続を必要としません。
意図したものが本当に入ろうとしているか をレビューしたい場面や、
レンダリング結果を別のツールに食わせたい場面で使います。
5. apply でクラスタに反映する
ここまで来れば、本番作業はあと 1 コマンドです。
current-context が入れたいクラスタを指していることをもう一度確認してから、
tazuna apply を実行します。
kubectl config current-context # 入れたいクラスタを指していること
tazuna apply
Tazuna は次のことを順に行います。
tazuna.yamlをロードして検証するmanifests[]を宣言順に走査する- 各 Manifest を対応する Manager(ここでは kustomize Manager)に渡す
- kustomize Manager が
pathをレンダリングし、結果をクラスタに反映する - 反映した結果を State としてクラスタ内に記録する
State はクラスタ内 tazuna namespace の ConfigMap (tazuna-state-<manifest-name>)
に置かれます。tazuna namespace が無ければ自動的に作られるので、
事前に作っておく必要はありません。
反映されたことを確認する
普段どおり kubectl で見ても良いですし、Tazuna 側からも確認できます。
kubectl get deployment -n default nginx
tazuna state list
tazuna state list には、いま Tazuna が「自分が入れたもの」として記録している
リソースが一覧で出ます。今回のガイドでは Deployment/nginx 1 件が出ているはずです。
ここに出ているリソースは、後で tazuna destroy で安全に取り外せる対象でもあります。
よくある落とし穴
最初の 1 枚を書くときによく踏むものを並べておきます。
pathの起点を勘違いする —tazuna.yaml自身のディレクトリ起点です。cdした場所からの相対パスのつもりで書くと、CI とローカルで挙動が食い違う原因になります。- クラスタを取り違える —
kubectl config current-contextの確認を apply の直前に必ず入れる運用にします。context_matchesを導入すれば仕組みで防げますが、 まずは目視確認を習慣にします。 - kustomize 側のエラーを Tazuna のエラーだと思う —
tazuna buildが失敗するときは、 ほとんどの場合 kustomize 側のエラーがそのまま伝播してきています。kustomize build ./pathを直接実行して切り分けると速いです。 - 手で
kubectl applyしたものを混ぜる — 同じクラスタに対して Tazuna 経由と 手作業を混在させると、State と実体がずれていきます。混ぜる場合は、 あとからtazuna state diffで差分を見られることだけ覚えておきます。
次に進む
次のガイドでは、ここで作った tazuna.yaml に Manifest を増やし、
複数のアドオンを順序付きでクラスタに入れる ところを扱う予定です。
そこから先で --tags による絞り込み、includes による分割、context_matches による
誤クラスタ事故の防止といった話に段階的に踏み込んでいきます。
運用
このセクションは、Tazuna を 継続的に使う 局面の指針をまとめます。 タスク単位の手順(「新しい add-on を入れる」「tazuna.yaml を書く」など)は ガイド を、コマンドやスキーマの仕様は リファレンス を参照してください。
このセクションでは、事故を起こさない運用 と drift を発見できる運用 を中心に扱います。
一覧
tazuna destroyの運用 — 本番クラスタで destroy を打つときに踏むべき手順、TAZUNA_DESTROY_EXECUTABLEとcontext_matchesの二段ガード、事故が起きやすいシナリオ。- Drift モニタリング —
tazuna state diffを定期実行して drift を可視化する運用、出力フォーマットと 通知の組み立て方。 - CI パイプライン —
PR で
check/build、mainマージでapplyを回す典型構成、destroyの置き場、状態同期の選択。
tazuna destroy の運用
このページは、本番に近いクラスタで tazuna destroy を打つときの 手順と備えるべきガード をまとめます。
コマンドの仕様そのものは tazuna destroy リファレンス を参照してください。
なぜ runbook 化するか
destroy は Tazuna 管理下のリソースをクラスタから取り除く操作で、影響範囲が
クラスタ全体に及び得る 唯一の系統的な書き込みコマンドです。手で kubectl delete
していくのと違い、Tazuna が「自分の管理対象」と見なすものはまとめて消えます。
二段ガード(プロンプト + 環境変数)は仕組みとしての防御線ですが、運用側でも 「何が消えるかを事前に確認する」「context を取り違えない」 を組み立てておく必要があります。
前提として整える
destroy をクラスタに対して使う可能性があるなら、その tazuna.yaml には
spec.context_matches を入れておく ことを強く推奨します。
spec:
context_matches:
- ^prod-tokyo$
context_match_mode: or
manifests:
# ...
これがあると、destroy 時に current-context が prod-tokyo でなければ
クラスタには一切触れずに失敗します。手元の context 設定ミスに対する、もっとも安価な
保険です。詳細は tazuna.yaml - context_matches を参照。
標準フロー
以下の 1〜3 は tazuna destroy の内部処理ではなく、運用上の事前確認手順 です。
Tazuna 自身は state list を呼びませんが、destroy 前に手で打つことを強く推奨します。
# 1. current-context を確認(destroy 直前は必ず)
kubectl config current-context
kubectl get nodes
# 2. 何が消えるかを把握する(推奨)
tazuna state list
# 3. 必要なら範囲を絞る(実行時とまったく同じ --tags を付ける)
tazuna state list --tags experimental # 確認用
# 4. 本実行。プロンプトと環境変数の両方を満たして初めて削除が走る
TAZUNA_DESTROY_EXECUTABLE=true tazuna destroy --tags experimental
tazuna destroy 自体は次の順で動きます。
tazuna.yamlをロード・バリデーションする。context_matchesを評価する。不一致なら即終了。--forceが無ければ Y/N のプロンプトを出す。TAZUNA_DESTROY_EXECUTABLE=trueでなければ、ログだけ出して終了。- すべて満たしていれば、Manager の Destroy を順に呼び出す。
「プロンプトに Yes」と「環境変数 TAZUNA_DESTROY_EXECUTABLE=true」の 両方 が
揃わない限り、リソースは消えません。
範囲を絞る運用
クラスタ全体ではなく、特定のグループだけを取り外したい場合は --tags で絞り込みます。
TAZUNA_DESTROY_EXECUTABLE=true tazuna destroy --tags experimental
--tags は OR 評価です(tazuna.yaml - tags)。
廃止予定のものに lifecycle:deprecated のような専用タグを付けておき、その単位で削除する、
というパターンが扱いやすくなります。
tazuna destroy --tags <空> は全 Manifest が対象です。絞らない destroy を行うときは
事前に tazuna state list で全量を見ておき、想定外のリソースが入っていないことを確認してください。
事故が起きやすいシナリオ
実際にやりがちなパターンと、対応策の対応表です。
| シナリオ | どこで止まる / なぜ事故になるか | 推奨対応 |
|---|---|---|
| current-context を staging のつもりが production になっていた | context_matches を書いていれば 2 で停止する。書いていないと進む。 | 本番系の tazuna.yaml には必ず context_matches を入れる。プロンプトで止まれるよう --force は付けない。 |
CI に destroy を組み込み、誤って main で発火 | 環境変数を付けていないなら 4 で止まる。TAZUNA_DESTROY_EXECUTABLE=true を CI 全体に常設していると進んでしまう。 | CI には destroy を組み込まない。どうしても必要なら、専用の手動 workflow を作り、その job だけで一時的に環境変数を渡す。 |
--tags を付け忘れて全消ししてしまう | プロンプトと環境変数の両方を満たすと進む。 | 「絞りなしの destroy」を本番に近いクラスタで打たない運用にする。打つときは事前 state list を必ず通す。 |
手作業で kubectl apply したものは destroy で消えない | State に無いリソースは Tazuna 管理対象外として扱われ、destroy の対象にならない。 | 状態が乖離していると判断したら、tazuna state diff で乖離を見える化した上で対応を決める。 |
destroy の代わりに使える緩い手段
リソースを「いま完全に消す」必要がない場合、次の選択肢があることを覚えておきます。
tazuna state sync+TAZUNA_STATE_SYNC_DELETE=true—tazuna.yamlから Manifest を消したうえでstate syncを打つと、removed分類で 削除されます(tazuna state sync)。tazuna.yamlのソースの真実を変えずに reset したいときには使えません。--tagsで絞った destroy — 上記参照。
関連
- コマンド仕様:
tazuna destroy - 評価される
context_matches:tazuna.yaml - 削除前の確認:
tazuna state list
Drift モニタリング
このページは、tazuna state diff を 定期的に回して drift を可視化する運用 の作り方をまとめます。
コマンドの仕様は tazuna state diff を、
State の中身の仕様は State の内部構造 を参照してください。
何を drift と呼ぶか
ここでの drift は、tazuna.yaml から生成されるべきリソース集合(Build 結果)と、
クラスタ内 State に記録されているリソース集合の差です。
これは tazuna state diff の出力そのものに当たります。
| Diff type | 検出されるケース | drift の典型例 |
|---|---|---|
added | Build 結果に存在し、State に無い | tazuna.yaml を更新して Manifest を増やしたが、まだ反映していない |
modified | 両方に存在するが内容が違う | Helm values 変更、kustomize overlay 変更、image tag 更新の未反映 |
removed | State にあって Build 結果に無い | Manifest を tazuna.yaml から外したが、リソースはクラスタに残っている |
always-sync | 常に同期扱い | GenesisSecret 由来 Secret。drift ではなく「毎回チェックする箇所」 |
tazuna state diff は クラスタの実体までは見ていません。
クラスタに対して手で kubectl apply した結果(State には無いリソース)は
ここでは検出されません。Tazuna の管理対象外として無視されます。
出力フォーマット
tazuna state diff は Manifest 単位で次のような出力を出します。
Manifest: ingress-nginx
STATUS RESOURCE HASH
modified ingress-nginx/apps/v1/Deployment/ingress-nginx/controller abc123... -> def456...
Manifest: aws-credentials
STATUS RESOURCE HASH
always-sync aws-credentials//v1/Secret/default/aws-credentials xyz789...
差分が無い場合は次の 1 行だけが出ます。
No changes detected.
「drift なし」の判定は この 1 行で判断するのが現状もっとも素朴 です
(出力に No changes detected. を含むかどうかでフィルタする)。
tazuna state diff 自体は差分の有無で終了コードは変えません。
差分があってもエラーにはならない、という点に注意してください。
監視のかたち
実運用での「drift モニタリング」は次のいずれか(または組み合わせ)になります。
a. CI ジョブを定期実行する
GitHub Actions の schedule で 1 日に数回 tazuna state diff を回し、出力を保存します。
- メリット: 既存の CI 認証を再利用できる。差分が出たら Slack 等に投げやすい。
- デメリット: クラスタ接続情報を CI に持ち込む必要がある。短い周期には向かない。
ポイント:
- ジョブには クラスタへの read 権限だけ あれば足ります(
tazuna state diffは クラスタを変更しません)。 - 出力を
tazuna state diff -f path/to/tazuna.yaml > diff.txtのようにファイルに落とし、No changes detected.を含まない場合だけ通知を投げると、無風時のノイズが消えます。
b. クラスタ内 Job として走らせる
tazuna バイナリを含むコンテナイメージを用意し、CronJob として定期実行する方法です。
- メリット: 認証は ServiceAccount に閉じる。短い周期にしやすい。
- デメリット: イメージのビルド・配布が必要。CI と同じ
tazuna.yamlリポジトリへの アクセスを Job 側にも持たせる必要がある。
type: oras を使って tazuna.yaml 一式を OCI artifact として配布しておくと、Job 側で
リポジトリの clone を持たずに済みます(tazuna apply --offline
と組み合わせると registry も不要になります)。
通知の組み立て
通知側で読みたい情報は次の 3 つです。
- どの Manifest に差分があるか
- どの Diff type か(特に
removedは注意) - どの リソース か(State key の形式で)
State key の形式は manifest/group/version/kind/namespace/name(cluster-scoped は
namespace 抜き)で固定なので、grep ベースの後段処理に十分なります。
詳細は State の内部構造 - State key を参照してください。
通知の最小プロトタイプ:
if ! tazuna state diff -f tazuna.yaml | tee diff.txt | grep -q "No changes detected."; then
curl -X POST "$SLACK_WEBHOOK_URL" --data "$(jq -Rs '{text: .}' < diff.txt)"
fi
jq -Rs '{text: .}' は、diff.txt の中身を 生文字列のまま Slack の Incoming Webhook が
期待する {"text": "..."} 形式 JSON に包み直すための定型です(-R で raw 入力、-s で
全行を 1 つの文字列にスラープ)。
検知後の対応
drift が出たときの選択肢は次のいずれかです。
- 意図した変更だった:
tazuna apply(またはtazuna state sync)で State をクラスタに追従させる。 - 意図しない変更だった:
modified: 誰がいつ変えたかを git log / クラスタの監査ログ等で追い、 変更を巻き戻すかtazuna.yaml側に取り込むかを判断する。added:tazuna.yaml側に Manifest を増やしたが反映していない、というケースが多い。 意図に合わせて apply するか、tazuna.yaml側を元に戻す。removed: Tazuna から Manifest を外したが、リソースはクラスタに残っている。tazuna destroyの--tags絞り込みや、tazuna state sync+TAZUNA_STATE_SYNC_DELETE=trueで片付ける。
- GenesisSecret の
always-sync: drift ではないので通知から除外して構いません。
関連
- コマンド仕様:
tazuna state diff/tazuna state sync - State の内部構造: State の内部構造
- 用語: Diff type / always-sync
CI パイプライン
このページは、tazuna.yaml を持つリポジトリで CI / CD パイプラインに Tazuna を組み込む
ときの典型構成をまとめます。Tazuna は手元で apply するためにも、CI から
apply するためにも使えます。ここでは後者の組み立て方を中心に扱います。
典型構成
役割を分けると次の 3 ステージになります。
| ステージ | 目的 | 走らせるコマンド | クラスタアクセス |
|---|---|---|---|
| 検証 | tazuna.yaml が壊れていないことの保証 | tazuna check、tazuna build | なし |
| 反映 | main の内容をクラスタに反映する | tazuna apply(または tazuna state sync) | あり |
| 取り外し | Tazuna 管理リソースを削除する | tazuna destroy | あり |
「検証」は全 PR で走らせて構いません。「反映」は通常 main への push をトリガにします。
「取り外し」は CI に常設しない ことを推奨します(tazuna destroy の運用 参照)。
検証ステージ
tazuna.yaml を CI に乗せる場合、最低限の通過条件として tazuna check を入れます。
クラスタに触れずに走るので、PR でのコストはほぼゼロです。
# GitHub Actions の例(要点だけ)
- name: tazuna check
run: tazuna check -f tazuna.yaml
- name: tazuna build (preview)
run: tazuna build -f tazuna.yaml > rendered.yaml
PR で build 結果をアーティファクトに残しておくと、レビュー時に「最終的に何が apply されるか」を
レンダリング結果ベースで確認できます。type: oras を使っているなら --offline を
付けて先取り cache を使う構成も検討できます(tazuna build)。
反映ステージ
main への push をトリガに tazuna apply を走らせる構成が基本です。
on:
push:
branches: ["main"]
jobs:
apply:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write # OIDC でクラスタに繋ぐ場合
steps:
- uses: actions/checkout@v6
- name: install tazuna
run: |
curl -L https://github.com/pepabo/tazuna/releases/download/v0.1.0/tazuna_Linux_x86_64.tar.gz \
| tar xz -C /usr/local/bin tazuna
- name: configure kubeconfig
run: |
# クラスタ側の都合に応じて、aws-iam-authenticator / gke-gcloud-auth-plugin
# / kubeconfig secret 等で current-context を設定する
aws eks update-kubeconfig --name prod-tokyo --region ap-northeast-1
- name: tazuna apply
run: tazuna apply -f tazuna.yaml
ポイント:
tazuna applyの current-context は kubeconfig の current-context そのものです。 CI で current-context を切り替えるステップを必ず明示します。tazuna.yamlにspec.context_matchesを 入れておけば、誤って違うクラスタを向いた kubeconfig で apply しようとしても 即終了します。CI でも有効な保険になります。- Tazuna は失敗時に非ゼロ終了するので、CI 側で特別なエラーハンドリングは不要です (CLI - 終了コード)。
apply か state sync か
CI で回すコマンドには 2 通りあります。
| コマンド | いつ何が走るか | drift 検知 |
|---|---|---|
tazuna apply | tazuna.yaml で宣言された Manifest を 全部 Manager に通す | しない(毎回上書き) |
tazuna state sync | Build 結果と State を比較し、差分(added / modified / always-sync)だけ反映 | する |
おおまかな指針:
- ブートストラップ初期 / Manifest 数が少ない:
tazuna applyが単純で予測しやすい。 - Manifest 数が増えて 1 回の
applyが重くなった:tazuna state syncで差分のみに絞る。 removedの自動削除が欲しい:state sync+TAZUNA_STATE_SYNC_DELETE=true。誤削除のリスクと相談。
--atomic を使うか
tazuna state sync --atomic を付けると、いずれかのリソースでエラーが出たときに
State を更新せず終了します。反映自体は途中まで進む ため、CI で「全部入ったか
何も入らなかったか」の二値にはなりませんが、State 上の整合性は守れます。
詳細は tazuna state sync を参照。
取り外しステージ
CI から tazuna destroy を回す運用は推奨しません。
- 環境変数
TAZUNA_DESTROY_EXECUTABLE=trueを CI に常設すると、誤発火時のガードが プロンプトしか残らなくなる(しかも CI ではプロンプトに答えられないので、--forceと組み合わさると無条件で消えます)。 - どうしても CI から消す必要がある場合は、手動トリガの専用 workflow を作り、 その job に限って環境変数を渡す構成にします。
詳細は tazuna destroy の運用 を参照してください。
Tag を使った段階的反映
tazuna apply --tags で、CI で反映する Manifest を絞り込めます。
たとえば「インフラレイヤと application レイヤを分けて回す」「実験 add-on を独立した job
で回す」といった段階的反映に向きます。
tazuna apply --tags infra # 先に基盤を入れる
tazuna apply --tags application # 次にアプリ側
タグの設計は tazuna.yaml 側の manifests[].tags で
行います。
監視・通知との接続
CI とは別系で、tazuna state diff の定期実行を回しておくのが推奨構成です。
詳細は Drift モニタリング を参照してください。
CI で apply の成否を見るだけだと、「tazuna.yaml の更新が無いのに drift が起きている」
ケースを取り逃がします。
関連
- 仕様:
tazuna apply/tazuna build/tazuna check/tazuna state sync - 事故防止:
tazuna destroyの運用 - drift 検知: Drift モニタリング
リファレンス
このセクションは、Tazuna が受け付ける入力ファイルや CLI、内部データ構造の仕様を、 規約書として参照しやすい形でまとめます。
「なぜそうなっているか」は 概念、 「どう使うか」の手順は ガイド を参照してください。 リファレンスは事実の列挙に徹し、フィールド・型・デフォルト・例を中心に書きます。
一覧
現在掲載しているリファレンスは次のとおりです。 ここから順次、Manifest type 別の詳細や CLI、Test plugin、State の内部構造などを拡充していきます。
tazuna.yamlスキーマ — Tazuna への唯一の入力ファイルであるtazuna.yamlのトップレベル構造と、spec.manifests[]/spec.context_matches/includesなどの共通フィールドの仕様。tazuna.hint.yamlスキーマ — helmfile Manifest のvarsに対する制約を宣言するヒントファイルのスキーマ。 型・必須・条件付き必須・フォーマット検証ルールと、oneof_requiredなどのトップレベルルール。- GenesisSecret スキーマ —
外部 Secret ストア(1Password)から Kubernetes Secret を生成するための YAML スキーマ。
type: genesissecretの Manifest としてtazuna.yamlから参照されます。 - Test plugin —
manifests[].testsおよびspec.testsに書くTestPluginSpecの共通フィールドと、 組み込みプラグインWaitUntil/ExistNonExistの仕様。 - State の内部構造 —
State の保存先(
tazunanamespace の ConfigMap)、State key の文字列形式、 ContentHash の計算ルール、Diff type の分類仕様。 - Manifest type 別 —
kustomize/helmfile/oras/parallel/genesissecretの 5 type について、pathの意味・固有フィールド・apply / destroy / build 時の振る舞いを 1 ページずつ。 - CLI —
tazunaバイナリのサブコマンド・グローバルフラグ・環境変数の仕様。 各サブコマンドは 1 ページずつに分けて、フラグと振る舞いをまとめています。
読み方の約束
- フィールド名は YAML での表記(小文字キャメル or スネーク)で示します。
- 必須 と注記のないフィールドはすべて optional です。
- 「デフォルト」は値を省略したときに Tazuna が採用する値を示します。
ゼロ値(空文字 / 空スライス /
false/0)はとくに注記しない限りそのまま採用されます。 - 例示する YAML は最小構成で書きます。 実運用で必要になる追加フィールドは各セクションで個別に説明します。
tazuna.yaml スキーマ
このページは Tazuna への唯一の入力ファイルである tazuna.yaml の仕様をまとめます。
ここでは Manifest type 別の固有フィールド(kustomize / helmfile /
genesissecret / parallel / oras)と Test plugin のフィールドには深入りしません。
それらは順次、専用のリファレンスページで扱います。
ルート (Tazuna)
tazuna.yaml のルートオブジェクトです。Kubernetes manifest と同じ
apiVersion / kind / spec の 3 つを持ちます。
| フィールド | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
apiVersion | string | - | - | 設定する場合は tazuna.pepabo.com/v1 と完全一致である必要があります。省略可。 |
kind | string | - | - | 設定する場合は Tazuna と完全一致である必要があります。省略可。 |
spec | TazunaSpec | ◯ | - | Tazuna の振る舞いを定義する本体。 |
最小例:
apiVersion: tazuna.pepabo.com/v1
kind: Tazuna
spec:
manifests:
- name: nginx
type: kustomize
path: ./kustomize/nginx
TazunaSpec
| フィールド | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
manifests | [Manifest] | ◯ | - | Tazuna が順に処理する Manifest の配列。空配列は許容されません。 |
context_matches | [string] | - | [] | 現在の kubeconfig context 名がマッチすべき正規表現の配列。空でなければ apply / destroy 前に評価されます。 |
context_match_mode | string | - | or | context_matches の評価モード。or(いずれかに一致)または and(すべてに一致)。 |
tests | [TestPluginSpec] | - | [] | すべての Manifest 適用後に実行される Test plugin の配列。 |
context_matches
- 各要素は Go の
regexpパッケージでコンパイル可能な正規表現でなければなりません。 コンパイルに失敗するとtazuna checkの段階で弾かれます。 - 空配列または未設定の場合、context のチェックは行われません。
- 設定されている場合、
tazuna apply/tazuna destroyはクラスタに触る前に current-context を検証します。マッチしないと処理を中断します。
context_match_mode
or(デフォルト):context_matchesのいずれか 1 つにでもマッチすれば OK。and:context_matchesの すべて にマッチする必要があります。- それ以外の値を指定するとバリデーションエラーになります。
例:
spec:
context_matches:
- ^staging-
- -tokyo$
context_match_mode: and
manifests: []
Manifest
spec.manifests[] の各要素です。1 つの Manifest が、1 つのバックエンド
(kustomize / helmfile / 他)による「クラスタへ入れる単位」に対応します。
| フィールド | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
name | string | ◯ | - | Manifest 識別子。^[a-zA-Z0-9_-]+$ にマッチする必要があり、includes 展開後の全 Manifest 間でユニーク。_metadata は予約済みで使用不可。 |
description | string | - | "" | 人間向けの説明。挙動には影響しません。 |
type | string | △ (※) | - | kustomize / helmfile / genesissecret / parallel / oras のいずれか。 |
path | string | △ (※) | - | tazuna.yaml 自身の置かれているディレクトリ起点の相対パス。 |
tags | [string] | - | [] | tazuna apply --tags ... などで絞り込みに使うタグ。OR 評価。 |
includes | [IncludeFile] | - | [] | 別の tazuna.yaml を読み込むエントリ。設定時は他の Manifest 固有フィールドは無視されます。詳細は includes を使う を参照。 |
kustomize | ManifestKustomize | - | null | type: kustomize のときに参照されるオプション。 |
helmfile | ManifestHelmfile | - | null | type: helmfile のときに参照されるオプション。 |
genesisSecret | object | - | null | type: genesissecret のときに参照されるオプション。現状は空オブジェクト。 |
parallel | ManifestParallel | - | null | type: parallel のときに参照されるオプション。children[] に Manifest を入れ子で書く。 |
oras | ManifestORAS | - | null | type: oras のときに参照されるオプション。 |
tests | [TestPluginSpec] | - | [] | この Manifest の apply 後に実行される Test plugin の配列。 |
(※) includes を指定するときは type / path は不要。
それ以外のときは type と path が必須です。
name
- 必須。
- 使える文字種は
^[a-zA-Z0-9_-]+$。 _metadataは内部利用のため予約されており、Manifest 名としては使えません。includes展開後の全 Manifest 間で 一意 である必要があります。 重複しているとtazuna checkでエラーになります。
tazuna check では name のバリデーションは エラー として扱いますが、tazuna apply
/ build / destroy では移行期間として 警告ログのみ が出る挙動になっています。
新規導入時は tazuna check で先に通しておくのが安全です。
path
includesを使わないときは必須。tazuna.yaml自身の置かれているディレクトリ起点 の相対パスとして解釈されます。 コマンドを実行した cwd 起点ではありません。tazuna checkの時点で実在チェックが行われます。- type ごとに
pathが指すべき先が異なります。
type | path が指す先 |
|---|---|
kustomize | kustomization.yaml を含むディレクトリ |
helmfile | helmfile.yaml を含むディレクトリ |
genesissecret | GenesisSecret 定義 YAML ファイル(ディレクトリではない) |
parallel | 実体としては使用されません。children[] 側の path が使われます。バリデーション都合で空にはできません。 |
oras | 実体としては使用されません。バリデーション都合で空にはできないため、適当なディレクトリを書きます。 |
詳細な解釈は各 Manifest type 別ページ を参照してください。
type
includesを使わないときは必須。- 値の一覧は Manifest type を参照。
- 未対応の値を指定するとバリデーションエラーになります。
tags
- 文字列の配列。Tazuna 自身は内容を解釈しません。
--tagsフラグでの絞り込み時に、指定されたタグのいずれかが付いている Manifest だけが処理対象になります(OR 評価)。
IncludeFile
manifests[].includes[] の各要素です。別の tazuna.yaml を読み込み、その manifests[]
を展開します。
| フィールド | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
path | string | ◯ | - | 読み込む tazuna.yaml のパス。呼び出し元の tazuna.yaml からの相対 で書きます。 |
includes を使う
spec:
manifests:
- name: infra
includes:
- path: ./infra/tazuna.yaml
- path: ./addons/tazuna.yaml
includesを持つ Manifest は、自身が持つtype/path/tagsなどの 「Manifest 本体」のフィールドは 無視 されます。includesは ネスト不可 です。include 先のtazuna.yamlが さらにincludesを持っていても展開されません。- include 先で定義された Manifest の
nameも含めて、最終的な全 Manifest 間でnameがユニークである必要があります。
Manifest type 別フィールド
type に対応するフィールド(kustomize / helmfile / genesisSecret /
parallel / oras)は、それぞれ専用のリファレンスページに切り出しています。
ここでは存在と最低限の役割だけを示します。
| フィールド | 役割 |
|---|---|
kustomize | type: kustomize 向けオプション。defaultNamespace を持つ。 |
helmfile | type: helmfile 向けオプション。vars / includeCRDs / wait / kubeVersion などを持つ。 |
genesisSecret | type: genesissecret 向けの拡張点。現バージョンでは空オブジェクト。 |
parallel | type: parallel 向けオプション。children[] に Manifest を入れる。 |
oras | type: oras 向けオプション。reference / delegate を持つ。 |
tests フィールド
spec.tests および manifests[].tests の要素である TestPluginSpec の詳細仕様は
Test plugin を参照してください。
ここでは置かれる位置と実行タイミングだけを示します。
- 全体
tests(spec.tests): すべての Manifest 適用が終わったあとに実行されます。 - 個別
tests(manifests[].tests): その Manifest の適用直後に実行されます。
バリデーションのまとめ
tazuna check が tazuna.yaml に対して行う検証を一覧にしておきます。
クラスタには触れず、ここで失敗するものはすべて事前に弾けます。
apiVersion/kindを設定するなら値が正規値と完全一致すること。spec.manifests[]の各要素について:includesが無い場合:pathとtypeが設定されていること。typeが既知の値(kustomize/helmfile/genesissecret/parallel/oras)であること。pathの指す場所が実在すること。
spec.manifests[].nameが必須・使用可能文字・ユニーク・予約語禁止を満たすこと。spec.context_matchesが正規表現としてコンパイル可能であること。spec.context_match_modeがor/and/ 未設定のいずれかであること。type: helmfileの場合:helmfile.varsの各値がenv/static/opの いずれかを満たすこと(詳細は helmfile のリファレンスページ)。type: parallelの場合:parallel.children[]が空でなく、各 child も妥当な Manifest であること。type: orasの場合:oras.referenceが必須、oras.delegate.typeがhelmfile/kustomizeのいずれかであること。includesを指定する場合: 各include.pathが必須で、ファイルが実在すること。
tazuna.hint.yaml スキーマ
tazuna.hint.yaml は、type: helmfile の Manifest で使う vars に対して
「どんな値が取りうるか」「どれが必須か」 を宣言的に縛るためのヒントファイルです。
helmfile Manifest と同じディレクトリに置き、Tazuna が vars を解決する過程で参照します。
tazuna.yaml 本体のスキーマは tazuna.yaml スキーマ を参照してください。
置く場所と読み込み
Tazuna は helmfile Manifest の path ディレクトリ直下 から tazuna.hint.yaml を探します。
- ファイル名は
tazuna.hint.yaml固定。 - 存在しなければそのまま無視されます(後方互換のため、エラーにはなりません)。
- 1 つの helmfile Manifest につき高々 1 つです。
helmfile 以外の Manifest type からは読まれません。
ルート (TazunaHint)
| フィールド | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
apiVersion | string | - | - | スキーマバージョンを示します。値は現状検証されません。 |
kind | string | - | - | リソース種別を示します。値は現状検証されません。 |
vars | map<string, HintVar> | ◯ | - | varName をキーとする宣言の集合。 |
rules | [HintRule] | - | [] | var 横断のトップレベルバリデーションルール。 |
apiVersion / kind は 値の検証は行われません が、慣習として
apiVersion: tazuna.pepabo.com/v1 / kind: TazunaHint を書いておくと、
後で検証が入った場合にも揃えやすくなります。
最小例:
apiVersion: tazuna.pepabo.com/v1
kind: TazunaHint
vars:
clusterName:
type: string
required: true
replicas:
type: string
default: "3"
HintVar
vars の各エントリ(var 1 つ分の宣言)です。
| フィールド | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
type | string | ◯ | - | var の型。string / slice / map のいずれか。 |
required | bool | - | false | ユーザーから必ず提供されなければならないかどうか。 |
default | any | - | null | 未提供時に注入する値。required: true との併用不可。 |
description | string | - | "" | 人間向けの説明。挙動には影響しません。 |
format | string | - | "" | 値のフォーマット検証ルール。type: string のときだけ指定可能。詳細は format 参照。 |
required_with | [string] | - | [] | 「ここで挙げた var のいずれかが提供されているとき、この var も必須」を意味する条件付き必須。required: true との併用不可。参照先は vars に存在しなければなりません。 |
required_without | [string] | - | [] | 「ここで挙げた var が すべて 未提供のとき、この var が必須」を意味する条件付き必須。required: true との併用不可。参照先は vars に存在しなければなりません。 |
値が未提供のときの振る舞い
helmfile Manifest 側の vars 解決後、各 var に対して次の順で処理されます。
- すでに値が提供されていれば、そのまま採用する。
- 提供されておらず
required: trueならエラー。 defaultがあればその値を注入する。- それ以外は 型ごとのゼロ値 を注入する(
string→""、slice→[]、map→{})。
条件付き必須(required_with / required_without)の判定は、上記のゼロ値注入の結果ではなく、
ユーザーから明示的に提供された値の集合 に対して行われます。
ゼロ値が入った var が「提供済み」と誤判定されないようにするための実装です。
format
format は type: string の var に対する文字列フォーマット検証です。
値が空文字列(ゼロ値注入を含む)の場合は検証はスキップ されます。
非空文字列が入っているときだけ検証が走ります。
| 値 | 検証 |
|---|---|
hostname | RFC 952 / 1123 に準拠したホスト名パターン(英数字 / - / .、各ラベルは英数字で開始・終了) |
url | net/url.ParseRequestURI で解釈でき、かつ scheme が空でないこと |
email | 簡易的な user@domain.tld 形式(簡易正規表現) |
ip | net.ParseIP で解釈できる IPv4 / IPv6 アドレス |
cidr | net.ParseCIDR で解釈できる CIDR 表記 |
uuid | RFC 4122 形式(ハイフン区切り) |
semver | セマンティックバージョン。v 接頭辞はオプション。pre-release / build metadata まで対応 |
datetime | time.RFC3339 形式の日時文字列 |
ここに無い値を指定するとバリデーションエラーになります。
HintRule
rules は var 横断のバリデーションを宣言するためのトップレベルルールです。
個別 var の処理が一通り終わったあとに評価されます。
| フィールド | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
type | string | ◯ | - | ルール種別。現状は oneof_required のみ。 |
vars | [string] | ◯ | - | ルールが対象とする var 名の配列。2 件以上 が必要。参照先は vars に存在しなければなりません。 |
message | string | - | "" | バリデーションエラー時に表示するカスタムメッセージ。 |
oneof_required
vars に挙げた var のうち、少なくとも 1 つがユーザーから提供されていなければエラー、というルールです。
rules:
- type: oneof_required
vars:
- certManagerIssuerName
- certManagerClusterIssuerName
message: "either certManagerIssuerName or certManagerClusterIssuerName must be set"
判定基準は条件付き必須と同じく、ゼロ値注入前の ユーザー提供 の値の集合です。
default で値が入った var は「提供された」とは扱われません。
バリデーション
tazuna.hint.yaml がロードされると、まずスキーマレベルで次の検証が行われます。
vars[*].typeがstring/slice/mapのいずれかであること。vars[*].required: trueとvars[*].defaultを併用していないこと。vars[*].formatを指定しているときにtype: stringであること。vars[*].formatが既知の値であること(format 参照)。vars[*].required_with/vars[*].required_withoutの参照先がvarsに存在すること。vars[*].required: trueとrequired_with/required_withoutを併用していないこと。rules[*].typeが既知の値であること(現状はoneof_requiredのみ)。rules[*].varsの長さが 2 以上であること。rules[*].varsの参照先がvarsに存在すること。
それらを通過したのち、helmfile Manifest の vars 解決結果に対して
次の検証が走ります(値が未提供のときの振る舞い と
format を参照)。
- hint で宣言された型と、helmfile 側に渡された値の型が整合すること
(例:
type: sliceと宣言した var にstaticMapが来たらエラー)。 required: trueの var に値が来ていること。required_with/required_withoutの条件を満たしていること。formatを持つ string var の値が、空文字列でない場合に format パターンを満たしていること。rulesを満たしていること(oneof_requiredの少なくとも 1 つが提供されていること)。
関連
- 用語:
tazuna.hint.yaml - helmfile Manifest の
vars側のスキーマ:tazuna.yamlの Manifest type 別フィールド
GenesisSecret スキーマ
GenesisSecret は、外部の Secret ストア(現バージョンでは 1Password)にある秘匿情報を取得し、 Kubernetes Secret として 生成 するための宣言です。
GenesisSecret は Kubernetes の CRD ではなく、Tazuna が読む YAML スキーマ です。
クラスタに GenesisSecret リソースが現れるわけではなく、適用結果として Secret が現れます。
tazuna.yaml からは type: genesissecret の Manifest として参照します。
# tazuna.yaml
spec:
manifests:
- name: aws-credentials
type: genesissecret
path: ./genesissecrets/aws.yaml
type: genesissecret の path は YAML ファイル 1 つを直接指します
(他の Manifest type のようにディレクトリを指すのではありません)。
ルート (GenesisSecret)
| フィールド | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
apiVersion | string | - | - | スキーマバージョンを示します。値は現状検証されません。 |
kind | string | - | - | リソース種別を示します。値は現状検証されません。 |
spec | GenesisSecretSpec | ◯ | - | GenesisSecret 本体。 |
apiVersion / kind のフィールドは構造体に対応する宣言がなく、書いても
読まれずに無視されますが、慣習として apiVersion: tazuna.pepabo.com/v1 /
kind: GenesisSecret を書いておくと、後から検証が入っても揃えやすくなります。
GenesisSecretSpec
| フィールド | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
provider | string | - | "" | 取得元 Provider の指定。現バージョンの Manager は値を参照していません。 Provider は Tazuna 全体で 1 つ(1Password 向け実装)が組み込まれていて、tazuna apply の起動時に決定されます。 |
secrets | [GenesisSecretGenerate] | ◯ | - | 取得対象。複数書けます。 |
outputs | [GenesisSecretOutput] | ◯ | - | 出力先。複数書けます。 |
GenesisSecretGenerate
secrets[] の各要素です。1 つの「Provider 上のアイテム」を表します。
| フィールド | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
uri | string | ◯ | - | Provider 上のアイテムを指す URI。詳細は uri の形式 参照。 |
items | map<string, GenesisSecretGenerateItem> | ◯ | - | Provider から取得した key と、出力 Secret 上のキー名の対応表。 |
preferLabel | bool | - | false | Provider が返したフィールドを ラベル名 でキー化するかどうか。false のときは ID(ランダム文字列になる場合がある)でキー化されます。1Password で人間が付けたフィールド名を items のキーに書きたい場合は true にします。 |
uri の形式
1Password Provider では、url.Parse の結果のうち path の 1 つ目を vault 名、2 つ目を item 名
として解釈します。scheme やホストは現バージョンでは使われません。
tazuna secret-to-genesissecret が自動生成するときは次の形式で書き出します。
op://<op-host>/<vault>/<item>
例:
uri: op://example.1password.com/Platform/aws-credentials
scheme やホストはパースには通りますが、参照されません。 将来別 Provider を増やしたときに使い分けるためのスペースとして残されている、と理解しておくと安全です。
GenesisSecretGenerateItem
items マップの 値 にあたる構造です(キーは Provider から返ってきた field の ID または label)。
| フィールド | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
mapTo | string | ◯ | - | 出力先 Kubernetes Secret の data キー名。Provider から取得した値はこのキー名で Secret に格納されます。 |
例:
items:
accessKeyID:
mapTo: AWS_ACCESS_KEY_ID
secretAccessKey:
mapTo: AWS_SECRET_ACCESS_KEY
items のキー accessKeyID が Provider 上のフィールド名(preferLabel: true ならラベル名)に対応し、
mapTo がそのまま Kubernetes Secret のキー名になります。
items のキーが Provider 側に存在しないとエラーになります。
GenesisSecretOutput
outputs[] の各要素です。1 つの「出力先」を表します。
| フィールド | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
kubernetesSecret | GenesisSecretOutputKubernetesSecret | △ (※) | null | 出力先として Kubernetes Secret を作る場合に指定します。 |
stdout | object | - | null | スキーマ上は存在しますが 現バージョンでは未対応 です。kubernetesSecret が null の場合は実行時にエラーになります。 |
(※) 現バージョンでは outputs[] の各要素は kubernetesSecret を必須 とします。
構造体上は stdout も存在しますが、kubernetesSecret == nil だと
.spec.output currently supports only KubernetesSecret というエラーで失敗します。
GenesisSecretOutputKubernetesSecret
| フィールド | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
namespace | string | ◯ | - | 出力する Secret の namespace。 |
name | string | ◯ | - | 出力する Secret の name。 |
labels | map<string, string> | - | null | 出力する Secret に付ける labels。 |
annotations | map<string, string> | - | null | 出力する Secret に付ける annotations。 |
type | string | - | Opaque | corev1 の SecretType。空文字列のときは Opaque(厳密には kubernetes.io/opaque ではなく Kubernetes のデフォルト Opaque)として扱われます。kubernetes.io/tls などを指定できます。 |
context | string | - | "" | 構造体上は存在しますが、現バージョンの Manager 実装では参照されません。 出力先クラスタは Tazuna 全体の current-context が使われます。 |
解決の流れ
tazuna apply 時、type: genesissecret の Manifest は次のように処理されます。
manifests[].pathの指す YAML ファイル(tazuna.yaml自身のディレクトリ起点)を読む。spec.secrets[]の各要素を Provider に渡し、フィールド集合を取得する。itemsのmapToでキー名をリネームしながら、すべてのsecrets[]の結果を 1 つのmap[string]stringにマージする(同じキーが衝突した場合は 後勝ち)。spec.outputs[]の各kubernetesSecretについて、namespace/nameを持つ KubernetesSecretをCreateOrUpdateする。StringDataにマージ済みの map がそのまま入る。labels/annotations/typeは宣言どおりに付与される。
tazuna destroy 時も同じ Provider 取得が走り、outputs[].kubernetesSecret の
namespace / name で示される Secret を削除します。
tazuna build 時は、出力対象が outputs[0].kubernetesSecret 1 件分の Secret YAML として
標準出力に書き出されます(複数 outputs を書いていても、build では先頭 1 件のみが対象)。
State と always-sync
GenesisSecret から生成される Secret は、tazuna state diff 上で常に
always-sync 分類になります。
ContentHash で差分判定できる対象ではなく、Provider 側を真実の源として
毎回同期する扱いです。詳細は Diff type /
always-sync を参照してください。
例
最小例:
apiVersion: tazuna.pepabo.com/v1
kind: GenesisSecret
spec:
secrets:
- uri: op://example.1password.com/Platform/aws-credentials
preferLabel: true
items:
accessKeyID:
mapTo: AWS_ACCESS_KEY_ID
secretAccessKey:
mapTo: AWS_SECRET_ACCESS_KEY
outputs:
- kubernetesSecret:
namespace: default
name: aws-credentials
type: kubernetes.io/tls を出力する例:
apiVersion: tazuna.pepabo.com/v1
kind: GenesisSecret
spec:
secrets:
- uri: op://example.1password.com/Platform/tls-wildcard
preferLabel: true
items:
certificate:
mapTo: tls.crt
privateKey:
mapTo: tls.key
outputs:
- kubernetesSecret:
namespace: ingress-nginx
name: wildcard-tls
type: kubernetes.io/tls
labels:
managed-by: tazuna
関連
tazuna.yaml側からの参照:tazuna.yamlManifest type 別フィールド- Provider の語彙: Provider (SecretProvider)
- 既存 Secret を 1Password と GenesisSecret に書き出す:
tazuna secret-to-genesissecret - 用語: GenesisSecret
Test plugin
Test plugin は、Manifest の適用前後にクラスタの状態を検証するための仕組みです。
tazuna.yaml に書き、tazuna apply のフローに組み込まれます。
このページでは Test plugin の YAML スキーマと、組み込みの 2 種(WaitUntil / ExistNonExist)
の仕様をまとめます。
配置と実行タイミング
Test plugin は tazuna.yaml の 2 箇所に書けます。
| 配置箇所 | 実行タイミング |
|---|---|
manifests[].tests | その Manifest を apply した 直後 に実行 |
spec.tests | すべての Manifest の apply が終わったあと に実行 |
tazuna build / tazuna check / tazuna state diff などクラスタを変更しない
コマンドでは Test plugin は実行されません。tazuna destroy 時にも実行されません。
TestPluginSpec(共通フィールド)
manifests[].tests と spec.tests の各要素は同じ構造 TestPluginSpec を取ります。
| フィールド | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
type | string | ◯ | - | プラグイン種別。WaitUntil または ExistNonExist(大文字小文字をそのまま)。 |
waitUntil | WaitUntilArgs | △ (※) | null | type: WaitUntil のときに必須。 |
existNonExist | ExistNonExistArgs | △ (※) | null | type: ExistNonExist のときに必須。 |
minConsecutiveSuccessCount | int | - | 1 | テスト関数が連続でこの回数だけ成功したら、テストプラグイン全体を 成功 とする。0 を指定したときも内部で 1 に補正されます。 |
minConsecutiveFailureCount | int | - | 0 | テスト関数が連続でこの回数だけ失敗したら、テストプラグイン全体を 失敗 として打ち切る。0 のときはこのチェックは行われず、timeoutSeconds のみが打ち切り条件になります。 |
timeoutSeconds | int | - | 実質無限 | 全体タイムアウト秒。指定時間を超えると失敗。0(未指定)のときは実質無期限(内部で約 280 日が設定されます)。 |
intervalSeconds | int | - | 0 | テスト関数の再実行間に挟む待機秒。0 のときは即座に再実行されます。 |
(※) type と waitUntil / existNonExist の対応関係は実行時に検証されます。
waitUntil を指定して type: ExistNonExist を書く、といった食い違いがあると実行時にエラーになります。
評価ループの挙動
すべての Test plugin は次のループで動きます。
- テスト関数(プラグイン固有のロジック)を 1 回実行する。
- 結果(成功/失敗)を履歴に追記する。
- 直近
minConsecutiveSuccessCount件がすべて成功なら 成功 として終了。 minConsecutiveFailureCountが 0 でなく、直近のminConsecutiveFailureCount件が すべて失敗なら 失敗 として終了。timeoutSecondsが経過したら 失敗 として終了。intervalSeconds秒スリープして 1 に戻る(0なら即時)。
「1 回成功すれば OK」「再試行間隔は 1 秒」「最大 60 秒で打ち切り」を表現したい場合は次のようになります。
tests:
- type: WaitUntil
timeoutSeconds: 60
intervalSeconds: 1
waitUntil:
# ...
WaitUntilArgs
指定したリソースが「目的の状態」になるまでループで待つプラグインです。 判定条件は CEL 式で表現します。
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
resource.apiVersion | string | ◯ | 対象リソースの apiVersion。例: apps/v1、cert-manager.io/v1。 |
resource.kind | string | ◯ | 対象リソースの kind。例: Deployment、Certificate。 |
namespace | string | ◯ | 対象リソースの namespace。 |
name | string | ◯ | 対象リソースの name。 |
condition | string | ◯ | 真偽を返す CEL 式。式の中では object という名前で、取得したリソースが unstructured な map として参照できます。式の評価結果は bool 型でなければなりません(コンパイル時に型チェックされます)。 |
各イテレーションは「リソースを Get → CEL 式を評価」の組み合わせで動きます。
リソースの取得に失敗した(404 を含む)回もそのループの「失敗」として扱われます。
代表的な condition 例:
# Deployment が要求どおり Ready になっている
condition: "object.status.readyReplicas == object.spec.replicas"
# Available conditions が True になっている(条件 list 評価)
condition: >-
object.status.conditions.exists(c,
c.type == "Available" && c.status == "True")
CEL 式自体の言語仕様は CEL の公式ドキュメントを参照してください。
Tazuna は object 変数の追加と「結果は bool」という制約だけを掛けています。
例(WaitUntil)
tests:
- type: WaitUntil
timeoutSeconds: 120
intervalSeconds: 2
waitUntil:
resource:
apiVersion: apps/v1
kind: Deployment
namespace: ingress-nginx
name: ingress-nginx-controller
condition: "object.status.readyReplicas == object.spec.replicas"
ExistNonExistArgs
指定したリソースが「存在しているべき」または「存在していないべき」を表明するプラグインです。
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
resource.apiVersion | string | ◯ | 対象リソースの apiVersion。 |
resource.kind | string | ◯ | 対象リソースの kind。 |
namespace | string | ◯ | 対象リソースの namespace。 |
name | string | ◯ | 対象リソースの name。 |
shouldExist | bool | ◯ | true のとき、リソースが存在すれば成功。false のとき、存在しなければ成功。 |
判定は 1 回の Get 結果で行われます。
Get が NotFound を返すかどうかで存在判定し、shouldExist と突き合わせます。
NotFound 以外のエラー(権限不足など)はそのイテレーションの「失敗」として扱われます。
例(ExistNonExist)
tests:
# 想定したリソースが入ったことの表明
- type: ExistNonExist
existNonExist:
resource:
apiVersion: apps/v1
kind: Deployment
namespace: tazuna-managed
name: nginx
shouldExist: true
# 廃止したリソースが残っていないことの表明
- type: ExistNonExist
timeoutSeconds: 10
intervalSeconds: 1
existNonExist:
resource:
apiVersion: v1
kind: Secret
namespace: tazuna-managed
name: legacy-token
shouldExist: false
関連
- 配置先のフィールド:
tazuna.yamlのtestsフィールド - 用語: Test plugin
- 全体アーキテクチャ上の位置付け: 全体アーキテクチャ - Test plugin
State の内部構造
State は、Tazuna が「自分が入れたリソース」を追跡するための記録です。
クラスタ内の ConfigMap に保存され、tazuna state list / tazuna state diff /
tazuna state sync の起点になります。
このページでは State の保存形式と、それを支える State key / ContentHash / Diff type の 仕様をまとめます。
保存場所
State は クラスタ内 に保存されます。Tazuna のローカルファイルやリモートストレージは使いません。
| 要素 | 値 |
|---|---|
| Namespace | tazuna(無ければ自動作成される) |
| ConfigMap 名 | tazuna-state-<manifest-name> |
| 形式 | ConfigMap.data に key/value で 1 リソース 1 エントリ |
1 つの Manifest が 1 つの ConfigMap に対応します。
includes 展開後の各 Manifest 名はユニーク(tazuna.yaml の name 参照)なので、
ConfigMap 名は衝突しません。
State key
State key は、ConfigMap 内の 1 エントリを指す識別子です。
構造体としては manifestName / group / version / kind / namespace / name を持ち、
文字列化のフォーマットは次の 2 通りです。
| リソースのスコープ | 形式 | パート数 |
|---|---|---|
| namespaced | {manifest}/{group}/{version}/{kind}/{namespace}/{name} | 6 |
| cluster-scoped | {manifest}/{group}/{version}/{kind}/{name} | 5 |
group は core group("")の場合は空セグメントになります。
例: core/v1 の ConfigMap(namespaced)であれば、my-manifest//v1/ConfigMap/default/my-cm のように
2 つ目のスラッシュ間が空になります。
ConfigMap data key へのエンコード
Kubernetes の ConfigMap.data の key は [-._a-zA-Z0-9]+ しか許さず、/ を含められません。
そのため Tazuna は ConfigMap への書き込み時に State key 文字列の / を __ に置換します。
読み込み時には逆変換します。
state key: nginx/apps/v1/Deployment/default/nginx
data key: nginx__apps__v1__Deployment__default__nginx
Kubernetes の DNS-1123 名(manifest 名 / group / namespace / name)に _ は含まれないため、
__ は安全なセパレータとして使えます。
State エントリ (StateEntry)
各エントリは ConfigMap 上 1 つの value として、次の JSON 形で書き込まれます。
{"contentHash":"<hex sha256>"}
| フィールド | 型 | 説明 |
|---|---|---|
contentHash | string | リソースの内容に対する SHA-256 ハッシュ。詳細は ContentHash 参照。 |
_metadata キー
ConfigMap には予約キー _metadata がもう 1 つ入ります。
これは State エントリではなく、State 全体のメタ情報です。
{"gitCommitHash":"<sha>","lastSyncedAt":"<rfc3339>"}
| フィールド | 型 | 説明 |
|---|---|---|
gitCommitHash | string | 同期時に記録された git commit hash。 |
lastSyncedAt | string | 同期時刻。 |
Manifest の name には _metadata は使えません
(tazuna.yaml の name で予約語として扱われています)。
この衝突を避けるためのガードです。
ContentHash
ContentHash は、各リソースの YAML 表現から計算される SHA-256 の hex 文字列です。
Tazuna は server-side で付与される field と status を除いて計算します。
除外するフィールド:
| フィールド | 除外理由 |
|---|---|
metadata.resourceVersion | クラスタの世代管理用、適用ごとに変動するため |
metadata.uid | クラスタ採番、適用ごとに変動するため |
metadata.creationTimestamp | クラスタ採番、適用ごとに変動するため |
metadata.generation | クラスタ採番、適用ごとに変動するため |
metadata.managedFields | server-side apply の追跡情報 |
metadata.selfLink | クラスタ採番 |
status | コントローラが書く動的フィールド |
計算手順:
- オブジェクトを JSON マーシャル / アンマーシャルして deep copy する。
- 上記の除外対象フィールドを削除する。
- 残りを JSON マーシャルする。
- SHA-256 を取り hex 文字列化する。
status を含めると Pod の再起動などで毎回ハッシュが変わってしまうので、
「tazuna.yaml から見て同じ状態か」 を判定できる粒度に絞っています。
Diff type
tazuna state diff と tazuna state sync は、Build 結果と既存 State の比較結果を
Diff type で分類します。
| Diff type | 意味 | state sync の挙動 |
|---|---|---|
added | Build 結果に存在し、State に無い | 反映する |
modified | 両方に存在するが、ContentHash が異なる | 反映する |
removed | State に存在し、Build 結果に無い | デフォルトはスキップ。TAZUNA_STATE_SYNC_DELETE=true のときだけ削除 |
always-sync | 差分計算をスキップし、常に同期扱いとする | 反映する |
state diff の出力は added → modified → removed → always-sync の順、
同 Diff type 内は State key 昇順で安定ソートされます。
always-sync の対象
現バージョンでは、type: genesissecret 由来の Secret が always-sync 分類になります。
これらは Provider 側を真実の源として毎回同期する性質を持ち、ContentHash で差分判定できる対象ではありません。
詳細は GenesisSecret スキーマ - State と always-sync を参照してください。
関連
- 操作する CLI:
tazuna state list/tazuna state diff/tazuna state sync - 用語: State / State key / ContentHash / Diff type / always-sync
Manifest type 別リファレンス
tazuna.yaml の manifests[].type には 5 種類の値を取れます。
このセクションでは type ごとの path が指す先、固有フィールド、
apply / destroy / build 時の振る舞い を 1 ページずつにまとめます。
Manifest の共通フィールド(name / path / type / tags / includes / tests)の仕様は
tazuna.yaml スキーマ - Manifest を参照してください。
一覧
kustomize— kustomize でレンダリングしたリソースを反映するhelmfile— helmfile template の結果を反映するoras— OCI registry から artifact を pull し、helmfile / kustomize に委譲するparallel— 子 Manifest を並列に処理するgenesissecret— GenesisSecret YAML から Kubernetes Secret を生成する
type と固有フィールドの対応
各 type は manifests[] 内で 対応するオプションオブジェクト を持ちます。
type と対応するフィールドだけが読まれ、他は無視されます。
type | 固有フィールド名 | フィールド型 |
|---|---|---|
kustomize | kustomize | ManifestKustomize |
helmfile | helmfile | ManifestHelmfile |
oras | oras | ManifestORAS |
parallel | parallel | ManifestParallel |
genesissecret | genesisSecret | 空オブジェクト(現バージョンではフィールドを持たない) |
type: genesissecret は全部小文字ですが、対応するフィールド名は genesisSecret(camelCase)です。
YAML キーは camelCase に統一されており、type の値だけがプレーンな識別子(全部小文字)になっています。
type と path の対応
path は tazuna.yaml 自身の置かれているディレクトリ起点 の相対パスとして解釈されます。
type ごとに何を指すべきかが異なります。
type | path が指す先 |
|---|---|
kustomize | kustomization.yaml を含むディレクトリ |
helmfile | helmfile.yaml を含むディレクトリ |
oras | 実体としては使用されません。バリデーション都合で空にはできないため、適当なディレクトリを書きます。 |
parallel | 実体としては使用されません。children[] 側の path が使われます。バリデーション都合で空にはできません。 |
genesissecret | GenesisSecret YAML ファイル(他の type と違い、ディレクトリではなく単一ファイル) |
type: kustomize
kustomize Manifest は、kustomize でレンダリングした Kubernetes manifest をクラスタへ反映します。
Tazuna は内部で kustomize (sigs.k8s.io/kustomize) を呼び、kustomize build <path> 相当の
結果を生成して使います。
path
kustomization.yaml が置かれているディレクトリを指します。
tazuna.yaml 自身のディレクトリ起点 の相対パスで書きます。
ディレクトリ内に妥当な kustomization.yaml が無いと tazuna build / apply が失敗します。
固有フィールド
manifests[].kustomize のオブジェクトに書きます。
| フィールド | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
defaultNamespace | string | - | "" | レンダリング結果のリソースで metadata.namespace が未指定のものに付与する namespace。空のときはリソース側に書かれた namespace(無ければ Kubernetes 既定の default)が使われます。 |
振る舞い
| 操作 | 内部処理 |
|---|---|
Build | kustomize build <path> 相当のレンダリングを行い、結果 YAML を標準出力に書く。 |
Apply | レンダリング結果を unstructured オブジェクト群に変換し、defaultNamespace を補完したうえで 1 つずつ CreateOrUpdate する。 |
Destroy | レンダリング結果を unstructured オブジェクト群に変換し、defaultNamespace を補完したうえで 1 つずつ削除する。 |
kustomize build 自体はクラスタへの接続を必要としません。
ローカルファイルだけで完結します。
例
manifests:
- name: ingress-nginx
type: kustomize
path: ./kustomize/ingress-nginx
tags:
- infra
- name: app-overlay
type: kustomize
path: ./kustomize/app/overlays/staging
kustomize:
defaultNamespace: staging
関連
type: helmfile
helmfile Manifest は、helmfile で記述された複数の Helm release を、
helmfile template 相当でレンダリングしてからクラスタへ反映 する Manifest type です。
Tazuna は内部で helmfile/helmfile パッケージの app.Template を呼び、その出力 YAML を
unstructured オブジェクトに変換して CreateOrUpdate します。helm の release 履歴は
クラスタ側に保存しません(helm rollback は使えなくなります)。
ブートストラップにおいては rollback よりも宣言的な再生成を優先する、というスタンスです。
path
helmfile.yaml(または helmfile.yaml.gotmpl などの helmfile が認識するファイル)が
置かれているディレクトリを指します。
tazuna.yaml 自身のディレクトリ起点 の相対パスで書きます。
固有フィールド
manifests[].helmfile のオブジェクトに書きます。
| フィールド | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
vars | map<string, HelmFileVar> | - | {} | helmfile に渡す変数。詳細は vars 参照。 |
includeCRDs | bool | - | false | helmfile template に --include-crds 相当を渡します。 |
defaultNamespace | string | - | "" | レンダリング結果のリソースで metadata.namespace が未指定のものに付与する namespace。 |
extraValueFiles | [string] | - | [] | helmfile template に追加で渡す --values ファイル群。 |
wait | bool | - | false | true のとき、Apply 後に対象リソースが Ready になるまで待ちます。詳細は wait の挙動 参照。 |
timeoutSeconds | int | - | 0 | wait の最大待機秒数。0 のときは内部で 300 秒(5 分)が使われます。 |
kubeVersion | string | - | "" | helmfile template に渡す --kube-version の値。 |
vars
vars のキーは helmfile 側の変数名、値が HelmFileVar です。
tazuna.yaml のロード時、vars は次の順序で解決されます。
- 各 var の
from(env/static/op) に応じて値を取得する。 - 同じディレクトリに
tazuna.hint.yamlがあれば、tazuna.hint.yamlの 検証・デフォルト注入を行う。
vars に書かないでも tazuna.hint.yaml の default から値が入る、というケースもあります。
逆に tazuna.hint.yaml の制約に違反するとここでエラーになります。
HelmFileVar
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
from | string | ◯ | 値の取得元。env / static / op のいずれか。 |
env | string | △ (※) | from: env のとき必須。参照する環境変数名。 |
static | string | △ (※) | from: static のときに使う。スカラー値。 |
staticSlice | [string] | △ (※) | from: static のときに使う。スライス値。 |
staticMap | map<string, string> | △ (※) | from: static のときに使う。マップ値。 |
op | OnePasswordVaultSelector | △ (※) | from: op のとき必須。 |
(※) from の値に応じて、env / static 系のいずれか 1 つ / op が必須です。
from: static の場合、static / staticSlice / staticMap のうち 1 つだけ が設定されている必要があります。
OnePasswordVaultSelector
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
key | string | ◯ | フィールドを id で参照するか label で参照するか。id または label。 |
vault | string | ◯ | 1Password の Vault 名。 |
item | string | ◯ | 1Password の Item 名。 |
field | string | ◯ | 取得するフィールド。key が id ならフィールドの ID、label ならラベル。 |
wait の挙動
wait: true のとき、Apply の終わりに対象リソース全部の Ready 待ちが走ります。
2 秒間隔で polling し、timeoutSeconds(未指定なら 300 秒)を超えるとエラー。
各 Kind の Ready 判定:
| Kind | Ready 条件 |
|---|---|
Deployment | spec.replicas == 0 なら即 Ready。それ以外は status.readyReplicas == status.replicas かつ status.availableReplicas == status.replicas かつ status.replicas > 0 |
StatefulSet | spec.replicas == 0 なら即 Ready。それ以外は status.readyReplicas == status.replicas かつ status.replicas > 0 |
DaemonSet | status.numberReady == status.desiredNumberScheduled かつ status.desiredNumberScheduled > 0 |
Pod | status.phase == "Running" かつ Ready condition が True |
| その他 | 取得できれば即 Ready 扱い(ConfigMap / Secret / Service など) |
wait で待ちきれないリソース固有の条件(CRD の status など)を表現したい場合は、
Test plugin の WaitUntil(CEL 式)を使うほうが柔軟です。
振る舞い
| 操作 | 内部処理 |
|---|---|
Build | helmfile template の出力 YAML を標準出力に書く。 |
Apply | helmfile template の結果を unstructured 化し、defaultNamespace を補完して順に CreateOrUpdate。wait が true なら Ready 待ち。 |
Destroy | helmfile template の結果を unstructured 化し、defaultNamespace を補完して順に削除。wait は適用されません。 |
Apply / Destroy / Build のいずれも helmfile template の段階で vars を解決します。
解決に失敗した場合(環境変数未設定、1Password の Item にフィールドが無い等)はクラスタには触れずに失敗します。
例
manifests:
- name: cert-manager
type: helmfile
path: ./helmfile/cert-manager
helmfile:
includeCRDs: true
wait: true
timeoutSeconds: 120
vars:
clusterIssuerEmail:
from: env
env: CLUSTER_ISSUER_EMAIL
dnsProviderApiToken:
from: op
op:
key: label
vault: Platform
item: cert-manager
field: cloudflare-api-token
extraLabels:
from: static
staticMap:
managed-by: tazuna
tier: platform
関連
- helmfile.vars の制約:
tazuna.hint.yamlスキーマ - 用語: helmfile / Helm / 1Password
type: oras
oras Manifest は、OCI registry に置かれた artifact を pull し、その内容を
helmfile または kustomize に 委譲して クラスタへ反映する Manifest type です。
pull → 展開 → 委譲先 Manager の呼び出し、までを ORAS Manager がまとめて行います。 artifact の中身そのものは helmfile / kustomize と同じ作法で書きます。
path
ORAS Manifest の manifests[].path は 実体としては使用されません。
バリデーション都合で空にはできないため、何かしらのディレクトリを書きます。
委譲先 Manager に渡される path は、pull 後にローカルへ展開された
キャッシュディレクトリ(必要なら target でサブパスへ降りたもの)になります。
固有フィールド
manifests[].oras のオブジェクトに書きます。
| フィールド | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
reference | string | ◯ | - | OCI artifact の reference。tag 形式 (ghcr.io/example/foo:v1.0.0) と digest 形式 (ghcr.io/example/foo@sha256:...) の両方を受け付けます。 |
target | string | - | "" | 展開後の artifact root からの相対サブパス。省略時は root を指します。.. などで artifact root を脱出する値は拒否されます。 |
plainHTTP | bool | - | false | true のとき registry への接続を HTTP(非 TLS)で行います。 |
insecureSkipVerify | bool | - | false | true のとき registry 接続時の TLS 証明書検証をスキップします。 |
auth | ORASAuth | - | null | registry の認証情報を override します。省略時は docker config.json を使用します。詳細は 認証の解決 参照。 |
delegate | ORASDelegate | ◯ | - | pull 後の委譲先 Manager の設定。 |
ORASAuth
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
username | string | - | registry のユーザー名。 |
password | string | - | registry のパスワード。 |
両フィールドが空のときは override 扱いになりません(認証の解決 参照)。
ORASDelegate
| フィールド | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
type | string | ◯ | - | 委譲先の Manifest type。helmfile または kustomize。 |
helmfile | ManifestHelmfile | - | null | type: helmfile のときに委譲先へそのまま渡されるオプション。 |
kustomize | ManifestKustomize | - | null | type: kustomize のときに委譲先へそのまま渡されるオプション。 |
振る舞い
| 操作 | 内部処理 |
|---|---|
Build | artifact を pull → 委譲先の Build を呼ぶ。 |
Apply | artifact を pull → 委譲先の Apply を呼ぶ。 |
Destroy | artifact を pull → 委譲先の Destroy を呼ぶ。 |
委譲先には次のように新しい Manifest が組み立てられて渡されます。
name/description/tags/testsは元の ORAS Manifest からそのまま引き継ぐ。typeはdelegate.type(helmfile/kustomize)。pathは pull 後のローカルパス(target指定があれば追加でサブパスを結合)。- 固有フィールドは
delegate.helmfile/delegate.kustomizeをそのまま使う。
Test plugin も同じ Manifest の文脈で評価されます。
Pull とキャッシュ
ORAS の pull は digest 単位でローカルにキャッシュ されます。 同じ digest を持つ artifact の 2 回目以降の pull は registry にアクセスしません。
- キャッシュディレクトリ:
$XDG_CACHE_HOMEが設定されていれば$XDG_CACHE_HOME/tazuna/oras- そうでなければ
$HOME/.cache/tazuna/oras
- キャッシュ構造:
blobs/<sanitized digest>/配下に artifact を展開するrefs/<sanitized reference>に tag → digest のマッピングを記録する
--no-cacheをapply/build/destroyに指定するとキャッシュを無視して常に registry から再取得します。--offlineを指定すると registry へのアクセスを禁止します。キャッシュにヒットしなければエラーになります。--no-cacheと--offlineは同時には指定できません。- CLI フラグは
apply/build/destroyのページを参照。
展開時の制約
artifact 内の tar 展開には ADR004 で定めた上限 が適用されます。
| 上限 | 値 |
|---|---|
| 展開後合計サイズ | 1 GiB |
| tar entry 数 | 10000 |
以下の不正な entry は拒否されます。
- 絶対パスを含む entry
..で展開先ディレクトリを脱出する entry(zip slip)- 展開先を脱出する symlink / hardlink
- サポート外の type(character device / block device / FIFO 等)
artifact の OCI manifest は layer が 1 つだけ であることが前提です。複数 layer の artifact は受け付けません。
認証の解決
registry に対する credential は次の優先順位で解決されます。
oras.authの override(username/passwordの少なくとも一方が非空)- docker の credential store(
$DOCKER_CONFIGまたは~/.docker/config.json) - anonymous(認証なし)
oras.auth を書いていても両フィールドが空のときは override 扱いされず、
docker 側へフォールバックします(意図しない anonymous 化を避けるため)。
同一プロセス内では token のキャッシュが共有されるため、同じ registry に対する複数の pull で token を取り直すコストはかかりません。
例
tag 指定 + helmfile 委譲:
manifests:
- name: cert-manager
type: oras
path: ./oras/cert-manager # 実体としては使われないが必須
oras:
reference: ghcr.io/example/cert-manager-helmfile:v1.14.0
delegate:
type: helmfile
helmfile:
includeCRDs: true
wait: true
digest 指定 + kustomize 委譲 + サブパス:
manifests:
- name: ingress-nginx
type: oras
path: ./oras/ingress-nginx
oras:
reference: registry.example.com/platform/ingress-bundle@sha256:abc123...
target: kustomize/ingress-nginx
auth:
username: ci-bot
password: ${REGISTRY_TOKEN}
delegate:
type: kustomize
kustomize:
defaultNamespace: ingress-nginx
関連
- 委譲先:
type: helmfile/type: kustomize - CLI:
tazuna apply/tazuna build/tazuna destroy - 用語: ORAS / OCI artifact
type: parallel
parallel Manifest は、複数の子 Manifest を 並列に処理する ためのコンテナです。
子の type は kustomize / helmfile / genesissecret / oras のいずれか
(parallel のネストは想定していません)。
path
parallel Manifest 自体の manifests[].path は 実体としては使用されません。
バリデーション都合で空にはできないため、何かしらのディレクトリを書きます。
実際の処理対象パスは、各 children[].path 側で指定します。
固有フィールド
manifests[].parallel のオブジェクトに書きます。
| フィールド | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
children | [Manifest] | ◯ | - | 並列に処理する子 Manifest の配列。1 件以上 必要。 |
children[] の各要素は Manifest と同じ構造です。
children[] 内の Manifest が持つ name も、include 展開後の全 Manifest 名と同じ空間で
一意でなければなりません(tazuna check で検証されます)。
振る舞い
| 操作 | 内部処理 |
|---|---|
Apply | children[] の各要素に対応する Manager の Apply を goroutine で並列 に呼ぶ。エラーは集約して返す。 |
Destroy | children[] の各要素に対応する Manager の Destroy を並列に呼ぶ。 |
Build | children[] の各要素に対応する Manager の Build を並列に呼び、宣言順を保ったまま \n---\n で結合した文字列を返す。空文字の出力はスキップ。 |
children[] の処理順序は保証されません。並列で動かして問題ないグループにだけ使ってください。
順序依存(A の CRD を待ってから B を入れる、など)がある場合は、parallel を使わず
通常の manifests[] の宣言順に並べるか、子 Manifest 側の Test plugin で
Ready 待ちを表現します。
例
並列に入れて構わない 2 つの kustomize を 1 つの parallel に束ねる例:
manifests:
- name: observability
type: parallel
path: ./parallel/observability # 実体としては使われないが必須
parallel:
children:
- name: prometheus
type: kustomize
path: ./kustomize/prometheus
tags:
- observability
- name: grafana
type: kustomize
path: ./kustomize/grafana
tags:
- observability
関連
- 子 Manifest として書ける type:
kustomize/helmfile/genesissecret/oras - Manifest 共通フィールド:
tazuna.yaml- Manifest
type: genesissecret
genesissecret Manifest は、別ファイルに書いた GenesisSecret YAML
を読み込み、外部 Secret ストア(現バージョンでは 1Password)から取得した値で
Kubernetes Secret を生成する Manifest type です。
tazuna.yaml 側でこの Manifest type が担うのは「どの GenesisSecret YAML を読むか」だけです。
中の spec.secrets / spec.outputs などの仕様は GenesisSecret スキーマ
を参照してください。
path
他の Manifest type と違い、path は ディレクトリではなく YAML ファイル 1 つを直接指します。
tazuna.yaml 自身のディレクトリ起点 の相対パスで書きます。
manifests:
- name: aws-credentials
type: genesissecret
path: ./genesissecrets/aws.yaml # ← ファイルを直接指す
固有フィールド
manifests[].genesisSecret のオブジェクトに書きます。
現バージョンでは フィールドを持たない空オブジェクト です。 将来の拡張のために予約されているフィールド名です。
manifests:
- name: aws-credentials
type: genesissecret
path: ./genesissecrets/aws.yaml
# genesisSecret: {} # 現状は中身が空のため書く必要なし
振る舞い
| 操作 | 内部処理 |
|---|---|
Build | GenesisSecret YAML を読み込み、Provider から値を取得し、outputs[0].kubernetesSecret 1 件分の Secret YAML を標準出力に書く。 |
Apply | GenesisSecret YAML を読み込み、Provider から値を取得し、outputs[].kubernetesSecret の各エントリに対して Kubernetes Secret を CreateOrUpdate する。 |
Destroy | GenesisSecret YAML を読み込み(Provider 取得も実行されます)、outputs[].kubernetesSecret の namespace / name に該当する Secret を削除する。 |
Build は outputs の先頭 1 件のみを出力する点が Apply と異なります(複数 outputs を
書いていても、tazuna build の出力は 1 件分です)。詳細は
GenesisSecret - 解決の流れ を参照してください。
State との関係
type: genesissecret から生成される Secret は、tazuna state diff 上で常に always-sync
として扱われます。ContentHash で差分判定する対象ではなく、Provider 側を真実の源として
毎回同期されます。詳細は State の内部構造 - Diff type と
GenesisSecret - State と always-sync を参照してください。
関連
- GenesisSecret YAML のスキーマ: GenesisSecret スキーマ
- 既存 Secret から GenesisSecret を書き出す:
tazuna secret-to-genesissecret - 用語: GenesisSecret / Provider (SecretProvider) / always-sync
CLI
このセクションは tazuna バイナリが提供するすべてのサブコマンドの仕様を、
1 コマンド 1 ページで網羅します。
ページは規約書として読まれることを想定しています。 コマンドの選び方や運用上の使い分けは ガイド を、 そもそも各コマンドが何を解いているかは 概念 を参照してください。
サブコマンド一覧
tazuna apply—tazuna.yamlをクラスタに反映するtazuna build— クラスタに触らずにレンダリング結果を出力するtazuna check—tazuna.yamlの妥当性を検証するtazuna destroy— Tazuna 管理リソースをクラスタから削除するtazuna state list— State に記録されているリソースを一覧するtazuna state diff— Build 結果と State の差分を出すtazuna state sync— 差分を State 主導で反映するtazuna secret-to-genesissecret— 既存 Secret を 1Password と GenesisSecret に書き出すtazuna tags—tazuna.yamlに書かれているタグを一覧するtazuna version— バージョン情報を出力する
グローバルフラグ
すべてのサブコマンドが継承する persistent フラグです。
| フラグ | エイリアス | 型 | デフォルト | 説明 |
|---|---|---|---|---|
--file-path | -f | string | tazuna.yaml | tazuna.yaml のパス。 |
--log-level | -l | string | info | ログレベル。debug / info / warn / error のいずれか。 |
--version | - | - | - | ルートコマンドにのみ付くフラグ。バージョン情報を出して終了する。tazuna version と等価。 |
共通の振る舞い
kubeconfig
クラスタアクセスを行うサブコマンドは、起動時に kubeconfig をロードし、
current-context が指すクラスタ に対して動作します。
KUBECONFIG 環境変数や --kubeconfig 相当のフラグは Tazuna 側では持たず、
kubectl と同じ解決ルールに従います。
context_matches の評価
tazuna.yaml の spec.context_matches が設定されている場合、
クラスタに触る直前 に current-context 名と照合します。
- 評価が走るコマンド:
apply/destroy - 評価が走らないコマンド:
build/check/state list/state diff/state sync/tags/version/secret-to-genesissecret
評価モードは spec.context_match_mode(or / and、デフォルト or)に従います。
詳細は tazuna.yaml スキーマ - context_matches を参照。
tazuna.yaml のバリデーション
apply / build / destroy / check / tags は、いずれも実行の最初に
tazuna.yaml をロードしてバリデーションします。
バリデーションで失敗するとクラスタには触れません。
チェック項目の一覧は tazuna.yaml スキーマ - バリデーションのまとめ を参照。
終了コード
| 終了コード | 意味 |
|---|---|
0 | 成功 |
| 非ゼロ | 失敗。標準エラーに error: ... 形式でエラーが出力されます。 |
非ゼロ終了は CI でそのまま失敗扱いにできます。 コマンドごとに異なる終了コードを返すような区別は現状ありません。
環境変数
CLI フラグに加えて、Tazuna が参照する環境変数を一覧にしておきます。
| 環境変数 | 値 | 影響するコマンド | 効果 |
|---|---|---|---|
TAZUNA_DESTROY_EXECUTABLE | true | destroy | これが true に設定されていない限り、destroy は実体の削除を行いません。プロンプトで Yes と答えても、この環境変数が無ければ何も起こりません。 |
TAZUNA_STATE_SYNC_DELETE | true | state sync | これが true のときだけ、State には残っていてクラスタには無くなったリソース(removed)を削除します。デフォルトは削除をスキップします。 |
KUBECONFIG | パス | クラスタを触る全コマンド | 通常の kubectl と同じ kubeconfig 解決ルールに従います。 |
tazuna apply
tazuna.yaml で宣言された Manifest 群をクラスタへ反映します。
Tazuna の中心となるコマンドです。
tazuna apply [-f tazuna.yaml] [--tags ...] [--no-cache | --offline]
振る舞い
実行順序は次のとおりです。クラスタに触れるのは 5 以降です。
tazuna.yamlをロードしてバリデーションする。spec.context_matchesが設定されていれば、current-context と照合する。 合致しなければ即終了する。--tagsでフィルタする。manifests[]を 宣言順 に走査する。- 各 Manifest を対応する Manager に渡し、クラスタへ反映する。
- 各 Manifest の
testsを実行する。 - すべての Manifest 適用後、
spec.tests(全体 Tests)を実行する。
フラグ
グローバルフラグ に加えて次を受け付けます。
| フラグ | エイリアス | 型 | デフォルト | 説明 |
|---|---|---|---|---|
--tags | -t | []string | [] | 指定したタグのいずれかが付いている Manifest だけを処理対象にします(OR 評価)。 |
--no-cache | - | bool | false | type: oras の Manifest で、キャッシュを使わずに常に registry から再取得します。 |
--offline | - | bool | false | type: oras の Manifest で、registry へのアクセスを禁止します。キャッシュにヒットしなければエラーになります。 |
--no-cache と --offline は同時に指定できません。
例
tazuna apply -f tazuna.yaml
tazuna apply -f tazuna.yaml --tags web,batch
tazuna apply -f tazuna.yaml --log-level debug
関連
- 評価される
context_matches - フィルタの仕様は
manifests[].tags - 反映前にレンダリングだけ確認したい場合は
tazuna build - 既存リソースを取り外す場合は
tazuna destroy
tazuna build
tazuna.yaml で宣言された Manifest 群をレンダリングし、結果を標準出力に書き出します。
クラスタは変更しません。 apply 前のプレビューや、別ツールへのパイプ入力として使います。
tazuna build [-f tazuna.yaml] [--tags ...] [--no-cache | --offline]
振る舞い
tazuna.yamlをロードしてバリデーションする。--tagsでフィルタする。- 各 Manifest を対応する Manager の Build に渡し、結果を連結して標準出力に書き出す。
context_matches の評価は行いません。
クラスタへの reach も Manager の Build 実装次第ですが、
組み込みの Manager は基本的に kubeconfig を要求しません
(ORAS の registry pull は別途ネットワークアクセスを行います)。
フラグ
グローバルフラグ に加えて次を受け付けます。
| フラグ | エイリアス | 型 | デフォルト | 説明 |
|---|---|---|---|---|
--tags | -t | []string | [] | 指定したタグのいずれかが付いている Manifest だけを処理対象にします(OR 評価)。 |
--no-cache | - | bool | false | type: oras の Manifest で、キャッシュを使わずに常に registry から再取得します。 |
--offline | - | bool | false | type: oras の Manifest で、registry へのアクセスを禁止します。キャッシュにヒットしなければエラーになります。 |
--no-cache と --offline は同時に指定できません。
例
tazuna build -f tazuna.yaml
tazuna build -f tazuna.yaml --tags web
tazuna build -f tazuna.yaml | kubectl diff -f -
関連
- 反映する場合は
tazuna apply - 差分は
tazuna state diff
tazuna check
tazuna.yaml の妥当性を、クラスタには触れずに検証します。
CI で最初に通す対象に向きます。
tazuna check [-f tazuna.yaml] [--fix]
振る舞い
tazuna.yamlをロードする。- ファイルおよび展開後の
manifests[]全体に対してバリデーションを実行する。 - 問題が無ければ
okを標準出力に書き、終了コード 0 で抜ける。 --fixを指定した場合は、name未設定の Manifest に自動採番した上でtazuna.yamlを書き戻し、fixed: <path>を標準出力に書く。
検証項目の一覧は tazuna.yaml スキーマ - バリデーションのまとめ を参照してください。
クラスタへのアクセスは行いません。
フラグ
グローバルフラグ に加えて次を受け付けます。
| フラグ | エイリアス | 型 | デフォルト | 説明 |
|---|---|---|---|---|
--fix | - | bool | false | name 未設定の Manifest を自動採番し、tazuna.yaml を書き戻します。 |
--fix はファイルを上書きします。バージョン管理下で実行することを推奨します。
例
tazuna check
tazuna check -f path/to/tazuna.yaml
tazuna check --fix
関連
- 検証ルールの詳細:
tazuna.yamlスキーマ
tazuna destroy
Tazuna が管理しているリソースをクラスタから削除します。 事故を防ぐために 二段階のガード が掛かっています。
TAZUNA_DESTROY_EXECUTABLE=true tazuna destroy [-f tazuna.yaml] \
[--tags ...] [--force] [--no-cache | --offline]
振る舞い
-
tazuna.yamlをロードしてバリデーションする。 -
spec.context_matchesが設定されていれば、current-context と照合する。 合致しなければ即終了する。 -
--forceが無ければ、次のプロンプトを出して Y/N の確認を取る。!!! All resources managed by Tazuna will be deleted !!! Are you sure you want to delete them? -
環境変数
TAZUNA_DESTROY_EXECUTABLEがtrueでなければ、 ログだけ出してクラスタには 触れず に終了する。 -
ガードを通過した場合のみ、
--tagsフィルタを適用したうえで Manager の Destroy を順に呼び出し、対応リソースをクラスタから削除する。
つまり「プロンプトで Yes」「TAZUNA_DESTROY_EXECUTABLE=true」の 両方 を満たさない限り、
リソースは消えません。
フラグ
グローバルフラグ に加えて次を受け付けます。
| フラグ | エイリアス | 型 | デフォルト | 説明 |
|---|---|---|---|---|
--force | - | bool | false | 削除前の確認プロンプトをスキップします。環境変数のガードはスキップしません。 |
--tags | -t | []string | [] | 指定したタグのいずれかが付いている Manifest だけを削除対象にします(OR 評価)。 |
--no-cache | - | bool | false | type: oras の Manifest で、キャッシュを使わずに常に registry から再取得します。 |
--offline | - | bool | false | type: oras の Manifest で、registry へのアクセスを禁止します。 |
--no-cache と --offline は同時に指定できません。
環境変数
| 環境変数 | 値 | 説明 |
|---|---|---|
TAZUNA_DESTROY_EXECUTABLE | true | これが設定されていない限り、destroy は何も削除しません。CI で誤って destroy が走るのを防ぐためのキルスイッチです。 |
例
TAZUNA_DESTROY_EXECUTABLE=true tazuna destroy
TAZUNA_DESTROY_EXECUTABLE=true tazuna destroy --tags experimental
TAZUNA_DESTROY_EXECUTABLE=true tazuna destroy --force
関連
- 評価される
context_matches - 反映側は
tazuna apply
tazuna state list
クラスタに保存されている Tazuna の State を読み、 Tazuna 管理下にあるリソースとその content hash を一覧します。
tazuna state list [-f tazuna.yaml]
振る舞い
tazuna.yamlをロードする。- 各 Manifest の
nameから対応する State ConfigMap (tazunanamespace のtazuna-state-<manifest-name>)を読む。 - State に記録されている各リソースの GVK / namespace / name / content hash を 標準出力に整形して出力する。
context_matches の評価は行いません。
クラスタへの read アクセスのみを行い、State を含むいかなるリソースも変更しません。
フラグ
グローバルフラグ 以外に固有フラグはありません。
例
tazuna state list
tazuna state list -f tazuna.yaml
関連
- 差分の確認は
tazuna state diff - 差分の反映は
tazuna state sync - State の語彙は 用語集 - State
tazuna state diff
各 Manager の Build 結果と、クラスタに保存されている State を比較し、 リソース単位の差分を出力します。クラスタは変更しません。
tazuna state diff [-f tazuna.yaml]
振る舞い
tazuna.yamlをロードする。- 各 Manifest について、Manager の Build を呼び出して
「いま
tazuna.yamlから生成されるべきリソース」を組み立てる。 - クラスタ上の State と突き合わせて、リソース単位で次のいずれかに分類して出力する。
| Diff type | 意味 |
|---|---|
added | Build 結果には存在し、State には存在しない |
modified | 両方に存在するが、content hash が異なる |
removed | State にあるが、Build 結果には存在しない |
always-sync | 差分計算をスキップし、常に同期する扱いの分類。type: genesissecret 由来の Secret はここに入る |
context_matches の評価は行いません。
クラスタへの read アクセスのみを行い、何も変更しません。
フラグ
グローバルフラグ 以外に固有フラグはありません。
例
tazuna state diff
tazuna state diff -f tazuna.yaml
関連
- 反映は
tazuna state sync - 全件レンダリング結果が欲しいときは
tazuna build - 用語: Diff type / ContentHash
tazuna state sync
各 Manager の Build 結果と State を比較し、追加・変更されたリソースだけを クラスタへ反映します。同期に成功したリソースの State は ConfigMap に書き戻されます。
tazuna state sync [-f tazuna.yaml] [--atomic]
振る舞い
tazuna.yamlをロードする。- 各 Manifest について Build を呼び出し、State との差分を計算する。
added/modified/always-sync分類のリソースをクラスタへ反映する。removed分類のリソースは デフォルトではスキップ される。TAZUNA_STATE_SYNC_DELETE=trueを設定したときに限り、削除を行う。- 同期に成功したリソースの State を書き戻す。
--atomic を指定した場合、いずれかのリソースでエラーが発生したときは
State をまったく更新せずに終了します(途中まで進んだ反映自体は巻き戻りません)。
context_matches の評価は行いません。
フラグ
グローバルフラグ に加えて次を受け付けます。
| フラグ | エイリアス | 型 | デフォルト | 説明 |
|---|---|---|---|---|
--atomic | - | bool | false | エラーが発生したときに State を更新せずに終了します。 |
環境変数
| 環境変数 | 値 | 説明 |
|---|---|---|
TAZUNA_STATE_SYNC_DELETE | true | removed 分類のリソースを削除します。設定されていない場合は削除を行いません。 |
例
tazuna state sync
tazuna state sync -f tazuna.yaml
tazuna state sync --atomic
TAZUNA_STATE_SYNC_DELETE=true tazuna state sync
関連
- 差分の確認は
tazuna state diff - 用語: Diff type / always-sync
tazuna secret-to-genesissecret
クラスタ上の既存 Secret を 1Password に書き出し、 それを参照する GenesisSecret YAML を生成します。 移行 / 棚卸し用の片道のコマンド であり、定常運用で繰り返し叩くものではありません。
tazuna secret-to-genesissecret \
--op-host <host> \
[--namespace <ns>] \
[--label-selector <sel>] [--name-regex <re>] \
[--vault <vault>] [--note <note>] \
[--dump-dir <dir>] [--dry-run]
振る舞い
--namespace(デフォルトdefault)の Secret を--label-selector/--name-regexで絞り込む。- 各 Secret のデータを 1Password の
--vaultに Item として書き出す。 - その Item を参照する GenesisSecret YAML を
--dump-dir(デフォルト.)に出力する。 --dry-runのときは、1Password への書き込みも YAML の生成も行わずに、 対象 Secret の選定結果だけを出力する。
tazuna.yaml は読まないので -f / --file-path は無視されます。
グローバルフラグのうち実際に効くのは -l / --log-level だけです。
クラスタへの read と 1Password への write の両方が走るため、
1Password CLI (op) が認証済みであること が前提です。
フラグ
グローバルフラグ に加えて次を受け付けます。
| フラグ | 型 | デフォルト | 必須 | 説明 |
|---|---|---|---|---|
--op-host | string | - | ◯ | 1Password サービスアカウント URL のホスト部分(例: example.1password.com)。 |
--namespace | string | default | - | 対象 Secret が存在する Kubernetes namespace。シェル補完で実クラスタの namespace を列挙します。 |
--label-selector | string | "" | - | 対象 Secret を絞る label selector。例: app=foo,tier=db。 |
--name-regex | string | "" | - | 対象 Secret の name に対する正規表現。 |
--vault | string | "" | - | 1Password の vault 名。シェル補完で実 vault を列挙します。 |
--note | string | "" | - | 生成される 1Password Item に付ける note。 |
--dump-dir | string | . | - | 生成された GenesisSecret YAML の出力先ディレクトリ。 |
--dry-run | bool | false | - | 書き込みを行わず、選定結果だけを出力します。 |
例
tazuna secret-to-genesissecret \
--op-host example.1password.com \
--namespace production \
--label-selector tazuna.pepabo.com/migrate=true \
--vault platform \
--dump-dir ./genesissecrets
tazuna secret-to-genesissecret \
--op-host example.1password.com \
--name-regex '^db-.*' \
--dry-run
関連
- 生成された YAML は
type: genesissecretの Manifest としてtazuna.yamlから参照します。 - 用語: GenesisSecret / Provider (SecretProvider)
tazuna tags
tazuna.yaml で宣言されているタグを一覧します。
タグごとに、そのタグが付いている Manifest の name を表示します。
tazuna tags [-f tazuna.yaml] [--tags ...]
振る舞い
tazuna.yamlをロードしてバリデーションする。includes展開後の全 Manifest を走査し、tagsをタグ名 → Manifest 名のリストのマップに集約する。- タグ名でソートして標準出力に出力する。出力は次の形式です。
<tag>:
- <manifest-name>
- <manifest-name>
--tagsが指定された場合は、そのタグ名に絞って出力する。
クラスタへのアクセスはありません。
フラグ
グローバルフラグ に加えて次を受け付けます。
| フラグ | エイリアス | 型 | デフォルト | 説明 |
|---|---|---|---|---|
--tags | -t | []string | [] | 出力対象を指定したタグ名に絞り込みます。 |
例
tazuna tags
tazuna tags -f tazuna.yaml
tazuna tags --tags frontend,backend
関連
--tagsの絞り込み仕様:manifests[].tags- 絞り込んで apply する場合は
tazuna apply
tazuna version
バイナリに埋め込まれたバージョン情報を出力します。
tazuna version
tazuna --version
両者は等価です。
振る舞い
次の形式で 1 行出力して終了します。
tazuna <version> (commit <commit>, built <date>, <os>/<arch>)
<version>— リリース時のタグ。ローカルビルドではdev。<commit>— リリース時の commit hash。未注入時はnone。<date>— リリース時のビルド日時。未注入時はunknown。<os>/<arch>—runtime.GOOS/runtime.GOARCH。
<version> / <commit> / <date> は goreleaser によるリリース時に注入されます。
go install / go run などローカルビルドでは未注入のためデフォルト値が出ます。
フラグ
固有フラグはありません。引数も受け付けません。
例
tazuna version
tazuna --version
コントリビュート
このセクションは、Tazuna のコードベース・ドキュメント・リリースに変更を入れる人向けの案内です。
リポジトリのルートにある CONTRIBUTING.md
が一次情報で、ここではそれを補う形で各トピックを 1 ページずつにまとめます。
一覧
- 開発環境 —
miseで toolchain を揃え、make buildでローカルバイナリを作るまでの手順とリポジトリ構成。 - テスト —
unit / integration / e2e の 3 レイヤと
makeターゲットの対応、KinD クラスタの用意。 - ドキュメント —
docs/の構造、mdbookでのプレビュー、po/en.poを使った英語訳の更新フロー、GitHub Pages への公開。 - リリース — tag push を起点とした goreleaser によるリリース、バージョン埋め込み、SBOM / 署名 / 来歴。
バグ報告 / 機能提案
GitHub の Issue テンプレート を使ってください。テンプレート無しの自由記述 issue は受け付けます。
セキュリティ起因の問題は SECURITY.md
の手順に従ってください。公開 issue は作らないでください。
Pull Request の流れ
CONTRIBUTING.md の記述と同じ流れです。再掲しておきます。
mainから作業ブランチを切る。- 変更はトピックごとに小さくまとめる。
- push する前にローカルで
make testとmake lintを通す。 main宛に PR を作成。CI が green になるまでレビュー対象にならない。
PR テンプレートはリポジトリの .github/PULL_REQUEST_TEMPLATE.md
を使います。
開発環境
このページは、Tazuna 本体に手を入れたい人がローカル環境を整え、 コード変更をビルド・実行・確認するまでの手順をまとめます。 ドキュメントやリリースについては別ページ(ドキュメント / リリース)を参照してください。
toolchain は mise で揃える
リポジトリには mise.toml が
入っており、必要な toolchain がピン留めされています。
[tools]
go = "1.26.0"
golangci-lint = "latest"
helm = "latest"
mise をインストール済みであれば、リポジトリのルートで mise install を実行すれば
これらが揃います。Go や golangci-lint をシステム側で別管理している場合は、mise.toml
と一致するバージョンを自分で揃えてください。
なお go.mod が要求する Go のバージョン (go 1.26.x) が mise.toml のピン留めより
新しい場合は、ビルド時に Go の toolchain ダウンロード機構が差分を吸収します。意図的に
toolchain ダウンロードを避けたい場合は、mise.toml を go.mod の go 行に揃えて使ってください。
helm バイナリは Tazuna 自身は使いません(Helmfile backend
は Go ライブラリとして組み込んでいます)。mise.toml に入っているのは、helm を
依存ツールとして扱う開発フローを将来サポートする余地を残すためのものです。
主要な make ターゲット
Makefile の中身に対応するターゲットだけ列挙します。
| ターゲット | 中身 |
|---|---|
make build | go build . で ./tazuna を生成 |
make install | make build の後 sudo mv tazuna /usr/local/bin |
make format | go fmt ./... |
make lint | golangci-lint run |
make test | go test ./...(unit テスト) |
make test-integration | go test -tags=integration ./... |
make test-e2e | make build && make devenv-create の後 go test -tags=e2e -count=1 ./test/e2e/... |
make test-all | unit + integration + e2e |
make cover | -race -covermode=atomic -coverprofile=coverage.out でテスト後、サマリ出力 |
make all | format → test → build → lint を順に実行 |
make devenv-create | kind で tazuna という名前のクラスタを立てる(既存なら context を切り替え) |
make devenv-destroy | kind delete cluster --name tazuna |
KinD クラスタ名は 固定で tazuna、kubeconfig context 名は kind-tazuna です。
e2e は KinD クラスタを前提にしているため、make test-e2e を初めて走らせるときは
内部で make devenv-create が動きます(テスト も参照)。
リポジトリ構成
主要なディレクトリの責務はおおむね次のとおりです。
| パス | 役割 |
|---|---|
main.go | エントリポイント。cmd.Execute() を呼ぶだけ。 |
cmd/ | Cobra のサブコマンド定義(apply / build / check / destroy / state ... / secret-to-genesissecret / tags / version)。 |
cmd/internal/ | サブコマンド間で共有する内部ユーティリティ。 |
api/v1/ | YAML スキーマに対応する Go 構造体定義(tazuna.yaml / tazuna.hint.yaml / GenesisSecret / TestPluginSpec / ORAS)。 |
pkg/runner/ | tazuna apply 全体のオーケストレーション。 |
pkg/manager/ | Manifest type 別の Manager 実装(kustomize / helmfile / genesis_secret / parallel、および oras/ サブパッケージ)。 |
pkg/state/ | State の表現と ConfigMap 永続化。 |
pkg/testplugin/ | WaitUntil / ExistNonExist 実装。 |
pkg/genesissecret/ | Provider インターフェースと 1Password 向け実装。 |
pkg/hint/ | tazuna.hint.yaml のロードと検証。 |
pkg/op/ | op(1Password CLI)の呼び出し。 |
pkg/validator/ | tazuna.yaml のバリデーション。 |
pkg/context/ | context_matches の評価。 |
pkg/prompt/ | 対話入力の抽象(destroy 時の Yes/No など)。 |
pkg/resource/ | 反映時に共通で使う Kubernetes リソース操作ヘルパ。 |
test/e2e/ | E2E テスト本体と fixture (testdata/)。 |
docs/ | このドキュメントサイト。 |
リファレンスでよく出てくる Manager / Runner / Validator などの責務分担は 全体アーキテクチャ を参照すると引き合わせやすいです。
ローカルバイナリで挙動を試す
make build で生成した ./tazuna を直接呼べば、リリース版のかわりに開発中の
バイナリで挙動を試せます。
make build
./tazuna check -f path/to/tazuna.yaml
./tazuna build -f path/to/tazuna.yaml --tags infra
PATH に置きたいときは make install を使います(sudo が必要です)。
KinD で実機検証する場合は make devenv-create でクラスタを立て、
kubectl config use-context kind-tazuna で current-context を切り替えてから動かします。
テスト
Tazuna のテストは unit / integration / e2e の 3 レイヤです。
各レイヤは make ターゲットと 1 対 1 で対応しており、PR で常に動くのは unit
(CI)、e2e は KinD を前提にした手動レイヤです。
レイヤと走らせ方
| レイヤ | コマンド | 対象 | 前提 |
|---|---|---|---|
| unit | make test | go test ./... | なし。GitHub Actions の CI ワークフローで毎 push / PR 時に走る。 |
| integration | make test-integration | go test -tags=integration ./... | なし。build tag integration を付けた追加テストが対象。 |
| e2e | make test-e2e | go test -tags=e2e -count=1 ./test/e2e/... | KinD クラスタ。内部で make build && make devenv-create が走る。 |
| すべて | make test-all | unit → integration → e2e | e2e と同じ |
| カバレッジ | make cover | -race -covermode=atomic -coverprofile=coverage.out で unit を実行、サマリ出力 | なし |
CI(.github/workflows/ci.yaml)では go test -race -covermode=atomic -coverprofile=coverage.out ./...
が走るため、内容は make cover とおおむね一致します。
unit テスト
すべてのパッケージで *_test.go として書かれています。Go の標準的なテストです。
KinD / 外部 CLI に依存せず、go test ./... のみで完結します。
PR レビュー対象になるのはこのレイヤが green であることが大前提です。
integration テスト
build tag integration を付けた追加テストです。make test-integration で実行します。
外部依存はないが、unit テストには重すぎるシナリオを切り分ける場所として使われます。
go test -tags=integration ./... を直接叩いても同じです。
e2e テスト
test/e2e/ に置かれた本物のクラスタを使ったテストです。
build tag e2e で隔離され、./test/e2e/... だけが対象になります。
make test-e2e を実行すると、内部で次が順に走ります。
make build(./tazunaを作る)make devenv-create(KinD クラスタtazunaを立てる、既存なら context を切り替え)go test -tags=e2e -count=1 ./test/e2e/...
-count=1 が付くのは、e2e テストのキャッシュを禁止して毎回実走させるためです。
make devenv-destroy で KinD クラスタは片付きます(kind delete cluster --name tazuna)。
KinD クラスタの仕様
| 項目 | 値 |
|---|---|
| クラスタ名 | tazuna |
| kubeconfig context | kind-tazuna |
| 設定ファイル | .github/kind-config.yaml |
CI 用と開発者ローカル用で同じ KinD 設定を共有しているため、ローカルで通る e2e は 基本的に CI でも通ります。
テストデータ
e2e の fixture は test/e2e/testdata/ 配下にケースごとのディレクトリで置かれています。
tazuna.yaml と、type に対応した実体(kustomize/ / helmfile/ 等)が同居する作りです。
test/e2e/testdata/
├── kustomize-minimal/ # type: kustomize の最小ケース
├── helmfile-minimal/ # type: helmfile の最小ケース
├── parallel-minimal/ # type: parallel
├── testplugin-minimal/ # Test plugin (WaitUntil/ExistNonExist) の基本
├── testplugin-cel/ # WaitUntil の CEL 式が複雑なケース
├── tags-filter-minimal/ # --tags フィルタ
├── state-minimal/ # state list/diff/sync
├── state-modified/ # state diff の "modified" 判定
├── destroy-minimal/ # tazuna destroy
└── check-invalid/ # tazuna check の異常系
新しい機能を入れるときは、対応する fixture ディレクトリを追加し、最小構成の
tazuna.yaml を 1 つ書き、test/e2e/ 配下に *_test.go を追加する流れが一般的です。
lint
make lint
golangci-lint run を呼ぶだけです。golangci-lint のバージョンは mise.toml で
管理しているため、mise install で揃えれば追加の手当ては不要です。
CI でも同じ golangci-lint が走ります。PR を出す前にローカルで通しておくと往復が減ります。
ドキュメント
このページは、Tazuna のドキュメントサイト(いま読んでいるサイト)に変更を入れる人向けの案内です。
サイトは docs/ 配下で完結しており、mdBook +
mdbook-i18n-helpers(gettext / PO ファイル)
で構築しています。
ソースは 日本語 で書き、英語版は po/en.po の翻訳で派生させる構成です。
ディレクトリ構成
docs/
├── book.toml # mdBook の設定
├── src/ # ドキュメント本体(日本語ソース)
│ ├── SUMMARY.md
│ ├── introduction.md
│ ├── concepts/
│ ├── getting-started/
│ ├── guides/
│ ├── operations/
│ ├── reference/
│ └── contributing/
├── po/
│ └── en.po # 英語訳
├── theme/
│ └── fonts.css # Google Fonts (M PLUS U) の上書き
├── static/
│ └── index.html # /en/ と /ja/ をリンクする landing
└── THIRDPARTY.md # フォント等のサードパーティ資産
docs/src/SUMMARY.md がページの目次そのものです。新しいページを追加するときは
ここにも 1 行追記する必要があります(追記漏れがあると mdBook はビルドできても、
そのページはサイトに出ません)。
必要なツール
cargo install mdbook --locked
cargo install mdbook-i18n-helpers --locked
msgmerge(gettext 同梱)は PO の更新で使います。macOS なら brew install gettext。
ローカルでプレビュー
日本語版(ソース言語):
cd docs
mdbook serve --open
英語版:
cd docs
MDBOOK_BOOK__LANGUAGE=en mdbook serve --open
ファイル保存のたびに再ビルドされてブラウザがリロードされます。
ローカルでビルド
cd docs
mdbook build -d book/ja
MDBOOK_BOOK__LANGUAGE=en mdbook build -d book/en
cp static/index.html book/index.html
book/index.html をブラウザで開けば、リンクで /ja/ と /en/ を切り替えられます。
英語訳の更新
docs/src/ 配下の文章を編集したら、PO テンプレートを再生成して en.po に merge します。
cd docs
MDBOOK_OUTPUT__XGETTEXT__POT_FILE=messages.pot \
mdbook build -d po --no-create-missing
msgmerge --update po/en.po po/messages.pot
このあと po/en.po を開いて、追加された msgid に対応する msgstr を埋めます。
ソース側(日本語)と英語訳の対応が崩れているとサイト上で空白や欠落が見えるので、
ソース変更と同じ PR で en.po も更新するのが基本フローです。
デプロイ
.github/workflows/docs.yaml が公開を担当します。
mainへの push: サイトをビルドし、GitHub Pages へ公開する (actions/upload-pages-artifact+actions/deploy-pages)- PR: ビルドのみ。生成物は
github-pagesという名前で workflow run の artifact として ダウンロードできます。ローカルで展開して目で見るのが推奨レビュー手順です。
GitHub Pages は 1 サイトにつき 1 デプロイメントしか持てないため、PR ごとの live プレビュー URL は意図的に提供していません。
サードパーティ資産
サイトは Google Fonts の M PLUS U を
ランタイムでロードしています。フォント / アイコン / 画像など新しい外部資産を入れる場合は、
docs/THIRDPARTY.md
にライセンスと帰属を追記します。
ドキュメント側の規約
ここまでに書いた既存ページが従っている規約を、参考として残しておきます。
- トーンの使い分け: 概念は散文中心(concepts/)、ガイドは「目的→前提→手順」、 リファレンスはフィールド表とコード断片中心。
- アンカーリンク:
glossary や他リファレンスへの導線は
#anchorまで含めて貼る。 例:[Manifest type](../concepts/glossary.md#manifest-type)。 - コードと識別子:
tazuna.yamlのフィールド名、CLI フラグ、Go の型名はバッククォートで囲む。 - 言語ポリシー: ソースは日本語で書く。コード中のコメントは日本語で書いてよいが、 ログ・エラーメッセージ・CLI 出力は英語に統一する(プロジェクト全体の方針)。
リリース
Tazuna のリリースは タグ push をトリガに GitHub Actions が goreleaser を回す
という構成です。リリースを切るときに手元から goreleaser を直接呼ぶ場面は通常ありません。
ここでは「リリースが切られたときに何が起きるか」「バージョン文字列の供給元」 「成果物の検証手段」をまとめます。
トリガと出力
- ワークフロー:
.github/workflows/release.yaml - 起動条件:
push: tags: ["*"](任意のタグ push) - 公開先: GitHub Releases
タグ名はそのまま version 文字列として埋め込まれます。
セマンティックバージョニング(vX.Y.Z)に従うことを推奨します(changelog の自動生成 も参照)。
出力物
.goreleaser.yaml の
ビルド対象は次のとおりです。
| 軸 | 値 |
|---|---|
| GOOS | linux / darwin |
| GOARCH | amd64 / arm64 |
| CGO | CGO_ENABLED=0 |
| ldflags | -s -w -trimpath + バージョン埋め込み |
成果物のアーカイブ名は tazuna_<Os>_<Arch>.tar.gz(amd64 は x86_64 に正規化)で、
リリースには次のものが添付されます。
- 各 OS/arch の
.tar.gz(バイナリ) checksums.txt(SHA256)- 各アーカイブ + ソースの SBOM (
*.sbom.json、SPDX) checksums.txt.sigstore.json(cosign のキーレス署名バンドル)
GitHub Actions の actions/attest-build-provenance
が SLSA build provenance を別途生成し、gh attestation verify で検証できる形に
紐付けます。
バージョン文字列の埋め込み
main.go には次の var が宣言されていて、リリースビルド時に -X で値が注入されます。
var (
version = "dev"
commit = "none"
date = "unknown"
)
.goreleaser.yaml の ldflags で:
-X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}
注入された値は cmd.SetVersionInfo 経由で tazuna version
に表示されます。
go install / make build などローカルビルドの場合は注入されないため、
version / commit / date はそのまま dev / none / unknown になります。
changelog
.goreleaser.yaml の changelog セクションが GitHub Releases の説明文を組み立てます。
- 並び: コミット昇順 (
sort: asc) - 除外:
^docs:/^test:プレフィックスの commit - フォーマット: ヘッダ
## Tazuna {{.Version}}と、フッタに前リリースとの compare リンク
PR のタイトル / commit メッセージ規約は CONTRIBUTING.md / PR テンプレートが基準です。
docs: / test: プレフィックスはリリースノートに出ない ので、プロダクトの動作変更
ではない PR にはこれらを付けると棚卸しがしやすくなります。
成果物の検証
リリースを使う側の検証手段はおおむね 3 つあります。
# 1. checksum の検証
sha256sum -c checksums.txt
# 2. checksums.txt の署名検証(cosign keyless)
cosign verify-blob \
--bundle checksums.txt.sigstore.json \
checksums.txt
# 3. SLSA provenance の検証
gh attestation verify <file> --repo pepabo/tazuna
3 つ目は GitHub CLI 経由で SLSA build provenance を確認する手段です。 リリース直後でも内部 CI でも使えます。
切るときの実務
mainが安定していることを確認する(CI が green)。vX.Y.Z形式のタグを切って push する。Releaseワークフローが走り、Releases が公開されることを確認する。- 必要なら自動生成された changelog を手で整える。
ドキュメントサイトの公開は別ワークフロー(docs.yaml)
で、こちらは main への push をトリガに動きます。リリース切りとは独立しています。