Ansbileは宣言型か?手続き型か?
Ansibleは宣言型だろうか?手続き型だろうか?
ドキュメントによって見解が異なるので混乱しやすいポイントだ。
Ansible寄りのドキュメントでは宣言型と言われることが多い。
一方、Terraform、Puppet、Kuberenetesなど純粋な宣言型ツールの視点からはAnsibleは手続き型と言われることが多い。
Ansibleの本質は手続き型
AnsibleはPlaybookに手順を記述しているので個人的には手続き型だと考える。
しかし冪等性があるので条件によっては宣言的な使い方も可能だ。 以下に詳しく見ていこう。
宣言的に動作するケース
望む状態
例えばリソースA、BをAnsibleで作成した後、リソースCを追加して、「リソースA、B、C」にしたくなったとする。
宣言
望んだ状態が「リソースA、B、C」なので宣言的なツールでは定義ファイルに「リソースA、B、C」と記載することになる。
そこでリソースA、Bを作成したPlaybookにリソースCを作成する手順を追記してみよう。
結果
Playbookを実行しよう。
リソースA、Bを作成する手順は既に実行済みなので冪等性によりAnsbileはスキップする。 未実施のリソースCを作成する処理のみが実施され、結果は「リソースA、B、C」になる。
望んだ状態が「リソースA、B、C」で、Playbookの宣言も「リソースA、B、C」で、結果も「リソースA、B、C」なので宣言的に動作していると言える。
しかしこれを持ってAnsibleを宣言的と理解するのは危険だ。 次は宣言的に動作しないケースを見てみよう。
宣言的に動作しないケース1:削除
望む状態
例えばリソースA、BをAnsibleで作成した後、Bを削除して「リソースA」にしたくなったとする。
宣言
そこでリソースA、Bを作成したPlaybookを編集し、リソースBを作成する手順を削除する。
今、Playbookに宣言されているリソースはAのみだ。 このPlaybookを実行すると宣言通り「リソースA」になるだろうか?
結果
Playbookを実行しよう。
リソースAを作成する手順は実施済みなのでスキップする。 リソースBに対する処理はなにも記述していないのでAnsibleはリソースBに対してなにも実施しない。 結果は「リソースA、B」になる。
宣言通りのは結果にならない。
望む状態にするには?
「リソースA」にするにはリソースA、Bを作成したPlaybookを編集し、リソースBを作成する手順を削除して、リソースBを削除する手順を追記する。
手順を記述しないと望む状態にならないので手続き的と言えるだろう。
宣言的に動作しないケース2:変更
望む状態
例えばリソースA、BをAnsibleで作成した後、BをCに変更して「リソースA、C」にしたくなったとする。
宣言
リソースA、Bを作成したPlaybookを編集し、リソースBを作成する手順を削除して、リソースCを作成する手順を記述する。
Playbookに宣言されているリソースはAとCだ。 このPlaybookを実行すると宣言通り「リソースA、C」になるだろうか?
結果
このPlaybookを実行したときの結果はリソースB、CがMutable(変更可能)かImmutable(変更不可)かによって異なる。
Mutableな場合
Mutableなリソースは直接変更することができる。
Playbookを実行するとBがCに変更されて、結果は「リソースA、C」となる。
望んだ状態が「リソースA、C」で、Playbookの宣言も「リソースA、C」で、結果も「リソースA、C」なので宣言的だ。
Immutableな場合
Immutableなリソースは直接変更できない。 既存リソース(B)を削除して新規リソース(C)を作成する必要がある。
Playbookを実行するとBを削除する手順がないので既存リソースBは削除されない。 新規リソースCが作成されて、結果は「リソースA、B、C」となる。
宣言通りのは結果にならない。
望む状態にするには?
「リソースA、C」にするにはリソースA、Bを作成したPlaybookを編集し、リソースBを作成する手順を削除して、リソースBを削除する手順とリソースCを作成する手順を追記することだ。
手順を記述しないと望む状態にならないので手続き的と言えるだろう。
結論
以上のようにAnsibleを純粋な宣言型だと考えると痛い目にあう可能性がある。
冪等性は宣言型であることを保証しない。
Ansibleは本質的には手続き型だと考えた方が無難だろう。