1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Playbook を後から整理しやすくする、Ansible の最初の設計

1
Posted at

はじめに

Playbook を後から整理しやすくする、Ansible の最初の設計_qiita.png

Ansible は YAML で書けます。
そのため、最初はどうしても「まず Playbook を書いて動かす」「設計や文書は後で考える」という流れになりがちです。

ただ、実務で運用を続けると、別の問題が出てきます。
Playbook は動いているのに、どこに何を書くべきかが人によって違う。inventorygroup_varshost_vars の責務が曖昧になる。role の切り方が揺れる。秘密情報や環境差分の扱いが後回しになる。テストや移行の考え方が実装後にしか出てこない。

この記事は個別案件の振り返りではなく、Ansible / Playbook を最初からどう設計しておくと、後で整理しやすく、保守しやすく、横展開しやすいかを整理するものです。

本記事で整理すること

この記事で整理したいのは、次の 3 点です。

  • Ansible のベストプラクティスを、ディレクトリ構造だけでなく設計全体として捉えること
  • 一般的なコード仕様書やコード設計を、Ansible では何に対応させるとよいか
  • Playbook を書く前に、どの文書と設計観点を固定しておくと後で整理しやすいか

先に結論を置くと

Ansible は「設定を YAML で書く道具」ではなく、「自動化の設計をコードとして表現する道具」として扱った方がうまくいきます。
最初に仕様書、設計書、変数方針、テスト方針、運用方針を持っておくと、Playbook は後からかなり整理しやすくなります。

言い換えると、後から整理しやすい Playbook は、最初から「書き方」だけでなく「置き方」「分け方」「試し方」まで決まっています。

なお、この記事では次の 3 つを意識して書き分けます。

  • 公式ドキュメントに書かれていること
  • そこから読み取れる実務上の推論
  • そのうえでの私の推奨

動画解説

記事内容を動画にして解説しています。

Playbook を書くときに先に考えておきたい5つのこと

Playbook を書き始める前に考えておくべき論点は、意外と少数に畳めます。

  1. entry point をどう分けるか
  2. inventory と variables をどこまで分離するか
  3. roles をどう切るか
  4. secret と環境差分をどう扱うか
  5. テストと移行をどこで設計するか

1. entry point をどう分けるか

公式の Playbooks guide は、playbook を automation blueprint として扱っています。
つまり、Playbook は単なる処理列ではなく、「何を実行の入口にするか」を設計する場所です。

ここでいう entry point は、要するに「人が最初に叩く Playbook」のことです。
アプリでいう main 関数や、Web アプリでいう最初の URL に近いイメージです。

たとえば、全部を 1 本の site.yml から動かすのか、
「OS 初期設定」「ミドルウェア設定」「監視設定」のように入口を分けるのか、という話です。

最初に決めておきたいのは、次のような点です。

  • site.yml のような全体入口を持つのか
  • 機能別やレイヤ別に分けるのか
  • 環境別に playbook を分けるのか
  • タグで切るのか、entry point 自体を分けるのか

ここが曖昧だと、あとから Playbook が増えたときに「どれが正本か」が見えにくくなります。

最低限、次の 3 つは固定しておくと後で楽です。

  • 正本となる entry point はどれか
  • 環境差分は inventory で吸うのか playbook で分けるのか
  • 日常運用で人が実行する入口は何個に抑えるか

2. inventory と variables をどこまで分離するか

Ansible の公式は inventory を、単なるホスト一覧ではなく、グループ、ディレクトリ、group_varshost_vars を含めた構造として説明しています。
さらに variables では precedence がかなり細かく定義されていて、同じ名前の値を複数の場所に置くと、最後は「どこで上書きされたのか」を追う話になります。

inventory は、ざっくり言うと「どのサーバー群に適用するかを決める台帳」です。
group_vars はグループ共通の値、host_vars はそのホストだけの値、と考えると最初は理解しやすいです。

たとえば、dev 全体で共通の DNS 設定は group_vars
app01 だけが持つ IP やホスト名は host_vars、という分け方です。

