本記事は「Ansible Advent Calendar 2022」の19日目のエントリとなります。
Ansibleで環境変数を参照したりタスク実行時にセットしたりする方法についておさらい。
おさらいして整理してると気付けたけど、「ローカルか、リモートか」でなく、「Ansible本体の実行環境か、マネージドノードのタスクの実行環境か」という区切りで考えるのがポイント。(環境変数に限らず、だけど)
環境変数の参照
コントロールノード(ローカル)の環境変数を参照
大前提として「ルックアップ(lookup
)プラグインはコントロールノードで処理される」という仕様があります。もう少し細かくいうと、(対象がローカルの場合を含むマネージドノード上の)タスクを実行するタイミングでなく、(CLIであれば)ansible-playbook
を実行するノードで処理されます。
このルックアッププラグインの1つで環境変数を参照できるenv
ルックアッププラグインを使えばタスク実行時などにローカルの環境変数を参照できます。
環境変数zzz
をprintするサンプルは以下。
--- - hosts: server tasks: - debug: msg: "{{ lookup('env', 'zzz') }}"
環境変数zzz
にhello
をセットした実行例が以下。
(実行ノードのawx.jp-z.jp
はリモートです)
$ export zzz=hello $ ansible-playbook -i inventory.ini print-env-sample.yml PLAY [server] *************************************************************** TASK [debug] **************************************************************** ok: [awx.jp-z.jp] => { "msg": "hello" } ok: [localhost] => { "msg": "hello" }
ルックアッププラグイン自体の説明はこちら
envルックアッププラグイン
マネージドノード(リモート)の環境変数を参照
ノードのfacts変数のenv
を参照します。具体的にはansible_facts.env
に取得できた環境変数が全てセットされています。(あるいは以前からの書式でansible_env
)
facts変数で環境変数を収集するには、gather_facts
を使用します。(デフォルト有効)
gather_subset
で収集する範囲を限定する場合でも、環境変数はmin
指定でもOKの模様。(明示的にenv
も指定可能)
環境変数USER
をprintするサンプルは以下。
--- - hosts: server gather_facts: true gather_subset: min tasks: - debug: msg: "{{ ansible_facts.env.USER }}"
ansible_connection
でコネクションプラグインlocal
を使ってローカル実行のUSER
はzaki
、リモートはubuntu
という環境での実行例。
以下はデフォルトの状態で実行。ローカル(ansible-playbook
を実行しているノード)はユーザーzaki
で、リモートのawx.jp-z.jp
の実行ユーザーはubuntu
となっている。
$ ansible-playbook -i inventory.ini print-env-sample.yml PLAY [server] *************************************************************** TASK [Gathering Facts] ****************************************************** ok: [localhost] ok: [awx.jp-z.jp] TASK [debug] **************************************************************** ok: [awx.jp-z.jp] => { "msg": "ubuntu" } ok: [localhost] => { "msg": "zaki" }
ここで、実行ノードでexport
を使って環境変数USER
を侑ちゃんに設定して実行してみると以下の通り。
ローカル実行のタスクのみ内容が更新されており、ansible_facts
で収集したリモートの環境変数には影響してないことを確認できます。
$ export USER=yu-chan $ ansible-playbook -i inventory.ini print-env-sample.yml PLAY [server] *************************************************************** TASK [Gathering Facts] ****************************************************** ok: [localhost] ok: [awx.jp-z.jp] TASK [debug] **************************************************************** ok: [awx.jp-z.jp] => { "msg": "ubuntu" } ok: [localhost] => { "msg": "yu-chan" }
ただしexport
を使ったローカルのこの動作は「コネクションプラグインでlocal
を指定した場合」の話。ssh
を使ってローカルホストに接続した場合は「export
を使って使用中のシェルに一時的に設定した環境変数」は維持されないため、ログイン時にセットされるデフォルトの環境変数となります。
上記例ではプレイでfacts変数を収集するgather_facts
を指定していますが、1つのタスクとしてfacts変数を収集することも可能。
環境変数の指定
タスクの実行時にモジュールで使用する値として環境変数を設定するにはenvironment
ディレクティブを使用します。
指定方法は以前作成した以下も参照。
全タスクで使用するにはプレイに、タスク単体で使用するには(環境変数を使用するのが一つのタスクのみ、等)タスクと、要件にあわせて指定箇所を変更してスコープを調整できます。
記述例として、環境変数zzz
の値としてhello
をプレイにセットする場合は以下の通り。
- hosts: server environment: zzz: hello
実行例
--- - hosts: server gather_facts: true gather_subset: - min environment: zzz: hello tasks: - debug: msg: "{{ lookup('env', 'zzz') }}" - debug: msg: "{{ ansible_facts.env.zzz }}"
実行結果は以下の通り。
TASK [debug] **************************************************************** ok: [awx.jp-z.jp] => { "msg": "" } ok: [localhost] => { "msg": "" } TASK [debug] **************************************************************** ok: [awx.jp-z.jp] => { "msg": "hello" } ok: [localhost] => { "msg": "hello" }
environment
ディレクティブは「タスク実行の際に環境変数を付与」する動きになるため、マネージドノード上でのタスクの実行元となるコントロールノードのAnsibleプロセスの実行には影響しない。そのため、ルックアッププラグインでは参照できないのが確認できます。(説明が難しい…伝われ…)
使いどころとしては、クラウドサービスのアクセスキーとシークレットキーや、AAPのようなミドルウェアの接続情報など、複数タスクで共通して使用する値。モジュールのパラメタだけでなく環境変数を使用することで、プレイブックの記述量を減らして可読性を上げることができます。
- hosts: aap remote_user: ec2-user gather_facts: false environment: CONTROLLER_USERNAME: admin CONTROLLER_PASSWORD: "{{ password }}" CONTROLLER_VERIFY_SSL: false
使用するモジュールで環境変数が使用可能どうかはまとまった情報があるわけでなく、各モジュールのパラメタ等に「環境変数でも指定可能」のように書かれているのを確認する。(しかない、と思う)
例えばAAPやAWXのホスト情報を編集するawx_hostモジュール
(というかAWX関連の各モジュール)は、パラメタ毎に以下のような記載がある。
If value not set, will try environment variable
CONTROLLER_HOST
and then config files
https://docs.ansible.com/ansible/latest/collections/awx/awx/host_module.html
AWSであればガイドのAuthenticationの項に以下の記載あり。
Authentication with the AWS-related modules is handled by either specifying your access and secret key as ENV variables or module arguments.
For environment variables:
export AWS_ACCESS_KEY_ID='AK123' export AWS_SECRET_ACCESS_KEY='abc123'
参考
Ansibleドキュメント
過去ブログ
まとめ
- コントロールノードの環境変数を参照するには
env
ルックアッププラグイン - マネージドノードの環境変数を参照するにはfacts変数を収集
- タスクに環境変数をセットするには
environment
ディレクティブ - ルックアッププラグインが作用するのはAnsibleを実行するコントロールノード
environment
ディレクティブが作用するのはタスクを実行するマネージドノード
昔よくやってた(今でも多分やってるかも)けど、コントロールノードの実行ユーザーとマネージドノードのユーザーが同一だと、「処理対象ノードのホームディレクトリ以下の〇〇で□□するタスク」とかで、ついenv
ルックアッププラグイン使ってホームディレクトリを取得してちゃんと動いたように見えてたけど、あれ本当は誤りなんだよね。。