RHEL/CentOS/Rocky Linux系ではWebサーバーのパッケージ名がhttpdですが、Ubuntu/Debian系ではapache2になります。サービス名や設定ファイルのパスも異なるため、1本のPlaybookをそのまま複数ディストリビューションに流し込むのは難しいのです。
この記事では、Ansibleが自動収集するansible_os_familyというファクト変数と、include_varsによる動的変数ロードを組み合わせたクロスプラットフォームrole設計を解説します。RHEL系とDebian/Ubuntu系の両方に対応したroleをひとつの構成で管理する考え方と、実際のディレクトリ構造・コード例を順に説明します。
この記事のポイント
・ansible_os_familyはRHEL・Debianなど主要ディストリを自動判定するファクト変数
・vars/RedHat.yml・Debian.ymlでOS別変数ファイルを分離するのが定番設計
・include_tasks: "{{ ansible_os_family }}.yml"でOS別タスクを自動切り替えできる
・gather_facts: falseのPlaybookではファクト変数が取得できない点に注意
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
クロスプラットフォームの壁はどこに潜んでいるか
ディストリビューションが混在する環境でAnsibleを使うと、次のような差異が至るところで出てきます。・パッケージ名の違い:RHELはhttpd、UbuntuはApache2(パッケージ名はapache2)
・パッケージマネージャーの違い:dnf(RHEL系)とapt(Debian/Ubuntu系)
・設定ファイルのパスの違い:/etc/httpd/conf.dと/etc/apache2/sites-available
・ファイアウォールの違い:firewalld(RHEL系)とufw(Ubuntu系)
・ログの置き場の違い:/var/log/httpdと/var/log/apache2
こうした差異に対して「when: ansible_os_family == 'RedHat'」という条件分岐を1つのtasks/main.ymlに全部書き込んでしまうと、コードが複雑になってメンテナンスが困難になります。後から別のOS(AlmaLinuxやopenSUSEなど)を追加する際にも、あちこちを修正しなければなりません。
クロスプラットフォームrole設計の目標は「OS固有の処理をOS単位のファイルに分離して、tasks/main.ymlを薄く保つ」ことです。
ansible_os_familyとは何か
Ansibleはサーバーへ接続したときに、setupモジュールでホストの情報(ファクト)を自動収集します。その中にansible_os_familyという変数があり、ディストリビューションが属するファミリー名が格納されています。主なansible_os_familyの値は以下のとおりです。
・RedHat:RHEL、CentOS、Rocky Linux、AlmaLinux、Fedora
・Debian:Debian、Ubuntu、Raspbian
・Suse:openSUSE、SLES
・Windows:Windows Server各バージョン
実際にsetupモジュールで確認してみましょう。以下はRocky Linux 9.4とUbuntu 24.04 LTSのサーバーに対してansible_os_familyをフィルタリングした例です。
# Rocky Linux 9.4(ホスト名: web01)の場合 $ ansible web01 -m setup -a 'filter=ansible_os_family' -i inventory/hosts web01 | SUCCESS => { "ansible_facts": { "ansible_os_family": "RedHat" }, "changed": false } # Ubuntu 24.04 LTS(ホスト名: web02)の場合 $ ansible web02 -m setup -a 'filter=ansible_os_family' -i inventory/hosts web02 | SUCCESS => { "ansible_facts": { "ansible_os_family": "Debian" }, "changed": false }
より細かいバージョン情報が必要なときはansible_distribution("Rocky"・"Ubuntu"など)やansible_distribution_major_version("9"・"24"など)を使うこともできます。Ansibleの構成管理の全体設計についてはAnsible実践学習サイト(ansible.linuxmaster.jp)でも体系的に解説していますが、まずはansible_os_familyの使い方を押さえておくと現場での応用が広がります。
クロスプラットフォームroleの設計パターン
代表的な設計パターンは「OS別の変数ファイルと、OS別のタスクファイルをディレクトリで分離する」方法です。順番に説明します。1. ディレクトリ構成の設計
Webサーバー(Apache)をインストールするrole「webserver」を例にします。roles/webserver/ ├── defaults/ │ └── main.yml # デフォルト変数(OS非依存) ├── vars/ │ ├── RedHat.yml # RHEL/Rocky Linux系の変数 │ └── Debian.yml # Ubuntu/Debian系の変数 ├── tasks/ │ ├── main.yml # エントリポイント(薄く保つ) │ ├── RedHat.yml # RHEL系専用タスク │ └── Debian.yml # Debian系専用タスク ├── handlers/ │ └── main.yml └── templates/ └── vhost.conf.j2
2. OS別変数ファイルの分離
vars/RedHat.yml と vars/Debian.yml にそれぞれのパッケージ名・サービス名・設定パスを定義します。# vars/RedHat.yml apache_package: httpd apache_service: httpd apache_conf_dir: /etc/httpd/conf.d apache_log_dir: /var/log/httpd
# vars/Debian.yml apache_package: apache2 apache_service: apache2 apache_conf_dir: /etc/apache2/sites-available apache_log_dir: /var/log/apache2
3. tasks/main.ymlでのOS別タスク切り替え
tasks/main.yml はOS別の変数ファイルとタスクファイルを読み込むだけの薄いファイルにします。# tasks/main.yml --- - name: OS別変数ファイルを読み込む ansible.builtin.include_vars: "{{ ansible_os_family }}.yml" - name: OS別タスクを実行する ansible.builtin.include_tasks: "{{ ansible_os_family }}.yml"
tasks/RedHat.yml と tasks/Debian.yml の例を示します。
# tasks/RedHat.yml --- - name: httpdをインストールする(RHEL系) ansible.builtin.dnf: name: "{{ apache_package }}" state: present - name: firewalldでhttpポートを開放する ansible.posix.firewalld: service: http permanent: true state: enabled immediate: true - name: httpdを起動・有効化する ansible.builtin.service: name: "{{ apache_service }}" state: started enabled: true
# tasks/Debian.yml --- - name: apache2をインストールする(Debian系) ansible.builtin.apt: name: "{{ apache_package }}" state: present update_cache: true - name: ufwでhttpポートを開放する community.general.ufw: rule: allow port: "80" proto: tcp - name: apache2を起動・有効化する ansible.builtin.service: name: "{{ apache_service }}" state: started enabled: true
実際のPlaybook実行例
Rocky Linux 9.4(web01)とUbuntu 24.04(web02)の2台に対して上記のroleを含むPlaybookを実行した結果を示します。$ ansible-playbook site.yml -i inventory/hosts PLAY [Webサーバーを構成する] ********************************** TASK [Gathering Facts] ******************************* ok: [web01] ok: [web02] TASK [webserver : OS別変数ファイルを読み込む] ****************** ok: [web01] # vars/RedHat.yml を読み込み ok: [web02] # vars/Debian.yml を読み込み TASK [webserver : OS別タスクを実行する] ************************ included: /home/ansible/roles/webserver/tasks/RedHat.yml for web01 included: /home/ansible/roles/webserver/tasks/Debian.yml for web02 TASK [webserver : httpdをインストールする(RHEL系)] ************* changed: [web01] TASK [webserver : apache2をインストールする(Debian系)] ********** changed: [web02] TASK [webserver : httpdを起動・有効化する] ********************** changed: [web01] TASK [webserver : apache2を起動・有効化する] ******************** changed: [web02] PLAY RECAP ******************************************* web01 : ok=5 changed=3 unreachable=0 failed=0 skipped=0 web02 : ok=5 changed=3 unreachable=0 failed=0 skipped=0
ansible_os_familyだけでは足りないケースへの対応
1. ディストリビューション固有の対応が必要な場合
Rocky Linux 9とRHEL 8で設定ファイルのパスが異なる、UbuntuとDebianでパッケージのバージョンが違うといった状況では、ansible_os_familyより細かい粒度の変数を使います。・ansible_distribution:"Rocky"・"Ubuntu"・"Debian"など固有名称
・ansible_distribution_major_version:"9"・"24"などメジャーバージョン番号
変数ファイルを2段階にすることで、ファミリー共通の設定を上位ファイルで定義し、固有設定を下位ファイルで上書きできます。
# tasks/main.yml(2段階の変数ファイルロード) --- - name: OSファミリー別変数を読み込む ansible.builtin.include_vars: "vars/{{ ansible_os_family }}.yml" - name: ディストリビューション固有変数を上書き読み込む(存在する場合のみ) ansible.builtin.include_vars: "vars/{{ ansible_distribution }}.yml" failed_when: false
2. 対応OSをmeta/main.ymlで明示する
roleが対応しているOSをmeta/main.ymlに明記する習慣をつけましょう。チームで使う際に「このroleはAlmaLinuxに対応しているのか」という疑問が生じにくくなります。# meta/main.yml galaxy_info: author: your_name description: Cross-platform web server role platforms: - name: EL # RHEL/Rocky Linux/AlmaLinux versions: - 8 - 9 - name: Ubuntu versions: - focal # 20.04 LTS - jammy # 22.04 LTS - noble # 24.04 LTS
トラブルシュート
「Could not find or access 'RedHat.yml'」エラーが出る
include_tasksやinclude_varsで指定したファイルが見つからない場合に発生します。考えられる原因と対処は以下のとおりです。・ファイル名の大文字小文字ミス:LinuxはOSが大文字小文字を区別します。ansible_os_familyの値は"RedHat"(Rが大文字・Hが大文字)なので、ファイル名をredhat.ymlにすると一致しません
・ディレクトリの配置ミス:include_varsはroleのvars/から探しますが、include_tasksはtasks/からの相対パスになります。それぞれのディレクトリ構造を確認してください
・未対応OSへの適用:Suseなど非対応ファミリーにroleを流した場合、対応するファイルが存在せずエラーになります。meta/main.ymlで対応OSを制限し、テスト済み環境だけに流すようにしましょう
ansible_os_familyがundefinedになる
PlaybookにGather_facts: falseが設定されていると、setupモジュールが実行されずファクト変数が取得できません。ansible_os_familyを使う前にgather_factsがtrueになっていることを確認してください。# gather_factsが明示的にfalseになっている例(NG) - name: Webサーバーを構成する hosts: webservers gather_facts: false # ansible_os_familyが使えない tasks: ... # gather_factsをtrueに戻す(OK) - name: Webサーバーを構成する hosts: webservers gather_facts: true # または省略(デフォルトはtrue) tasks: ...
本記事のまとめ
クロスプラットフォームrole設計のポイントをまとめます。| やりたいこと | 設計のアプローチ |
|---|---|
| OS種別を自動判定する | ansible_os_family(RedHat/Debian/Suse等)を使う |
| OS別のパッケージ名・パスを分離する | vars/RedHat.yml・vars/Debian.ymlに変数を定義する |
| OS別の変数ファイルを自動読み込みする | include_vars: "{{ ansible_os_family }}.yml" |
| OS別のタスクファイルを切り替える | include_tasks: "{{ ansible_os_family }}.yml" |
| ディストリ固有の差異に対応する | ansible_distributionで2段階ロードする |
| ファクト変数が取得できないとき | gather_factsがfalseになっていないか確認する |
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、Ansibleを活用したサーバー自動化の設計から実装まで2日間のハンズオンで学べるAnsible実践セミナー(ansible.linuxmaster.jp)をぜひご覧ください。クロスプラットフォームrole設計を含む実務パターンを体系的に習得できます。
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら
- 前のページへ:ansible環境でshell/cmdに頼らない構成管理入門|role設計と代替モジュール選択指針
- この記事の属するカテゴリ:Ansibleへ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。
登録無料・いつでも解除できます