公式も、変数の置き場所についてはチームのガイドラインを決めて、できるだけ単純に保つことを勧めています。

precedence は変数の優先順位のことです。
難しく聞こえますが、「同じ名前の変数を複数の場所に置いたとき、最後にどれが勝つか」というルールだと思えば十分です。

つまり、最初に決めるべきなのは「変数が置ける場所」ではなく、「何の種類の値をどこに置くか」です。

たとえば次のような線引きを先に決めておくと崩れにくいです。

  • role のデフォルト値は defaults
  • 環境共通値は group_vars
  • 個体差は host_vars
  • 一時的な切替や実行時だけの値は extra_vars

3. roles をどう切るか

Roles の公式文書は、role に既知のディレクトリ構造があることを前提にしています。
taskshandlersdefaultsmetatemplates といった分割は、単なる作法ではなく、責務の分離そのものです。

role は、ざっくり言うと「同じ目的の設定をまとめた部品」です。
たとえば NTP 設定、ユーザー作成、SSH 設定のように、目的ごとにまとめた単位だと思うと分かりやすいです。

逆に、1 つの role の中に「ユーザー作成」「NTP」「DNS」「Apache 設定」が全部入っていると、
便利そうに見えて、あとから直すときにどこまで影響するかが分かりにくくなります。

role を task の寄せ集めとして切ると、あとから再利用しづらくなります。
逆に、責務単位で切って meta/main.yml や依存関係まで含めて設計しておくと、role は「整理しやすい単位」になります。

ここで大事なのは、role を「何を変更する単位か」で切ることです。
OS 初期設定、NTP、DNS、ユーザー管理、ミドルウェア設定のように責務で切ると、レビューもしやすくなります。

4. secret と環境差分をどう扱うか

Ansible Vault は重要ですが、Vault だけで設計は終わりません。
公式も、Vault が守るのは data at rest だけであり、復号後の扱いは play や plugin の設計側で気をつける必要があると警告しています。

Vault は、ひとことで言うと「Ansible 用の暗号化された変数ファイル」です。
ただし、暗号化したからすべて安全、ではなく、ログや diff に出してしまうと普通に見えてしまうことがあります。

つまり、秘密情報の設計は「ファイルを暗号化する」だけではなく、
「どこに置くか」「誰が見るか」「実行ログに出ないか」まで含めて考える必要があります。

つまり、実務では次を最初に決めるべきです。

  • 何を Vault 対象にするか
  • 何を平文で設計書に書かないか
  • no_log をどこで使うか
  • diff を見せてよい値と隠すべき値をどう分けるか

秘密情報は「暗号化するかどうか」より、「どこまで見せてよいか」を先に決めた方が事故りにくいです。

5. テストと移行をどこで設計するか

公式の check mode / diff mode 文書は、これらを Playbook や role を作成・編集するときの検証手段として説明しています。
Testing strategies でも、テストは deployment workflow に組み込むべきだとしていて、開発、staging、本番で同じ playbook を使いながら検証を積み上げる流れが示されています。

--check は「実際には変更しないで、何が変わるかを見る」実行です。
--diff は「どこが変わるかの差分を見る」実行です。
staging は本番の前に試す検証環境、migration は既存運用から新しい運用へ切り替える手順、と考えると読みやすいです。

たとえば、いきなり本番に当てるのではなく、
まず --check で確認し、次に staging で実際に試し、それから本番に流す、という順番です。

つまり、テストは実装後に足すものではなく、実装前に置くべき設計です。

少なくとも次は最初に決めておくとよいです。

  • 保存前に何を lint するか
  • 変更前に何を --check するか
  • 差分確認をどこまで --diff で見るか
  • staging と本番の承認境界をどこに置くか

要するに

Playbook を後から整理しやすくしたいなら、最初に設計すべきなのは YAML の書き方よりも、入口、変数、責務、秘密情報、検証、移行の 6 軸です。

最初に決めること 決めないまま進むと起きやすいこと
entry point どの Playbook が正本か分かりにくい
inventory / vars の分離 値の住所がぶれて探しづらい
role の責務 再利用しづらくレビューしづらい
secret 方針 平文混入やログ露出が起きやすい
test / migration 本番前の確認が属人的になる

