😇

【Ansible】いつの間にかRoleが終焉していた

2023/03/28に公開

気づいたらAnsible 2.10がリリースされて3年近く経過

筆者は最近までAnsible 2.9を使っていたのだが、ふと最新のAnsible 2.10へ移行してみた。するとAnsible 2.9まで動いていた自作Roleが動かなくなってしまった。

Ansible 2.10以降ではRoleが事実上の終焉

調べたところ、いわゆるStandalone Roleと呼ばれる既存のRoleはEoL状態になっていた。その変更によってAnsible 2.9までで動いていたRoleは2.10以降で動かなくなるケースも出てくる様子。
ちなみにStandalone Roleとは、Collectionという新たな枠組みに属さない単独のRoleという意味で、既存のほとんどのRoleがこれに該当する。

Aisible 2.10以降では、Collectionが標準化

Collectionとは、Playbook、Role、Module、Pluginをまとめてパッケージ化する新たな概念でPlaybookやRoleなどはCollectionの中に内包され群をなすようになる。この概念によってどのCollectionにも属さない単独なRole達は文字通りStandalone Roleと呼ばれるようになった。

具体的にどういう影響があるのか

AnsibleにはRole同士の依存関係を定義したりして、このRoleを動かすなら別のRoleが必要などというふうにすることで各種実装を疎結合にしていた。この概念に新たに影響を与えるのがModuleのCollection化である。日頃から無意識にModuleを使っているとModuleってなんだっけ?となりそうだが、copyだとかlineinfileだとかtaskの中で実行させる命令セット群のこと。Ansibleを使っていたら間違いなく使っている。このModuleというのはAnsible 2.9までは本体に全てのModuleが組み込まれていた。ところがModuleは年々増えていくため全てのModuleをAnsible本体に内包するコンセプトでは本体サイズが年々肥大化してしまい現実的ではなくなっていた。全然使ったことないModuleも大量にあるのに、そのせいで本体サイズがバカデカくなるのは望まないだろう。そこで2.10以降では、ansible.builtinというビルトインModule以外は各ModuleのCollectionを追加インストールして増やしていく仕組みに切り替わった。2.9以前は全ModuleがAnsible本体に内包されていたので”Moduleが存在しません”なんてことはならなかったが、2.10以降は使用したいModuleが含まれるCollectionを事前インストールしておかなければModuleが存在しないエラーも発生しうる。

具体例としては、サーバの初期キッティングに使いそうな下記task。1つ目のhostname:ansible.builtinというCollection内のModuleなので2.10でも初期インストールに含まれており、Collectionを追加インストールする必要ない。ところが2つ目のtimezone:community.generalというCollection内のModuleなので2.10では初期インストールに含まれておらず、community.generalというCollectionを追加インストールしないとエラーとなって実行できない。

- name: Set hostname
  hostname:
    name: localhost
  become: true
  
- name: Set timezone
  timezone:
    name: Asia/Tokyo
  become: true

つまり上記のRoleはcommunity.generalというCollectionと依存関係にあり、実行の前にはcommunity.general Collectionのインストールを行っておかなければならない。
しかし、RoleにはCollectionに対する依存関係を指定できない仕様になっている。

CollectionはAnsibleの実行環境毎にインストールするので、もし仮に人間が依存するCollectionを手作業で追加インストールしたとして、もし他の実行環境でRoleを実行したいならその環境にも手動でCollectionをインストールする必要がある。そうなるとやっと自作のRoleを作って他人に配布しようと思っても、Collectionを事前にインストールしておくようアナウンスしないと動かない。

ではどうすればいいのか?というところだが、根本的な対策としてまずは自作Roleを自作Collection内のRoleとして作り直す。次に自作Roleの入った自作Collectionに必要なModuleの入ったCollectionの依存性を定義する。 そうするとPlaybook実行時にCollectionに指定された他のCollectionへの依存性があると自動で追加インストールしてくれる。

(追記)回避策

根本的な対処策は自作RoleをCollection形式に変更することだが、とりあえずレガシーなStandalone Roleを手っ取り早く使い続けたい場合、Playbookディレクトリに./collections/requirements.ymlを作成すると実行時に必要なCollectionをインストールしてくれる。(今あるRoleを動かす上で何のCollectionのインストールが必要かは手作業で調べるしかない)

# tree
.
├── collections
│   └── requirements.yml
├── roles
│   └── requirements.yml
└── site.yml
# cat collections/requirements.yml
---
collections:
  - community.general

ansible-galaxy collection install xxxxというコマンドで必要なCollectionを実行環境に追加インストールすることも可能だが、時間が経つとまた何のCollectionをインストールしたか忘れてしまう可能性があるし、他の実行環境にStandalone RoleやPlaybookを移すことを考えると、上記に挙げたrequirements.ymlに指定して、Playbook実行時に自動でCollectionをインストールしてもらった方がマシだと思う。それで最終的にはCollection文化に移行してこうという話。

Discussion