こんにちは。 バックエンドエンジニア / SRE のまのめです。
くらしのマーケットのデプロイには、 Ansible が採用されています。
Ansible では、実行したコマンドの結果などを変数に入れる register
というキーワードがあります。
小ネタですが、この register
で本番デプロイ時にハマったので、そのことを書いていきます。
問題の Task
やりたかったことは、以下のような処理です。
もし env が prod なら本番環境用の 設定値 を、
そうではなく env が kaizen なら 改善環境用の 設定値 を
AWS の Parameter Store から取ってきて、register する
これを愚直に playbook に起こすと、以下のようになります。
- name: Set Prod Config command: aws ssm get-parameters --region ap-northeast-1 --name prod.config --query Parameters[0].Value --output text register: config when: "env == 'prod'" - name: Set Kaizen Config command: aws ssm get-parameters --region ap-northeast-1 --name kaizen.config --query Parameters[0].Value --output text register: config when: "env == 'kaizen'" - name: Print Result command: "echo '{{ config.stdout }}'"
※ Print している箇所は、実際は template に render するなどしています。
さて、結果はどうなるでしょうか。
- 改善環境(
env = 'kaizen'
): 改善環境用の設定値がセットされる - 本番環境(
env = 'prod'
):dict object has no attribute stdout
という エラー
本番デプロイ中だというのに、困りました。
原因
先程の例で、 env = 'prod'
のとき、config に register されていたものは、以下のような dict です。
"msg": { "changed": false, "skip_reason": "Conditional result was False", "skipped": true }
condition が false になるパターンは env == 'kaizen'
の場合ですね。
register がスキップされたのではなく、「評価されて false になった」という内容が register されて上書きされてしまっていました。
つまり記事タイトルのとおりですが、Ansible の register は when によってスキップできないようです。
ドキュメントにも書いてありました。
If a task fails or is skipped, Ansible still registers a variable with a failure or skipped status, unless the task is skipped based on tags.
Using Variables / Ansible Documentation
回避策
この箇所をコメントアウトし、ファイルに直書きしたものを読み込む方式に切り替えました。
本当は、「値が更新されても 1 箇所変えれば全てに適用されるようにしたい」という意図で Parameter Store から取る方式にしていたので、ちょっと不本意な形です。
何かいい方法はないのでしょうか……もし知見がある方がいらっしゃいましたら、教えていただきたいです。
最後に
こういう小ネタも案外ドキュメントにちゃんと書いてあることもあるので、しっかりと目を通しておかないといけないですね。
なお、結局未だにいい解決方法が確立できていません。
くらしのマーケットは、まだまだデプロイ周りでもこういった改善ができるところがたくさんあります。
SRE として一緒に育ててくださる方は、ぜひ こちら からお気軽にご連絡ください!