Ansible をコードとして見ると、何を設計すべきか

一般的なソフトウェア開発で設計対象になるものは、Ansible でもほぼそのまま存在します。

playbook は entry point 設計

どの playbook がどの対象を自動化し、どこまでを責務とするのか。
これはアプリケーションでいうエントリポイント設計に近いです。

inventory は環境設計

公式の sample setup も、環境ごとの inventory、group_varshost_vars、トップレベル playbook を分けています。
inventory は「接続先一覧」ではなく、環境、グループ、親子関係、適用範囲の設計です。

つまり inventory は、サーバー一覧表というより「この Playbook をどの単位で当てるかを決める設計図」に近いです。

ここが整理されていると、
「dev 全体に当てたいのか」「監視系だけに当てたいのか」「この 1 台だけに当てたいのか」が迷いにくくなります。

variables はデータ設計

どの値を defaults に置き、どの値を group_vars に置き、どの値を host_varsvars_files に置くか。
これはほぼデータモデル設計です。

最初は難しく見えますが、要するに「設定値の住所を決める話」です。
この住所が決まっていないと、あとで値を探すだけでつらくなります。

初学者向けに言い換えると、
「設定値にラベルを貼って、どの棚にしまうかを先に決める」という感覚です。

roles は責務分割

role は再利用できる task 置き場ではなく、責務のまとまりです。
ここを最初から意識して切ると、role catalog を作りやすくなります。

vault はセキュリティ設計

Vault を入れれば安心、ではなく、秘密情報の所在と露出境界を決める必要があります。
これはセキュリティ設計です。

lint / check / diff / staging は検証設計

ansible-lint--syntax-check--check--diff、staging 適用をどうつなぐか。
これも設計の一部です。

ansible-lint は、Ansible らしい書き方や危ない書き方をチェックするツールです。
プログラムでいう linter とほぼ同じです。

つまり、「書いたあとに気合いで確認する」のではなく、
「どの段階でどの確認を通すか」を先に決めておく、という話です。

runbook / migration / rollback は運用設計

どの playbook をどの順序で、どの inventory で、どのタグ付きで実行するのか。
異常時にどこまで戻すのか。
ここまで入って初めて、運用可能な Playbook 群になります。

runbook は「運用手順書」、rollback は「うまくいかなかったときにどこまで戻すか」の手順です。
本番で使うなら、この部分が最後にかなり効きます。

特に、実装者以外が回す場面では、
この runbook があるかないかで「安心して触れるか」がかなり変わります。

Ansible のベストプラクティスは「書き方」だけでは足りない

Ansible のベストプラクティスをディレクトリ構造の話だけに閉じると、実務では足りません。

ディレクトリ構造のベストプラクティス

公式の sample setup や roles 文書は、inventory、roles、vars、playbooks を分けた構造を示しています。
これは重要ですが、重要なのは「その構造がなぜ保守しやすいか」です。

構造を分ける意味は、責務を混ぜないことにあります。

雑に言えば、
「サーバー一覧の話」と「設定値の話」と「処理本体の話」を同じファイルや同じ場所に押し込まない、ということです。

変数の置き場と precedence の考え方

公式は precedence をかなり細かく定義しています。
ただ、実務の本質は precedence を覚えることではなく、同じ値をあちこちに置かないことです。

つまり、ベストプラクティスは「優先順位を暗記すること」より「優先順位で悩まない置き方を決めること」にあります。

FQCN、idempotency、lint を含む実装規律

Ansible は desired state を記述する道具です。
だから、state を記述できるところで shell に逃げない、何度流しても同じ状態になる、lint で基本的な規律を守る、といった実装規律が効いてきます。

FQCN は ansible.builtin.copy のような正式なモジュール名です。
idempotency は「何回流しても結果が安定すること」です。
この 2 つは、初学者でも早めに知っておくと後でかなり効きます。

たとえば、1 回目だけ成功して 2 回目で壊れる Playbook は運用でかなり困ります。
だから「もう一度流しても同じ結果になるか」は、最初から意識する価値があります。

