変数の優先順位とファクトの扱い
目標
値をコードから分離して複数の場所に配置し、そのうち何が勝つのかを自分で確認します。ファクトとregisterで、実行中に得た値も扱います。
なぜ重要なのか
「変数を変えたのに反映されない」という質問の答えは、ほとんどの場合、優先順位です。Ansibleは、同じ名前の変数を複数の場所から受け付け、衝突してもエラーを出さず、静かにより強いほうを使います。この性質は便利ですが、デバッグを難しくします。そのため、オーバーライドされてもよい値は弱い場所(ロールのdefaults)に、必ず守るべき値は強い場所に置くという、設計の感覚が必要です。コマンドラインの-eは何にでも勝ちますが、どこにも記録されないので、障害対応で使ったなら、必ずコードに戻しておく必要があります。そうしないと、次のデプロイが静かにその値を消します。
ステップ
/root/ans/vars/site.ymlを作成して、プレイのvars:にapp_name: checkoutを定義してください。その値を/root/ans/vars/out/app_name.txtに書いてください。/root/ans/vars/vars/common.ymlにapp_port: 9090を置き、vars_filesで読み込んでください。値を/root/ans/vars/out/app_port.txtに書いてください。/root/ans/inventory/group_vars/web.ymlにnode_role: frontendを、/root/ans/inventory/host_vars/web1.ymlにnode_role: canaryを置いてください。2つのディレクトリは、最初のラボで作成した/root/ans/inventory/hosts.iniと同じ場所にある必要があり、そうすれば自動的に読み込まれます。web2ではfrontendとして、web1ではcanaryとして見える必要があります。- コマンドを実行して、
registerで結果を受け取ったあと、標準出力だけを/root/ans/vars/out/uptime.txtに保存してください。 gather_factsをオンにして、収集されたファクトのうち、ホスト名・アーキテクチャ・システムを含むJSONを、/root/ans/vars/out/facts.jsonとして保存してください。-e app_port=9999で実行して、その値を/root/ans/vars/out/precedence.txtに保存してください。ステップ2で作成したapp_port.txtは、9090のままである必要があります。set_factで、app_nameとapp_portを連結した値を作成し、/root/ans/vars/out/endpoint.txtに、checkout:9090の形で保存してください。/root/ans/vars/out/summary.jsonを作成してください。app(=checkout)、port(=9090)、role(web1のホスト変数の値)、host(収集したファクトのホスト名)の4つのキーを持つ必要があります。
参考
- ラボのPodは、ラボごとに新しく起動します。
/root/ans/inventory/hosts.iniがなければ、最初のラボで作成したものと同じインベントリ(web1・web2・db1、ansible_host=127.0.0.1、ansible_port=2222、ansible_user=root、[prod:children]にweb・db)を、先に作り直してください。構造は、/opt/lab/fixtures/ansible/inventory.sample.iniを参考にすればよいです。 ansible-inventory -i /root/ans/inventory/hosts.ini --listで、グループ/ホスト変数が実際にどのようにマージされたかを見られます。debugモジュールのvar:で、特定の変数の最終的な値を、すぐに確認できます。- よくある間違い1: ステップ4で、registerのオブジェクト全体をファイルに書いてしまうことです。
.stdoutだけが必要です。 - よくある間違い2: ステップ6で、同じファイルを上書きして、前のステップの結果を失ってしまうことです。ステップごとに、別のファイルに残してください。
プレイ変数を定義して使う
/root/ans/vars/site.ymlを作成して、プレイのvars:にapp_name: checkoutを定義してください。その値を/root/ans/vars/out/app_name.txtに書いてください。
プレイのvars:の下に値を置き、copyモジュールのcontentで、Jinja2を使って参照してください。
変数ファイルを分離する
/root/ans/vars/vars/common.ymlにapp_port: 9090を置き、vars_filesで読み込んでください。値を/root/ans/vars/out/app_port.txtに書いてください。
vars_files:は、パスのリストです。値が増えたら、プレイから切り出すのが慣例です。
グループ変数とホスト変数を作成する
/root/ans/inventory/group_vars/web.ymlにnode_role: frontendを、/root/ans/inventory/host_vars/web1.ymlにnode_role: canaryを置いてください。2つのディレクトリは、最初のラボで作成した/root/ans/inventory/hosts.iniと同じ場所にある必要があり、そうすれば自動的に読み込まれます。web2ではfrontendとして、web1ではcanaryとして見える必要があります。
ディレクトリ名がそのままルールです。group_varsの下のファイル名はグループ名、host_varsの下はホスト名です。
コマンドの結果を変数に格納する
コマンドを実行して、registerで結果を受け取ったあと、標準出力だけを/root/ans/vars/out/uptime.txtに保存してください。
registerで受け取ったものは、オブジェクトです。ファイルには、そのうち標準出力だけを入れてください。
ファクトを収集してJSONで残す
gather_factsをオンにして、収集されたファクトのうち、ホスト名・アーキテクチャ・システムを含むJSONを、/root/ans/vars/out/facts.jsonとして保存してください。
gather_factsをオンにして、ansible_factsの一部を選び、JSONで書きます。to_nice_jsonフィルターが役に立ちます。
コマンドライン変数でオーバーライドする
-e app_port=9999で実行して、その値を/root/ans/vars/out/precedence.txtに保存してください。ステップ2で作成したapp_port.txtは、9090のままである必要があります。
-eで渡した値が最も強いです。前のステップで保存したファイルは上書きせず、別の名前で残してください。
set_factで値を組み合わせる
set_factで、app_nameとapp_portを連結した値を作成し、/root/ans/vars/out/endpoint.txtに、checkout:9090の形で保存してください。
2つの変数を連結した新しい値を作成して、ファイルに書きます。形式は、이름:포트です(プレースホルダーは名前とポートです)。
変数・ファクト・ホスト変数を合わせた要約を作成する
/root/ans/vars/out/summary.jsonを作成してください。app(=checkout)、port(=9090)、role(web1のホスト変数の値)、host(収集したファクトのホスト名)の4つのキーを持つ必要があります。
4つのキー(app、port、role、host)を持つJSONを作成します。roleはweb1のホスト変数、hostは収集したファクトから取得します。