いつの間にか Ansible の変数にスコープの概念が入っていてプロビジョンに失敗するようになっていたという話。
正直、自分はあんまりテクニカルな方面のアンテナを張っていないので、ソフトウェアのアップデートで仕様が変わっていたりすると即死してしまう。
今回は、よくわかっていないまま Ansible の Playbook をいろんなところからのコピペで作っていたら、いつの間にか動かないものになっていた。
Variables — Ansible Documentation
Ansible has 3 main scopes:
- Global: this is set by config, environment variables and the command line
- Play: each play and contained structures, vars entries, include_vars, role defaults and vars.
- Host: variables directly associated to a host, like inventory, facts or registered task outputs
どうやら、Ansibleには変数のスコープが3種類あるようで、このうち Play (要は一回の実行単位)スコープで保持してほしい変数を Host スコープに入れていたので、スコープから外れてしまったようだ。
失敗するようになっていた定義
どこからパクったのかすら忘れてしまったが site.yml
に以下のように書いてやって、インベントリファイルで stage
変数を設定することで、環境毎の差分を吸収するようにしていた。
site.yml(```yaml:site.yml って書けないの?)
- hosts: all vars_files: - vars/{{ stage }}.yml tasks: - name: dump on site.yml debug: var=_stage - include: allservers.yml - include: webservers.yml - include: appservers.yml - include: memservers.yml - include: dbservers.yml
が、こうすると include
しているファイルの中にも hosts
があるので site.yml
の hosts
で設定した変数はスコープから外れてしまうようだった。
インターネットをさまよった結果、どうやら変数にスコープの概念が入った結果未定義になってしまったような気がしただけなので、あまり確信はない。
# site.yml - hosts: all vars_files: - vars/{{ stage }}.yml tasks: - name: dump on site.yml debug: var=_stage - include: allservers.yml # allservers.yml - hosts: allservers gather_facts: no become: yes become_method: sudo roles: - {role: common, tags: [always]} # common ロールで実行される task - name: dump variables. debug: var=_stage # vars/{{ stage }}.yml _stage: mariadb: root_password: db: # ~~長々と設定値定義
上記のような定義で実行すると、以下のように未定義になってしまっていた。
TASK [dump on site.yml] ******************************************************** ok: [192.168.33.74] => { "_stage": { "mariadb": { "db": [ # ~~長々と変数内容 TASK [common : dump variables.] ************************************************ ok: [192.168.33.74] => { "_stage": "VARIABLE IS NOT DEFINED!" }
Play スコープで任意の変数ファイルを読む
で、本来これを記事の先頭に書けよ、という気がしなくもないが、記事を書きだしたタイミングではどうすればいいのかわからなかったのでケツにある。
- Play: each play and contained structures, vars entries, include_vars, role defaults and vars.
とあるので include_vars
タスクで読んだら Play スコープになるようなので、単に以下のように変えてみた。
# site.yml - hosts: all tasks: - name: includes stage variable file. include_vars: vars/{{ stage }}.yml - name: dump on site.yml debug: var=_stage - include: allservers.yml # allservers.yml - hosts: allservers gather_facts: no become: yes become_method: sudo roles: - {role: common, tags: [always]} # common ロールで実行される task - name: dump variables. debug: var=_stage # vars/{{ stage }}.yml _stage: mariadb: root_password: db: # ~~長々と設定値定義
結果、各ホストでも変数が見えるようになったので、さしあたってはこれでいいかなぁ。と、深堀をやめたのであった。
TASK [includes stage variable file.] ******************************************* ok: [192.168.33.74] TASK [dump on site.yml] ******************************************************** ok: [192.168.33.74] => { "_stage": { "mariadb": { "db": [ # ~~長々 TASK [common : dump variables.] ************************************************ ok: [192.168.33.74] => { "_stage": { "mariadb": { "db": [ { # ~~長々
Ansible のバージョン
こんな感じでした。
$ yum list ansible Loaded plugins: fastestmirror Loading mirror speeds from cached hostfile * base: ftp.tsukuba.wide.ad.jp * extras: ftp.tsukuba.wide.ad.jp * remi-safe: remi.kazukioishi.net * updates: ftp.tsukuba.wide.ad.jp Installed Packages ansible.noarch 2.0.1.0-2.el7 @epel $