Ansibleを使い始めて間もないエンジニアが必ずぶつかる壁だ。
この問題を解決するのが facts(ファクト) だ。AnsibleはPlaybookのタスクを実行する前に、対象ホストのOS情報・CPU・メモリ・ネットワーク設定を自動で収集する。収集した情報はPlaybook内で変数として参照できるため、OSの種類に応じて処理を切り替えたり、メモリ容量によってパラメータを変えたりといった「環境適応型のPlaybook」を実現できる。
この記事では、Ansible factsの仕組み・setupモジュールが収集する情報の種類・gather_factsの制御方法(無効化・部分収集)・when条件分岐へのfacts活用パターン・カスタムfactsの定義方法を、実際の実行結果とともに解説する。
動作確認環境: RHEL 9.4 / Ubuntu 24.04 LTS、Ansible 2.16.x
この記事のポイント
・gather_facts: true(デフォルト)でsetupモジュールが自動的にホスト情報を収集する
・ansible_distributionでOS種別を判定してwhen条件分岐に使える
・gather_facts: falseに設定すると大規模環境でPlaybookを高速化できる
・/etc/ansible/facts.d/にINIファイルを置くとカスタムfactsを定義できる
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
Ansible factsとは何か|Playbookが走る前に何が起きているか
ansible-playbookコマンドを実行したとき、タスクの前に必ず表示される行がある。PLAY [webservers] ************************************************************** TASK [Gathering Facts] ********************************************************* ok: [webserver01] ok: [webserver02] ok: [db01]
setupモジュールを自動実行して各種情報を取得している。収集されたfactsは
ansible_factsというディクショナリに格納され、ansible_distributionやansible_memtotal_mbといった変数名でPlaybook内から参照できる。Playbookに明示的な設定を書かなくても、デフォルトで収集が有効になっているのがポイントだ。factsの仕組みを理解することで、「このホストはRHELなのかUbuntuなのか」「RAMは8GB以上あるか」をPlaybook実行時に動的に判断できるようになる。複数のOS・スペックのホストを同一Playbookで管理するための基盤がfactsだ。
setupモジュールが収集する情報の種類
1. OS・ディストリビューション情報
Playbookの条件分岐で最もよく使われる情報群だ。OSファミリーで大まかに分岐し、バージョンで細かく制御するパターンが現場の定番だ。・ansible_distribution:ディストリビューション名(例: "RedHat", "Ubuntu", "CentOS", "Rocky")
・ansible_distribution_version:バージョン番号(例: "9.4", "24.04")
・ansible_distribution_major_version:メジャーバージョンのみ(例: "9", "24")
・ansible_os_family:OSファミリー("RedHat" または "Debian")
・ansible_kernel:Linuxカーネルバージョン(例: "5.14.0-427.13.1.el9_4.x86_64")
2. CPU・メモリ情報
JVM ヒープサイズやDBのバッファプールサイズなど、リソース依存のパラメータ設定に使う情報群だ。・ansible_processor_count:CPUソケット数
・ansible_processor_vcpus:仮想CPU(vCPU)数
・ansible_memtotal_mb:総メモリ量(MB単位)
・ansible_memfree_mb:空きメモリ量(MB単位)
3. ネットワーク情報
IPアドレスやホスト名の確認・条件分岐に使う情報群だ。・ansible_hostname:ホスト名(短縮形)
・ansible_fqdn:完全修飾ドメイン名(FQDN)
・ansible_default_ipv4.address:デフォルトルート側のIPv4アドレス
・ansible_interfaces:ネットワークインターフェース名のリスト
4. setupモジュールを直接実行してfactsを確認する
Playbookを書く前に対象ホストのfactsを調べるには、アドホックコマンドでsetupモジュールを直接実行するのが手っ取り早い。# 対象ホストの全factsを表示する ansible webserver01 -m setup # filterオプションで絞り込む(ディストリビューション情報のみ) ansible webserver01 -m setup -a "filter=ansible_distribution*"
webserver01 | SUCCESS => { "ansible_facts": { "ansible_distribution": "RedHat", "ansible_distribution_major_version": "9", "ansible_distribution_release": "Plow", "ansible_distribution_version": "9.4" }, "changed": false }
ansible_distributionが"Ubuntu"になり、ansible_distribution_versionが"24.04"に変わる。条件分岐のwhen句で使う変数の実値をここで確認しておくと、Playbook作成時のミスを防げる。メモリ情報を確認したいときは次のようにfilterを変える。
# メモリ情報だけ確認する ansible db01 -m setup -a "filter=ansible_memory_mb"
db01 | SUCCESS => { "ansible_facts": { "ansible_memory_mb": { "nocache": { "free": 13412, "used": 2427 }, "real": { "free": 6893, "total": 15839, "used": 8946 }, "swap": { "cached": 0, "free": 2047, "total": 2047, "used": 0 } } }, "changed": false }
ansible_memory_mb.real.totalが15839MB(約16GB)であることがわかる。このような実測値を把握しておくことで、メモリベースの条件分岐をPlaybook内で自信を持って設計できる。Ansibleのfacts収集を実機でハンズオン体験したい方は、>> Ansibleハンズオン講座の詳細を見る をご覧ください。
gather_factsの制御|収集を無効化して高速化する
1. gather_facts: falseで収集を無効化する理由
factsの収集はPlaybookの冒頭で対象ホスト全台に対して実行される。ホスト数が多い環境では、この処理が実行時間のボトルネックになることがある。100台のホストに対してPlaybookを実行した場合、gather_factsだけで30秒以上かかることも珍しくない(並列接続数が
forks設定に縛られるためだ)。単純なファイル配布やコマンド実行のみでOS情報が不要なPlaybookでは、gather_facts: falseを指定して収集をスキップできる。--- - name: ファイルを配布する(facts不要なため収集をスキップ) hosts: all gather_facts: false tasks: - name: 設定ファイルを転送する copy: src: files/app.conf dest: /etc/app/app.conf mode: '0644'
gather_facts: falseを設定すると、Playbookの出力から「TASK [Gathering Facts]」のステップが消え、最初のタスクから即座に実行が始まる。ただしansible_distribution等のfacts変数はすべてundefinedになるため、when条件でfacts変数を参照しているタスクがあると実行時エラーになる。この点は必ず確認すること。2. gather_subsetで必要な情報だけ収集する
factsを完全に無効化せず、必要な情報だけを収集したい場合はgather_subsetを使う。全情報を収集するよりも処理時間を短縮しながら、必要な変数は使えるようにするバランス型の設定だ。--- - name: ネットワーク情報だけ収集する hosts: all gather_facts: true gather_subset: - network - '!hardware' - '!virtual' tasks: - name: IPアドレスを表示する debug: msg: "{{ ansible_default_ipv4.address }}"
gather_subsetで指定できる主なサブセットは次の通りだ。・min:最小限の情報(OS・ホスト名・IPアドレス)
・network:ネットワークインターフェース・IPアドレス情報
・hardware:CPU・メモリ・ディスク情報
・virtual:仮想化環境の情報(VMware・KVM・Docker判定など)
・!hardware:先頭に「!」を付けると除外指定になる
まず
allで一度全収集して必要な変数を把握し、本番運用時にgather_subsetで絞り込む、という手順が実用的だ。収集したfactsをwhen条件分岐で使う設計パターン
1. OS別の処理分岐(RHELとUbuntuを同一Playbookで管理)
最も使用頻度の高いパターンだ。ansible_os_familyでRedHat系とDebian系を振り分ける。--- - name: Webサーバーをインストールする(OS混在環境対応) hosts: webservers become: true tasks: - name: Apache をインストールする(RHEL系) dnf: name: httpd state: present when: ansible_os_family == "RedHat" - name: Apache をインストールする(Debian系) apt: name: apache2 state: present update_cache: true when: ansible_os_family == "Debian" - name: Apache を起動する(RHEL系:サービス名が httpd) service: name: httpd state: started enabled: true when: ansible_os_family == "RedHat" - name: Apache を起動する(Debian系:サービス名が apache2) service: name: apache2 state: started enabled: true when: ansible_os_family == "Debian"
ok/changedになり、aptタスクはskippingになる。Ubuntu 24.04のホストでは逆になる。TASK [Apache をインストールする(RHEL系)] ********************************** changed: [webserver01] TASK [Apache をインストールする(Debian系)] ********************************** skipping: [webserver01] TASK [Apache をインストールする(RHEL系)] ********************************** skipping: [ubuntu01] TASK [Apache をインストールする(Debian系)] ********************************** changed: [ubuntu01]
2. メモリ容量に基づく分岐
DBのバッファプールサイズやJVMヒープ設定など、メモリ量によってパラメータを変えたい場面に使う。--- - name: MariaDB の innodb_buffer_pool_size を設定する hosts: dbservers become: true tasks: - name: バッファプールを16GB以上のサーバーは8GBに設定する lineinfile: path: /etc/my.cnf.d/server.cnf regexp: '^innodb_buffer_pool_size' line: 'innodb_buffer_pool_size = 8G' when: ansible_memtotal_mb >= 16384 - name: バッファプールを8GB未満のサーバーは1GBに設定する lineinfile: path: /etc/my.cnf.d/server.cnf regexp: '^innodb_buffer_pool_size' line: 'innodb_buffer_pool_size = 1G' when: ansible_memtotal_mb < 8192
ansible_memtotal_mbはMB単位の整数として格納されるため、>= 16384は「16GB以上」を意味する。数値の比較にはクォートが不要だ(文字列比較との混同に注意)。3. ホスト名・IPアドレスを条件にした制御
命名規則でホストの役割を識別している環境で、特定のホストグループにのみ処理を適用したいときに使う。--- - name: DBホストにのみ監視エージェントの設定を追加する hosts: all tasks: - name: DB用の監視設定を配置する(ホスト名に "db" が含まれるホストのみ) copy: src: files/db-monitor.conf dest: /etc/monitor/db-monitor.conf when: "'db' in ansible_hostname" - name: 特定サブネットのホストにのみファイアウォール設定を適用する firewalld: zone: internal permanent: true state: enabled when: ansible_default_ipv4.address | ansible.utils.ipaddr('192.168.10.0/24')
'db' in ansible_hostnameのようにPythonのin演算子を使える。IPアドレスのサブネット判定にはansible.utilsコレクションのipaddressフィルターが便利だ。カスタムfacts|独自情報を/etc/ansible/facts.d/に定義する
setupモジュールが収集する標準factsに加えて、独自のfactsをホスト側に定義することもできる。これが「カスタムfacts」だ。アプリのバージョン情報や環境区分(開発/ステージング/本番)など、Ansibleが自動収集できない情報を管理するのに便利だ。1. /etc/ansible/facts.d/にINIファイルを作成する
対象ホストの/etc/ansible/facts.d/ディレクトリに.fact拡張子のファイルを置く。INI形式のファイルが最も手軽だ。# /etc/ansible/facts.d/app.fact(INI形式) # このファイルを対象ホストに事前に配置する [app] version = 2.5.1 environment = production deploy_user = appuser
--- - name: カスタムfactsファイルを配置する hosts: appservers become: true tasks: - name: facts.d ディレクトリを作成する file: path: /etc/ansible/facts.d state: directory mode: '0755' - name: カスタムfactsファイルをコピーする copy: src: files/app.fact dest: /etc/ansible/facts.d/app.fact mode: '0644' - name: カスタムfactsを再収集する setup: filter: ansible_local
2. カスタムfactsをPlaybookで使う
カスタムfactsはansible_local変数の配下に格納される。INIファイル名(拡張子なし)がキー名になる。--- - name: カスタムfactsを使ってアプリの設定を制御する hosts: appservers tasks: - name: アプリのバージョンを表示する debug: msg: "アプリバージョン: {{ ansible_local.app.app.version }}" - name: 本番環境のみロギングを有効化する template: src: templates/logging.conf.j2 dest: /etc/app/logging.conf when: ansible_local.app.app.environment == "production"
ansible_local.ファイル名.セクション名.キー名の形式になる。上の例ではansible_local.app.app.versionとなる(ファイル名"app"、セクション名"app"、キー名"version")。facts活用時のトラブルと注意点|よくある落とし穴の解決策
・gather_facts: false時に変数参照するとエラーになる:収集を無効化したPlaybookでansible_distribution等を参照するとundefined変数エラーが発生する。「when: ansible_os_family == 'RedHat'」のような条件があると、そのタスクはエラーで止まる(skippingにはならない)。gather_factsをfalseにするPlaybookはfacts変数を参照していないことを必ず確認すること・fact gatheringが失敗するケース:SSH接続に問題があるとsetupモジュールの実行自体が失敗する。「FAILED! => Timeout (12s) waiting for privilege escalation prompt」や「Failed to connect to the host via ssh」が出た場合は接続設定・sudoの設定を先に確認する
・変数優先順位との関係:factsはgroup_vars・host_varsより低い優先順位を持つ。同名の変数がhost_varsに定義されている場合、factsの値はその変数で上書きされる。意図しない上書きが起きていないか、変数の優先順位を把握した設計が必要だ
・カスタムfactsのパスの注意:
/etc/ansible/facts.d/は対象ホスト(管理対象サーバー)側に置くディレクトリだ。Ansibleを実行するコントロールノード(自分のPC)側に置いても読み込まれないので注意すること本記事のまとめ
| やりたいこと | 方法・変数名 |
|---|---|
| 対象ホストの全factsを確認する | ansible ホスト名 -m setup |
| ディストリビューション情報のみ確認する | ansible ホスト名 -m setup -a "filter=ansible_distribution*" |
| OSファミリーで処理を分岐する | when: ansible_os_family == "RedHat" |
| メモリ容量で処理を分岐する | when: ansible_memtotal_mb >= 16384 |
| ホスト名で処理を絞り込む | when: "'db' in ansible_hostname" |
| facts収集を完全に無効化する | Playbook冒頭に gather_facts: false |
| 必要な情報だけ収集する | gather_subset: ['network', '!hardware'] |
| 独自情報をfactsに追加する | /etc/ansible/facts.d/*.fact にINIファイルを配置 |
| カスタムfactsを参照する | ansible_local.ファイル名.セクション名.キー名 |
ansible ホスト名 -m setupで対象ホストのfactsを実際に確認し、使いたい変数の実値を把握してからPlaybookを書く習慣をつけると、when条件のミスや変数名の勘違いを防げる。カスタムfactsまで活用できるようになると、Ansibleが収集できないアプリケーション固有の情報も含めた設計が可能になる。構成管理の自由度が大きく広がるステップだ。
Ansible実践ハンズオンの詳細を見る >>
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
登録10秒/合わなければ解除3秒 / 詳細はこちら
- 次のページへ:AnsibleでLinuxサーバーのパッチ適用を自動化する方法|dnf・aptモジュールとserialによるローリング更新
- 前のページへ:Ansibleのcheckモードとdiffでドライラン検証する方法|本番適用前に変更内容を確認する運用設計
- この記事の属するカテゴリ:Ansibleへ戻る

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