「そのIPアドレス、直接書いていませんか?」それが苦労の始まりです。
こんにちは!「LINUX工房」管理人の「リナックス先生」です。
過去記事「Ansible応用講座 第1回」などの学習を通して、Ansibleの基本的な操作やクラウド連携の便利さにはもう触れましたか?ansible-playbook コマンドを叩いてサーバーが自動で構築される様子は、何度見ても気持ちが良いものですよね。
さて、入門を卒業したあなたが次に直面する壁。それは「修正の手間」です。
- 「テスト環境と本番環境で、インストールするバージョンを変えたい」
- 「サーバーごとに設定ファイルのIPアドレスだけ書き換えたい」
- 「OSがCentOSかUbuntuかによって、使うコマンド(yum/apt)を自動で切り替えたい」
もし、これらを解決するために「Playbookをコピーして別ファイルを作る」なんてことをしていたら、それはAnsibleの力を10%も引き出せていません。
今回からの新連載では、「一度書けばどこでも動く(Write Once, Run Anywhere)」スマートな自動化を実現するためのテクニックを学びます。
先生!待ってました!
実は現場で「PlaybookのIPアドレスを書き換えるのを忘れて、開発環境の設定を本番に反映しちゃった」という事故を起こしかけまして…。
ファイルの中身を書き換えなくても、環境を切り替えられるようになりたいです!
コウ君、それはヒヤリハットね!でも良い経験よ。
「値(パラメータ)」と「処理(ロジック)」を分離することこそが、Infrastructure as Code (IaC) の真髄なの。
今回はその第一歩として、「変数(Variables)」と、Ansibleが自動で集める情報「Facts」をマスターしましょう。
これが分かれば、Playbookの行数は半分以下に減らせるわよ!
本連載では、実務で即戦力となるAnsibleの中級テクニックを、全8回にわたって徹底解説します。
🚀 【続・Ansible講座】本連載のカリキュラム
- 【第1回】変数(Variables)とFactsの活用(今回):環境差異を吸収する
- 【第2回】ループと条件分岐 (Loop & When):複雑なロジックを組む
- 【第3回】ハンドラーと通知 (Handlers):無駄な再起動を防ぐ
- 【第4回】テンプレート (Jinja2):設定ファイルを動的に生成する
- 【第5回】ロール (Roles) の設計:Playbookを部品化して再利用する
- 【第6回】Ansible Vault:パスワードなどの機密情報を暗号化する
- 【第7回】エラーハンドリングとデバッグ:止まらない自動化のために
- 【第8回】実践プロジェクト:LAMP環境の完全自動構築と総まとめ
目次
1. なぜ「変数」が必要なのか? ハードコーディングの罪
プログラミングにおいて、具体的な値(IPアドレス、パスワード、ファイルパスなど)をソースコードの中に直接書いてしまうことを「ハードコーディング」と呼びます。
Ansibleにおいて、ハードコーディングは以下のような問題を引き起こします。
ハードコーディングのデメリット
- 再利用性の低下:
「WebサーバーA」用に書いたPlaybookを「WebサーバーB」に使おうとしたとき、ファイル内のIPアドレスやホスト名をすべて書き直す必要があります。 - 修正漏れのリスク:
「Apacheのバージョンを 2.4.6 から 2.4.57 に上げたい」と思ったとき、Playbook内に散らばる “2.4.6” という記述を10箇所修正するのは大変です。1箇所でも漏れればエラーになります。 - セキュリティリスク:
パスワードなどの機密情報をPlaybookに直接書くと、Gitなどで共有した際に漏洩する危険があります。
これらの問題を解決するのが「変数(Variables)」です。
「値」を変数として外に出し、Playbookの中では {{ variable_name }} のように参照する形にします。
2. 変数の定義と使い方(基本編)
Ansibleでは、変数の定義する方法がいくつかありますが、まずは最も基本的なPlaybook内での定義方法を見てみましょう。
2-1. varsセクションでの定義
Playbookの vars: セクションで変数を定義し、タスク内で {{ }} で囲んで使用します。
💡 文法チェック:Jinja2テンプレート
Ansibleでは変数の展開にPython製のテンプレートエンジン「Jinja2」を使用します。{{ my_variable }} のように二重中括弧で囲むのがルールです。
注意:YAMLの仕様上、{{ }} で始まる値は辞書(マップ)と誤認されやすいため、必ず全体をクォート "{{ var }}" で囲む必要があります。
実践:Webサーバー構築(変数版)
以下のPlaybookを作成してみましょう。
インストールするパッケージ名と、ドキュメントルートを変数化しています。
ファイル名:vars_test.yml
---
- name: 変数のテスト
hosts: all
become: true
# ここで変数を定義します
vars:
web_package: httpd
doc_root: /var/www/html
page_content: "Hello, Ansible Variables!"
tasks:
- name: Webサーバーをインストール
ansible.builtin.dnf:
name: "{{ web_package }}"
state: present
- name: Webサーバーを起動
ansible.builtin.service:
name: "{{ web_package }}"
state: started
enabled: true
- name: トップページを作成
ansible.builtin.copy:
content: "{{ page_content }}\n"
dest: "{{ doc_root }}/index.html"
mode: '0644'
このPlaybookの優れた点は、「Ubuntu用に使いたいなら web_package: apache2 に書き換えるだけ」で済む点です。
タスクの中身(ロジック)を触る必要はありません。
2-2. 実行時に変数を渡す (Extra Vars)
変数は、Playbookの中に書くだけでなく、コマンド実行時に外から注入することもできます。-e オプションを使います。
ansible-playbook vars_test.yml -e "page_content='Overwritten by Command!'"
こうすると、Playbook内の定義よりもコマンドライン引数が優先され、Webページの中身が書き換わります。
CI/CDパイプラインなどで、ビルド番号などを動的に渡す際によく使われます。
3. 【重要】変数をどこに書くべきか?(ベストプラクティス)
「vars: セクションに変数を書く」のは簡単ですが、サーバーの台数が増えるとPlaybookが肥大化して管理しきれなくなります。
実務では、変数を「インベントリ(Inventory)」に関連付けて管理するのが一般的です。
3-1. host_vars と group_vars
Ansibleには、「特定のホスト」や「特定のグループ」専用の変数を格納するディレクトリ構造の決まりがあります。
group_vars/: サーバーグループごとの変数を置くディレクトリ- 例:
group_vars/webservers.yml(Webサーバーグループ共通の設定) - 例:
group_vars/dbservers.yml(DBサーバーグループ共通の設定)
- 例:
host_vars/: 特定の1台だけの変数を置くディレクトリ- 例:
host_vars/192.168.1.10.yml(そのサーバー固有のIPやIDなど)
- 例:
ディレクトリ構成の例
.
├── inventory.ini
├── site.yml (Playbook)
├── group_vars/
│ ├── all.yml # 全サーバー共通 (NTP設定など)
│ └── webservers.yml # Webサーバー用の変数 (Apache設定など)
└── host_vars/
└── db-master.yml # DBマスター機固有の設定
このようにファイルを分割することで、Playbook本体(site.yml)はすっきりとロジックだけになり、環境ごとのパラメータは vars ディレクトリで管理できるようになります。
これが「IaCにおける整理整頓」の第一歩です。
4. Ansible Facts(自動収集変数)の活用
自分で定義する変数だけでなく、Ansibleが自動的に集めてくれる変数があります。
それが「Facts(ファクト)」です。
4-1. Factsとは?
AnsibleがPlaybookを実行する際、最初に Gathering Facts というタスクが自動で走っているのに気づきましたか?
ここでAnsibleは対象サーバーに接続し、OSの種類、IPアドレス、メモリ容量、ディスク空き容量などの情報を収集し、変数として格納しています。
4-2. どんな情報が取れるのか確認する
アドホックコマンドを使って、実際に取れる情報を見てみましょう。
![]() |
最短突破 LinuCレベル1 バージョン10.0合格教本[101試験, 102試験対応] 改訂新版 新品価格 |
ansible localhost -m setup
膨大なJSONデータが返ってきます。
よく使うFacts変数は以下の通りです。
| 変数名 | 格納されている値 |
|---|---|
ansible_distribution |
OSの種類(CentOS, Ubuntu, Rockyなど) |
ansible_distribution_major_version |
OSのメジャーバージョン(8, 9, 22など) |
ansible_default_ipv4.address |
そのサーバーのIPアドレス |
ansible_processor_vcpus |
CPUのコア数 |
ansible_memtotal_mb |
メモリ総量(MB) |
4-3. Factsを使った条件分岐(導入編)
Factsを使えば、「OSによって処理を変える」といったことが可能になります。
(詳しくは第2回の「条件分岐」で解説しますが、ここでは雰囲気だけ掴んでください)
- name: RedHat系の場合の処理
debug:
msg: "これはRHEL/CentOS/AlmaLinuxです。yum/dnfを使います。"
when: ansible_distribution == "AlmaLinux"
このように、Factsは「サーバーの状態に応じた動的な構成管理」を行うための強力な武器になります。
5. 実行結果を変数に入れる「register」
「コマンドを実行して、その結果によって次の処理を変えたい」という場面は多々あります。
例えば、「ファイルが存在するか確認し、存在しなければ作成する」といったケースです。
この時に使うのが register です。
registerの使用例
Linuxの date コマンドを実行し、その結果を変数 current_time に保存して表示するPlaybookです。
---
- name: registerのテスト
hosts: localhost
connection: local
tasks:
- name: 現在時刻を取得
ansible.builtin.command: date "+%Y-%m-%d %H:%M:%S"
register: current_time_result # ここで結果を変数に入れる
- name: 結果の中身を確認
ansible.builtin.debug:
var: current_time_result
- name: 標準出力だけを表示
ansible.builtin.debug:
msg: "現在は {{ current_time_result.stdout }} です。"
実行すると、current_time_result という変数には、コマンドの終了コード(rc)、標準出力(stdout)、標準エラー出力(stderr)などがオブジェクトとして格納されていることが分かります。
欲しい情報(今回は stdout)を取り出して使うのがポイントです。
⚠️ プロの注意点:commandモジュールの濫用
command や shell モジュールで何でもやろうとするのは「Ansibleアンチパターン」です。register は便利ですが、「既存のモジュール(file, serviceなど)で実現できないか?」を常に考える癖をつけましょう。モジュールを使ったほうが、冪等性(何度実行しても同じ結果になる性質)が担保されやすいためです。
6. 【プロのノウハウ】変数の優先順位と命名規則
最後に、実務でトラブルになりやすい「変数の優先順位」と「名前の付け方」について解説します。
6-1. 変数の優先順位(Precedence)
Ansibleでは、同じ名前の変数を複数の場所(group_vars, Playbook内, コマンド引数など)で定義できます。
もし重複した場合、どちらが勝つのでしょうか?
ざっくりとした「強さ」の順序は以下の通りです(下が強い)。
group_vars/all.yml(一番弱い:デフォルト値として使う)group_vars/webservers.yml(グループ固有)host_vars/server1.yml(ホスト固有)- Playbook内の
vars: - コマンドライン引数
-e(最強:一時的な上書き用)
基本方針として、「広い範囲(all)でデフォルト値を定義し、狭い範囲(host_vars)で必要に応じて上書きする」という設計にすると、管理がしやすくなります。
6-2. 命名規則(Naming Convention)
変数が何千個にもなると、「これ何の変数だっけ?」と混乱します。
プロの現場では、変数の役割がひと目で分かるようにプレフィックス(接頭辞)をつけることが多いです。
apache_port(アプリ名_役割)mysql_root_passwordcommon_ntp_server
また、すべてスネークケース(小文字とアンダースコア)で書くのがAnsibleの標準的な作法です。ApachePort や apachePort ではなく、apache_port と書きましょう。
まとめ:Playbookに「柔軟性」を与えよう
お疲れ様でした!
第1回では、脱・初心者のための第一歩として「変数」と「Facts」について学びました。
今回の要点まとめ:
- ハードコーディングは敵。 値は変数として外に出す。
- 変数は
{{ variable }}で呼び出し、全体をクォートする。 - group_vars と host_vars を使って、環境ごとの設定を整理する。
- Ansible Facts を使えば、サーバーの情報を自動で取得できる。
- register を使えば、コマンドの結果に応じた処理ができる。
なるほど!
「値」を外に出すだけで、Playbookがこんなにスッキリして使い回せるようになるんですね。
これなら本番環境と開発環境の切り替えも怖くないです!
次回は、プログラミング的な要素である「ループ(繰り返し)」と「条件分岐(if文)」について学びます。
これを使えば、「ユーザーを100人一気に作成する」とか「RedHat系とDebian系で処理を分ける」といった、さらに高度な自動化が可能になります。
次回、【第2回】ループと条件分岐 (Loop & When) でお会いしましょう!
▼ Ansibleの実験場を作ろう ▼
複数台構成の実験に最適
「おすすめVPS」
自動化スキルを活かす
「ITエンジニア転職」


コメント