TT Lab
はじめる
学ぶ 学習パス コース

Ansible基礎

インベントリ — 自動化の住所録

TT Labで続きを見る

一言でいうと

Ansibleは、「何をするか」よりも「誰に対して行うか」を先に問います。その答えがインベントリです。

なぜ必要なのか

サーバーが3台のときは、ターミナルを3つ開けば済みます。7台になると、ウィンドウを間違えて選ぶ事故が起きます。ホームラボを3ノードから7ノードに増やした記録を見ると、ノードを追加する手順自体は難しくないのですが、「どのノードに何をしたのか」を人が記憶した瞬間から、ミスが始まります。実際に、新しく追加した2つのノードには、以前のクラスターの残骸(古いバージョンのkubelet、古い証明書)が残っていて、それを片付ける手順を手作業で行っていると、1台は見落とします。

インベントリは、この問題を「リストをファイルにする」ことで解決します。ファイルに書かれていないサーバーは自動化の対象ではなく、ファイルに書かれたサーバーはすべて同じ扱いを受けます。この単純なルールが、「1台だけ設定が違う」状況を構造的になくします。

どう動くのか

インベントリには、3つの要素が含まれます。

要素 何か 例
ホスト 接続する対象1つ web1
グループ ホストのまとまり [web]、[db]
変数 ホスト/グループに付随する値 ansible_port=2222、app_port=8080

核心は、グループが階層をなすという点です。[prod:children]の下にwebとdbを入れると、prodは2つのグループのすべてのホストを含みます。そして、すべてのホストは、自動的にallグループに属します。変数は上から下へ流れますが、より狭い範囲が勝ちます。allの値よりグループの値が、グループの値よりホストの値が優先されます。

形式は、INIとYAMLの2つです。INIは短くて手で書きやすく、YAMLは入れ子構造や複雑な変数を扱いやすいです。どちらを使っても、ansible-inventory --listで出力してみれば、結局同じJSONになります。インベントリを疑うときは、ファイルをにらみつけず、このコマンドで実際の解釈結果を見てください。タイプミス1つでグループがまるごと空になっていることを、3秒でわかります。

現場での姿

1つ目は、「なぜ1台だけうまくいかなかったのか」という状況です。対象を絞り込むときに、--limitを使わず、インベントリからホストを一時的に削除する人がいます。すると、そのファイルがそのままコミットされて、数日後にそのサーバーだけがパッチから漏れます。対象の絞り込みは、インベントリではなく、実行オプションで行います。

2つ目は、接続情報も変数だということです。ansible_host、ansible_port、ansible_userは、特別な変数のように見えますが、ただの変数です。そのため、ジャンプホストや非標準ポートのような環境の違いを、コードを変更せずにインベントリで吸収できます。このラボ環境でも、sshdが127.0.0.1:2222で起動しているので、ansible_portでその違いを扱います。

3つ目は、動的インベントリです。クラウドではサーバーの一覧が毎日変わるので、ファイルの代わりにスクリプトが一覧を作ります。それでも概念は同じです。グループと変数を含むJSONを作ってくれるだけです。静的インベントリをきちんと理解すれば、動的インベントリは、出力形式が違うだけの同じものです。

変数をどこに置くのか

インベントリファイルの中に変数をたくさん書くと、すぐに読みにくくなります。そのため、実務では変数を別のディレクトリに切り出します。インベントリの隣にgroup_vars/とhost_vars/を置くと、group_vars/web.ymlはwebグループ全体に、host_vars/web1.ymlはそのホスト1台に適用されます。ファイル名がそのまま適用範囲なので、どこを直せばよいのか迷うことがありません。

優先順位は、先ほど見たとおり、狭いほうが勝ちます。ただし、実際の順序はそれより長く、よくぶつかるものだけを整理すると、次のとおりです。

  1. コマンドラインの-e(最も強い)
  2. タスクやブロックに直接書いた値
  3. host_vars/
  4. group_vars/(子グループが親グループに勝つ)
  5. group_vars/all
  6. ロールのデフォルト値(defaults/、最も弱い)

ロールのデフォルト値が最も弱いのは、意図された設計です。ロールは「この値がなければ、こうする」を書く場所であり、それを使う側が、常にオーバーライドできなければなりません。逆に、ロール内のvars/ははるかに強く、オーバーライドしにくいので、本当に変わってはいけないものにだけ使います。

ここに、実務のルールを1つ加えます。シークレットは、インベントリに平文で置きません。リポジトリにコミットされた瞬間に元に戻せず、削除しても履歴に残ります。暗号化された変数ファイルや、外部のシークレットストアから取得する方式を使いますが、どちらの場合でも、シークレットでない値とファイルを分けておくほうがよいです。1つのファイルに混在していると、ごく普通の設定を1つ直すために毎回暗号を解かなければならず、そうしているうちに、結局誰も暗号化を使わなくなります。

次のラボですること

/root/ans/inventory/hosts.iniにweb・dbグループと、prodという上位グループを作成し、同じ構造をYAMLでも表現します。次に、アドホックコマンドで3つのホストに一度に接続し、--limitで対象を絞り込んでみます。最後に、インベントリをJSONで出力して、グループごとのホストのレポートを作成します。