role 再利用を前提にした責務の切り方

role を再利用したいなら、「何をする role か」「何を input とし」「何を output とするか」が見える必要があります。
その意味で、role 設計はコード設計そのものです。

最初から持っておくと強い文書セット

ここは少し大事なので先に明確にしておきます。
Ansible の公式ドキュメントが、これから挙げる文書名をそのまま推奨しているわけではありません。

公式が示しているのは、playbooksinventoryvariablesrolesvaulttestingconfiguration といった責務の分かれ方です。
以下の文書セットは、その責務を実務で扱いやすくするために私が推奨しているものです。

requirements-spec.md

何を自動化するのか、対象環境、対象ホスト、対象外、完了条件、制約を書く文書です。

ここで「何をやらないか」まで固定しておくと、Playbook が肥大化しにくくなります。

初学者向けには、「この Playbook が何の仕事をするのかを一文で言えるようにする文書」と考えると分かりやすいです。

basic-design.md

inventory、roles、playbook、vars、plugins、tests の責務分割を定義します。

実務では「どこに何を書くかの地図」になる文書です。
最初に迷う人ほど、この地図があると楽になります。

最初にプロジェクトの全体図を 1 枚でも持っておくと、
あとから新しい人が入っても理解コストが下がります。

detailed-design.md

entry point ごとの目的、対象 hosts、呼び出す role、入力と出力を書きます。

あとから playbook の本数が増えても迷いにくいのは、この文書があるときです。
「この Playbook は何のためにあるのか」を短く説明できる状態を作る文書、と考えると分かりやすいです。

data-model.md

変数設計書です。
どの値をどこへ置くかを定義します。

Ansible ではこの文書が薄いと、変数 precedence の事故が起きやすくなります。

「この値はどこに置くのが正しいのか」を毎回会話で決める状態を避けるための文書、と考えるとよいです。

inventory-design.md

環境、グループ、親子関係、命名規約、適用範囲を定義します。

インフラ案件では、実質的に「環境構成図のテキスト版」に近い役割を持ちます。

図だけだと更新されなくなることがあるので、テキストで残す意味は大きいです。

role-catalog.md

role 名、責務、主要 input vars、handler、依存 role を整理します。

これは role の README を一覧化したような文書です。
部品一覧表のようなものだと思えば十分です。

セキュリティ / Vault 方針書

秘密値の扱い、Vault 対象、平文禁止対象、no_log や diff 方針を定義します。

セキュリティレビューや運用引継ぎでも効く文書です。

test-plan.md

ansible-lint--syntax-check--check--diff、staging、基本 health check の順序を定義します。

「何を通ったら次へ進めるか」を決めるゲート文書として使えます。

実務では、この文書があるだけで「いきなり本番へ行く空気」をかなり抑えられます。

migration-plan.md

既存運用から切り替える場合の段階、承認ポイント、戻し条件を定義します。

既存運用がある案件では、この文書がないと改修可否の議論が感覚論になりやすいです。

operations-runbook.md

どの playbook をどう実行するかを運用手順として固定します。

実装者以外が運用するなら、最後に効いてくるのはこの文書です。

自分が半年後に見返しても助かるのは、だいたいこの手の文書です。

複数人で扱うなら、ここに運用文書が増える

ここからは個人で書く場合より一段だけチーム寄りの話です。
ここでも、Ansible の公式が次の文書名を直接規定しているわけではありません。

ただ、公式は version control、repository guideline、testing requirement、branch/PR 前提の運用を各所で示しています。
そこから考えると、複数人で扱うときは「書き方」だけでなく「変更の仕方」と「レビューの仕方」を共有する文書が増えます。

私なら、個人向けの文書セットに加えて次を置きます。

contribution-guide.md

どの単位で変更し、どのブランチで作業し、どのテストを通してからレビューへ出すかを決める文書です。

review-checklist.md

変数の置き場、secret の混入、role の責務、影響範囲、check / diff / staging 実施有無など、レビュー時に最低限見る項目をそろえる文書です。

ownership-map.md

