見出し画像

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/


この記事が気に入ったらサポートをしてみませんか?