Ansible 変数の定義箇所

Ansibleの変数の優先度、特に複数箇所で同一名で定義された場合の優先順位について調べた。 また meta/main.yml:dependency を用いたrole間の依存関係に基づいたroleの適用順序も調べた。

roleの構造

はじめに role の構造について説明する。 ベストプラクティスをまねた構成が下のようになる。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
    role1/                # this hierarchy represents a "role"
        tasks/            #
            main.yml      #  <-- tasks file can include smaller files if warranted
        handlers/         #
            main.yml      #  <-- handlers file
        templates/        #  <-- files for use with the template resource
            ntp.conf.j2   #  <------- templates end in .j2
        files/            #
            bar.txt       #  <-- files for use with the copy resource
            foo.sh        #  <-- script files for use with the script resource
        vars/             #
            main.yml      #  <-- variables associated with this role
        defaults/         #
            main.yml      #  <-- default lower priority variables for this role
        meta/             #
            main.yml      #  <-- role dependencies
        library/          # roles can also include custom modules
        module_utils/     # roles can also include custom module_utils
        lookup_plugins/   # or other types of plugins, like lookup in this case

大きく分けて4つに分類してみる。

カテゴリ ディレクトリ名
ロール自体について meta
適用項目 tasks, handlers
変数 vars, defaults
Ansibleの拡張 library, module_utils, lookup_plugins

role間の依存関係

これに関わるのは meta ディレクトリ。 meta/main.yml ファイルでは項目 dependencies を使って他の role への依存を定義できる。 また依存先の role で使われる変数の値も指定できる。

1
2
3
4
dependencies: [
    "other_role_a",
    {"role": "other_role_b", "var_foo": "value_bar"},
]

次の節で詳しく書くが、この場合 other_role_a は普通に呼ばれるが、 other_role_b の適用時での var_foo の値は value_bar が用いられる。

roleの適用順序

基本的には playbookroles に記載されている role が上から順に適用されていく。 下の場合には roleA,roleB,roleC と適用されていく。

1
2
3
4
- roles:
  - roleA
  - roleB
  - roleC

ここで roleBmeta/main.ymlroleZ への依存が定義されていた場合、 roleZ の適用が roleB の適用に先行し、全体としては roleA,roleZ,roleB,roleC と適用されることになる。

複数の role が1つの role に依存している場合

不明瞭だった複数の role が同一 role に依存している場合の適用順序について調べた。

先に結果を具体例を用いて説明する。 下記の依存関係がある場合、 roleZ の適用は roleA,roleB,roleD の前に1回ずつ全部で3回呼ばれる。また roleD,roleEother_var が異なる値に解決されるとしても、適用箇所には無関係だった。

roleA -> {"role": "roleZ"}
roleB -> {"role": "roleZ", "var": "value"}
roleC -> {"role": "roleZ"}
roleD -> {"role": "roleZ", "var": "{{ other_var }}"}
roleE -> {"role": "roleZ", "var": "{{ other_var }}"}

これらから下の規則が推測される。

  • 各呼び出し元の依存定義の種類毎に1回ずつ呼ばれる
  • 変数の値が別の値を参照している場合でも role 適用時には値は解決されず文字列として扱われる
    • 値が解決されるのはあくまで task 内で利用される時に限られる

変数の値の解決順序

続いて、変数の値の解決について調べた。 まず、基本の確認。

"{{ var }}"tasks,defaults,vars,templates などで使うと評価され値に展開される。 var: "{{ foo }}"などと値がまた別の変数を参照している時には再帰的に展開される。

Ansible は複数のデプロイ先を同時に扱える。また変数定義や task の適用はホストやグループ毎に制御できる。 なので変数はホスト単位で管理されていると考えて問題ない。

変数は複数箇所で値を設定できる。自分が知ってて使う場所は以下の通り。(他にもあるかも知れないけど扱わない)

  • metadependencies による指定
  • rolevars 配下
  • set_fact モジュール task で定義
  • register による task の実行結果
  • playbookvars_files による定義
  • playbookvars による定義
  • inventory ファイル内
  • roledefaults 配下

これよりも強い指定方法もあるけど、あまり使ってない。 基本的に状況が絞られてるものほど優先度が高くなっている。 playbook での指定より task, role での指定の方が基本的に優先されている。

複数の role で同一変数を定義している場合

role はデプロイを分割する機構であるものの変数は role をまたいで干渉するため、整理しないと混乱する。そこで role に関わる vars,defaults,meta:dependencies での指定について調べた。

探される順序は下の様になった(上で見つかったらそこ確定)

  1. meta/main.yml での指定
  2. 現在の rolevars 内での定義
  3. 他の rolevars 内での定義(複数存在する場合、最後に定義した role の値)
  4. 現在の roledefaults 内での定義
  5. 他の roledefaults 内での定義(複数存在する場合、最後に定義した role の値)
comments powered by Disqus