Ansible Playbookの複数OS対応について
こんにちは、入社1年目のサーバ開発担当のHです。よろしくお願いします。今回はサーバの構成管理ツールAnsibleのPlaybookの複数OS対応について話をします。
背景
弊社にはCentOSを使ったサーバがあり、サーバの構築には構成管理ツールのAnsibleを使っています。AnsibleではPlaybookというファイルに構成を記載します。
このCentOSのサーバですが、CentOSの開発終了(CentOS Streamへの移行)に伴いOSの変更の話が出てきました。詳細は割愛させていただきますが、今回はUbuntuへのOS変更を実施することになりました。それに伴い、PlaybookをCentOSからUbuntuに対応させる作業が必要になりました。
移行先のOS用にAnsibleのPlaybookを新たに作成する方法もありますが、ほとんどが同じ処理であり、一部だけ処理が異なるとなると、ほぼ同じ内容の2つのPlaybookとなり、それを保守することになり大変で、また再利用もしづらいものになります。
それを避けるため、CentOSとUbuntuどちらでも使用できるAnsibleのPlaybookを書いたので、今回はその書き方を説明します。この記事に出てくるサンプルのコードはCentOSとUbuntu以外への対応は考えていないため、あらかじめご了承ください。
AnsibleのOSごとの処理の分け方
ここが今回のブログの本題です。今回紹介する5つの方法について、簡単にまとめました。
# 1. OSに依存しないモジュールを使う。
- name: OSに依存した書き方
shell: "mkdir /xxx"
- name: OSに依存しない書き方
file:
path: /xxx
state: directory
# 2. OSごとの変数にする
- name: include vars
include_vars: "{{ ansible_facts['distribution'] }}.yml"
# 3. whenステートメントでOSごとのタスクにする
- name: install openjdk-11 (CentOS)
yum:
name: java-11-openjdk-devel
state: present
when: ansible_distribution in ['RedHat','CentOS']
- name: install openjdk-11 (Ubuntu)
apt:
name: openjdk-11-jdk
state: present
when: ansible_distribution in ['Ubuntu']
# 4. OSごとにタスクを作り、include_tasksで各OSごとのタスクを呼び出す
- name: Aのインストール (CentOS)
include_tasks: CentOS.yml
when: ansible_distribution in ['RedHat','CentOS']
- name: Aのインストール (Ubuntu)
include_tasks: Ubuntu.yml
when: ansible_distribution in ['Ubuntu']
# 5. 変数の優先順位を考慮して変数を分ける
どの方法を用いてもOSごとの処理を書けますが、どの方法が最適化はその状況によります。他にさらに良い方法があるかもしれません。ここからは、それぞれの方法について詳しく説明します。
1. OSに依存しないモジュールを使う
AnsibleにはOSに依存していないモジュールが多数存在しています。そのため、それらのモジュールのみを用いることでOSに関係なく用いることが可能なtaskを作成することができます。
aptモジュールやyumモジュールの使用は避け、packageモジュールを使うなどの工夫やほかにもOSに依存しないモジュールとしてfileやuser等があります。ただしモジュールのパラメータ(パッケージ名、パス先等)がOSに依存する可能性があるため、そこは以降で説明する方法で補う必要があります。
2. OSごとの変数にする
OSに依存しないモジュールを使う場合に出てきたOSに依存してしまうモジュールのパラメータは、変数として定義しておいて、その変数をOSごとに変化させる方法です。
roles/[role名]
├── tasks
│ └── main.yml
└── vars
├── main.yml
├── CentOS.yml
└── Ubuntu.yml
# OSに共通する変数: roles/[role名]/vars/main.yml
common_var: test
# OSによって内容が異なる変数: roles/[role名]/vars/CentOS.yml
specific_var: test_centos
# OSによって内容が異なる変数: roles/[role名]/vars/Ubuntu.yml
specific_var: test_ubuntu
# roleの最初のタスクとして読み込む: roles/[role名]/tasks/main.yml
- name: include vars
include_vars: "{{ ansible_facts['distribution'] }}.yml"
- debug: var=common_var
- debug: var=specific_var
上記のroleを含むPlaybookを実行すると、common_varはOSによって表示は変わりませんが、specific_varはOSによって表示が変わります。
3. whenステートメントでOSごとのタスクにする
タスクにwhenステートメントを付け、タスクに実行条件を付ける方法。条件にはFact変数で得られるdistributionを用いて実行するか決めることでOSによって動作を分岐させます。
以下のように、CentOSではyumモジュールを使って、Ubuntuではaptモジュールを使ってインストールする場合などに使えます。また、この例の場合、packageモジュールとOS別変数を利用しても同様の結果が得られます。
- name: install openjdk-11 (CentOS)
yum:
name: java-11-openjdk-devel
state: present
when: ansible_distribution in ['RedHat','CentOS']
- name: install openjdk-11 (Ubuntu)
apt:
name: openjdk-11-jdk
state: present
when: ansible_distribution in ['Ubuntu']
4. OSごとにタスクを作り、include_tasksで各OSごとのタスクを呼び出す
OSそれぞれのタスク群を作り、それをOSによって呼び出すタスク群を変更する方法。OSごとに全く異なる処理を書きたい場合に使えます。たとえば、CentOSではソースからビルド、Ubuntuではパッケージをインストールなどの場合です。
roles/[role名]
└── tasks
├── CentOS.yml
├── Ubuntu.yml
└── main.yml
# roles/[role名]/tasks/CentOS.yml
Aをビルドしてインストールするロールを書く
# roles/[role名]/tasks/Ubuntu.yml
Aをパッケージからインストールするロールを書く
# roles/[role名]/tasks/main.yml
- name: Aのインストール (CentOS)
include_tasks: CentOS.yml
when: ansible_distribution in ['RedHat','CentOS']
- name: Aのインストール (Ubuntu)
include_tasks: Ubuntu.yml
when: ansible_distribution in ['Ubuntu']
5. 変数の優先順位でOSごとに変数を分ける
インベントリファイルでグループ変数を定義している場合に、そのグループ変数がOSごとに異なる場合に、グループ変数より優先されるホスト変数を指定して値を分ける方法。
変数の優先順位などが絡んでくるため、あまりおすすめしませんが、OSを移行完了後に分ける必要がなくなる変数のため、一時しのぎで行いました。変数の優先順位は公式サイトをご覧ください。
[test_server]
192.168.10.2 host_name=This_is_192.168.10.2
192.168.10.3
192.168.10.4
[test_server:vars]
host_name=This_is_test_server
この場合、host_nameはこのようになります。
192.168.10.2 -> This_is_192.168.10.2
192.168.10.3 -> This_is_test_server
192.168.10.4 -> This_is_test_server
最後に
今回はAnsible Playbookの複数OSの対応のための処理の分け方について話しました。他にも方法があるかもしれませんが、今回紹介した方法で大部分は対応できると思います。この記事が少しでも他の方の手助けになることを願います。
入社1年目でOSの変更という大きな作業に関わることができ、とても緊張してもいましたが、いくつかの先行事例もあり、無事AnsibleのCentOSとUbuntuの対応をすることができました。もともとCentOS用のAnsible Playbookのファイルがあったため、それをUbuntuに対応させる作業がメインでしたが、ほとんどはモジュールで共通の処理にすることができ、一部OS固有のみ対応することが多く、CentOSとUbuntuの両対応自体はすんなりできました。
AnsibleのようなInfrastructure as Codeでのサーバ構築など、jig.jp の技術に興味持っていただいた方は、ぜひ採用noteもご覧ください👉 https://note.com/jigjp_recruit/
この記事が気に入ったらサポートをしてみませんか?