inventory、roles、runbook、test のどこを誰が責任を持つかを明確にする文書です。

change-log.md

何を変えたか、どこに影響するか、戻し方はどうするかを追いやすくする文書です。

glossary.md

playbook、role、inventory group、baseline、runbook のような言葉の意味をそろえる文書です。

naming-convention.md

playbook 名、role 名、inventory group 名、variable 名の付け方をそろえる文書です。

テスト証跡テンプレート

ansible-lint--check--diff、staging、molecule などの結果をどう残すかをそろえる文書です。

要するに、個人運用では「自分が分かっている」で済む部分が、チーム運用では文書として必要になる、ということです。

観点 個人で扱うとき 複数人で扱うとき
変更管理 自分の判断で進めやすい 変更ルールと PR 単位が必要
レビュー 頭の中で済みやすい checklist が必要
責任分界 曖昧でも回りやすい ownership が必要
用語 何となく通じる glossary や命名規約が効く
テスト結果 手元確認で済みやすい 証跡の残し方をそろえた方が安全

コード仕様書とコード設計は、Ansible ではどう置き換わるか

一般的なコード案件で考えると、Ansible の文書は次のように対応づけると理解しやすいです。

ソフトウェア開発側 Ansible 側
要件定義 requirements-spec.md
基本設計 basic-design.md
詳細設計 detailed-design.md
データ設計 data-model.md
構成設計 inventory-design.md
モジュール設計 role-catalog.md
セキュリティ設計 セキュリティ / Vault 方針書
テスト設計 test-plan.md
移行計画 migration-plan.md
運用手順書 operations-runbook.md

ここまで見えると、Ansible を「コードではないから設計書はいらない」とは言いにくくなるはずです。

むしろ、設定変更がそのまま本番環境へ効くからこそ、通常のコード案件以上に設計の明文化が効く場面もあります。

アプリよりも「書いたものがそのまま環境へ効く」距離が近いので、
その意味では、Ansible の方が先に設計を言語化しておく価値が高いとも言えます。

この設計を最初に置くと何が楽になるか

保守しやすくなる

どこに何を書くかの基準が見えるので、あとから読んでも迷いにくくなります。

設計台帳や管理資料とつなぎやすくなる

変数、inventory、role、運用手順が文書として分かれていれば、設計台帳やスプレッドシート、別形式の管理資料にも反映先を切り分けやすくなります。

別案件の Playbook に横展開しやすくなる

案件固有の名前ではなく、文書の粒度で再利用できるからです。

移行やレビューの基準を共有しやすくなる

レビューが「好み」ではなく、設計と方針に照らしてできるようになります。

これは、レビュー観点を人ではなく文書へ寄せられるという意味でも大きいです。

チームでも動きやすくなる

複数人で触るときも、変更ルール、ownership、レビュー観点を後付けで作らずに済みます。
特に、inventory と role の責任分界、命名規約、テスト結果の残し方は、早めに決めた方が後で効きます。

実務ではどう始めるのがよいか

最後に、着手順を 4 段階にまとめます。

  1. まず要件と基本設計を固定する
  2. 次に inventory / vars / roles の責務を決める
  3. 実装前にテスト方針と移行方針を決める
  4. 実装後ではなく、実装前に runbook を持つ

ここまで決めてから Playbook を書き始めると、あとから整理するときの負債がかなり減ります。

全部を最初から完璧にそろえる必要はありません。
ただ、少なくとも「入口」「変数」「role」「秘密情報」「テスト」「運用」の 6 軸は、実装前に一度言語化しておく価値があります。

最初は Markdown 1 枚ずつでも十分です。
大事なのは完成度より、「後で迷う論点を先に言葉にしておくこと」です。

まとめ

Ansible のベストプラクティスは、YAML の書き方だけでは完結しません。
Playbook を後から整理しやすくしたいなら、最初に設計の粒度を決めて、仕様書、設計書、変数方針、テスト方針、運用方針まで含めて扱う方が強いです。

Playbook は動けば終わり、ではなく、後で整理しやすいように最初から設計する。
この記事で言いたかったのは、その一点です。

参考リンク

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?