「開発環境」と「本番環境」、Playbookを2つ作っていませんか?
こんにちは!「LINUX工房」管理人の「リナックス先生」です。
前回は、基本的なPlaybookの書き方と、主要モジュールを使ったWebサーバー構築を行いました。
しかし、前回のPlaybookには大きな欠点がありました。
設定ファイル(index.html)の内容が「固定」だったことです。
実際の現場では、こんな要望が必ず出てきます。
「開発環境はログレベルをDEBUGにしたいけど、本番環境はWARNにしたい」
「WebサーバーAには “Server-A”、WebサーバーBには “Server-B” と表示させたい」
先生、まさにそれで困ってました!
開発用と本番用で httpd.conf の設定を変えなきゃいけなくて、httpd_dev.conf と httpd_prod.conf を用意して、Playbookも2つ作って切り替えてます。
でもこれ、修正するとき両方直さなきゃいけないから、絶対いつかミスりますよね…。
そのやり方は「アンチパターン」の代表格ね。
Ansibleには「変数(Variables)」と「テンプレート(Template)」という強力な武器があるの。
これを使えば、たった1つのPlaybookとテンプレートファイルで、環境に合わせた設定ファイルを自動生成できるわ。
今回は、Ansibleを「魔法の杖」に変える、動的生成テクニックをマスターしましょう!
本記事では、AlmaLinux 9 をベースに、変数の定義方法、システム情報の自動取得(Facts)、そしてPythonベースの強力なテンプレートエンジン「Jinja2」を使った設定ファイルの書き換え術について徹底解説します。
🚀 Ansible完全攻略講座(バックナンバー)
現在地:【第4回】変数を使いこなせ。Jinja2テンプレートによる設定ファイルの動的生成
- 【第1回】構成管理の革命児!エージェントレスで始める自動化入門&環境構築
- 【第2回】ターゲットを支配せよ。インベントリの書き方とansible.cfgの最適解
- 【第3回】Playbookの基礎。YAMLの作法と「モジュール」によるタスク定義
- 【第4回】変数を使いこなせ。Jinja2テンプレートによる設定ファイルの動的生成
- 【第5回】コードを整理整頓。Rolesディレクトリ構成と再利用性の最大化
- 【第6回】秘密情報の管理と通知。Ansible Vaultの暗号化とHandlers
- 【第7回】実践演習。LAMP環境(Apache+MySQL+PHP)をボタン一つで構築する
- 【第8回】GUIで管理。Ansible AWX(Tower)入門とCI/CDパイプラインへの統合
第1章:変数(Variables)の基礎知識
プログラミングと同様に、Ansibleでも「値」に「名前」をつけて管理することができます。
変数を使うことで、Playbookの中から具体的な値(IPアドレスやポート番号、ユーザー名など)を追い出し、再利用性を高めることができます。
変数の書き方と参照方法
変数は主にYAML形式で定義し、Playbook内では {{ variable_name }} という形式(二重波括弧)で参照します。
定義例(vars):
vars: http_port: 80 server_name: "my-web-server"
参照例(tasks):
tasks:
- name: Print server name
ansible.builtin.debug:
msg: "This server is {{ server_name }} running on port {{ http_port }}"
変数を定義する3つの場所
Ansibleでは変数を定義できる場所が20箇所以上ありますが、初心者が覚えるべきは以下の3つです。
- インベントリ変数 (Host/Group Vars):
第2回で紹介したgroup_vars/web.ymlやhost_vars/web01.ymlです。
「Webサーバーグループはポート80」「DBサーバーグループはポート3306」といった、ホスト固有の値を定義するのに最適です。 - Playbook変数 (Playbook Vars):
Playbookファイルのvars:セクションに直接書きます。
そのPlaybookだけで使う一時的な定数などに使います。 - コマンドライン変数 (Extra Vars):
実行時に-eオプションで渡します。ansible-playbook site.yml -e "http_port=8080"
最も優先順位が高く、強制的に値を上書きしたい場合に使います。
変数の優先順位(Precedence)
同じ名前の変数が複数の場所で定義されていた場合、以下の順で優先されます(下に行くほど強い)。
- インベントリ変数(group_vars < host_vars)
- Playbook変数(vars)
- コマンドライン変数(-e) ← 最強
第2章:システム情報を自動取得する「Facts変数」
自分で定義する変数の他に、Ansibleが自動的に収集してくれる変数があります。
それが「Facts(ファクト)」です。
Gathering Facts とは?
Playbookを実行した時、最初に TASK [Gathering Facts] という表示が出ますよね?
あそこでAnsibleはターゲットサーバーに潜り込み、OSの種類、IPアドレス、CPUコア数、メモリ容量などの情報を収集し、変数に格納しています。
主要なFacts変数
ansible_ で始まる変数は、Facts変数である可能性が高いです。
| 変数名 | 格納されている値の例 |
|---|---|
ansible_distribution |
OS名 (例: “AlmaLinux”, “Ubuntu”) |
ansible_distribution_major_version |
メジャーバージョン (例: “9”, “22”) |
ansible_default_ipv4.address |
IPアドレス (例: “192.168.1.50”) |
ansible_hostname |
ホスト名 (例: “web01”) |
ansible_processor_vcpus |
CPUコア数 (例: 4) |
inventory_hostname |
インベントリ上の名前 (マジック変数) |
Factsの中身を確認する方法
setup モジュールを使うと、そのサーバーの全Factsを表示できます。
ansible web01 -m setup
大量のJSONが表示されますが、これら全てを変数として利用できるのです。
「OSがRedHat系ならdnf、Debian系ならaptを使う」といった条件分岐(when)などで大活躍します。
第3章:Jinja2(ジンジャーツー)テンプレートの魔術
変数がわかったところで、いよいよ本丸「Jinja2」の登場です。
Jinja2はPython製のテンプレートエンジンで、テキストファイルの中に変数を埋め込んだり、if文などのロジックを書いたりすることができます。
なぜ copy モジュールではダメなのか?
前回使った copy モジュールは、手元のファイルを「そのまま」サーバーに置くだけでした。
しかし、設定ファイル(httpd.conf や nginx.conf)の中身を、サーバーごとに変えたい場合(IPアドレスを埋め込むなど)は、copy では対応できません。
そこで登場するのが template モジュールです。
拡張子 .j2 のテンプレートファイルを処理し、変数を展開した上で、完成形のファイルをサーバーに配置します。
Jinja2の基本構文
主に使うのは以下の3つだけです。
1. 変数の埋め込み
ServerName {{ ansible_hostname }}
Listen {{ http_port }}
二重波括弧 {{ }} で囲むと、その部分が変数の値に置き換わります。
2. 条件分岐 (if)
{% if env == 'production' %}
LogLevel WARN
{% else %}
LogLevel DEBUG
{% endif %}
{% %} で囲むと、制御構文が書けます。
変数 env が ‘production’ なら WARN、それ以外なら DEBUG になります。
3. ループ (for)
{% for ip in allowed_ips %}
Allow from {{ ip }}
{% endfor %}
リスト(配列)の中身を繰り返し出力できます。
第4章:【実践】動的なWebページを作ってみよう
それでは、実際に手を動かしてみましょう。
「各サーバーのホスト名とIPアドレスを表示する index.html」を自動生成して配布します。
1. テンプレートファイルの作成
作業ディレクトリに templates ディレクトリを作り、その中に index.html.j2 を作成します。
mkdir templates nano templates/index.html.j2
index.html.j2 の内容:
<html>
<head><title>Server Info</title></head>
<body>
<h1>Welcome to {{ ansible_hostname }}</h1>
<p>This server's IP address is: {{ ansible_default_ipv4.address }}</p>
<p>Environment: {{ env_name }}</p>
</body>
</html>
{{ env_name }} は、こちらで定義する変数です。
2. 変数の定義
Playbook内で変数を定義します。
nano web_setup.yml
web_setup.yml の内容:
---
- name: Setup Dynamic Web Page
hosts: webservers
become: true
vars:
env_name: "Development" # ここで変数を定義
tasks:
- name: Install Apache
ansible.builtin.dnf:
name: httpd
state: present
- name: Deploy index.html from template
ansible.builtin.template: # copyではなくtemplateを使う!
src: templates/index.html.j2
dest: /var/www/html/index.html
mode: '0644'
- name: Start Apache
ansible.builtin.systemd:
name: httpd
state: started
enabled: true
3. 実行と確認
ansible-playbook web_setup.yml
実行後、ブラウザや curl で各サーバーにアクセスしてみてください。
- web01 にアクセス → “Welcome to web01” … “192.168.1.50”
- web02 にアクセス → “Welcome to web02” … “192.168.1.51”
同じPlaybook、同じテンプレートを使ったのに、サーバーごとに異なる内容のHTMLファイルが生成されました。
これがテンプレートの威力です。
第5章:【応用】設定ファイルの条件分岐(if文)
次はもう少し実用的な、httpd.conf の設定切り替えに挑戦しましょう。
1. シナリオ
- 変数
http_portで待受ポートを変更できるようにする。 - 変数
is_productionがtrueならログレベルをwarnに、falseならdebugにする。
2. テンプレートの作成
既存の httpd.conf を元にするのが安全ですが、ここでは簡易的な例を作ります。
nano templates/httpd.conf.j2
httpd.conf.j2 の内容(抜粋):
# Dynamic Port Configuration
Listen {{ http_port }}
# Log Level Configuration
{% if is_production %}
LogLevel warn
{% else %}
LogLevel debug
{% endif %}
DocumentRoot "/var/www/html"
3. Playbookの修正
---
- name: Setup Apache Config
hosts: webservers
become: true
vars:
http_port: 8080
is_production: false
tasks:
- name: Deploy httpd.conf
ansible.builtin.template:
src: templates/httpd.conf.j2
dest: /etc/httpd/conf/httpd.conf
validate: 'httpd -t -f %s' # ← ここがプロの技!
notify: Restart Apache
handlers:
- name: Restart Apache
ansible.builtin.systemd:
name: httpd
state: restarted
🔥 プロの技:validate オプション
設定ファイルを書き換えて再起動した瞬間、「構文エラーでApacheが起動しない!」という事故は絶対に避けなければなりません。validate オプションを使うと、Ansibleは「ファイルを配置する前に、構文チェックコマンドを実行」してくれます。%s の部分に一時ファイルのパスが入ります。
もしチェックコマンド(httpd -t ...)が失敗したら、ファイルの配置はキャンセルされ、元の設定ファイルが守られます。これは必須テクニックです。
第6章:変数をファイルに切り出す
Playbookの中に vars: を書くと、ファイルが長くなってしまいます。
第2回で紹介したディレクトリ構成に従い、変数を外出ししましょう。
ディレクトリ構成
.
├── inventory.yml
├── group_vars/
│ ├── all.yml # 全サーバー共通 (http_port: 80)
│ └── development.yml # 開発環境用 (http_port: 8080)
├── site.yml
└── templates/
└── httpd.conf.j2
group_vars/all.yml:
http_port: 80 is_production: true
inventory.yml:
all:
children:
development:
hosts:
web-dev.example.com:
vars:
http_port: 8080
is_production: false
production:
hosts:
web-prod.example.com:
このように構成すれば、web-dev にはポート8080とデバッグログ設定が、web-prod にはポート80と警告ログ設定が、1つのPlaybookを実行するだけで自動的に適用されます。
第7章:Jinja2の便利なフィルター機能
最後に、少し便利なJinja2の「フィルター」を紹介します。
パイプ | を使って値を加工できます。
1. default フィルター
変数が定義されていない場合の「デフォルト値」を設定します。
Listen {{ http_port | default(80) }}
これなら、http_port を定義し忘れてもエラーにならず、80番が使われます。
2. upper / lower フィルター
大文字・小文字に変換します。
Environment: {{ env_name | upper }}
出力: Environment: DEVELOPMENT
3. to_nice_json
変数の内容(リストや辞書)をきれいなJSON形式で出力します。デバッグや設定ファイルの生成に便利です。
まとめ:Playbookに「知性」を与えよう
お疲れ様でした!
変数とテンプレートを使いこなすことで、Ansibleは単なる「手順書の代わり」から、「環境に応じて振る舞いを変えるインテリジェントなツール」へと進化しました。
今回の重要ポイント:
- 変数は
{{ var }}で参照。-eオプションが最強。 - Facts変数は、サーバーの情報を自動取得してくれる強い味方。
- 設定ファイルの配布には
copyではなくtemplateモジュールを使う。 - Jinja2を使えば、if文やfor文で設定ファイルを動的に生成できる。
validateオプションで、再起動前の構文チェックを忘れずに。
さて、Playbookが便利になるにつれて、記述量が増えてファイルが長くなってきましたね。
「Webサーバーの設定」と「DBサーバーの設定」を1つのファイルに書くと、見通しが悪くなります。
もっと機能ごとにファイルを分割して、部品化できないでしょうか?
次回、第5回は「コードを整理整頓。Rolesディレクトリ構成と再利用性の最大化」です。
Ansibleにおける「整理整頓の最終形態」である Role(ロール) について学びます。
Roleを使えば、他人が作ったPlaybookを取り込んだり、自分のコードを部品化して使い回したりできるようになります。
本格的な運用の入り口です。お楽しみに!
▼ 変数とテンプレートを実験する ▼
動的構築を試す
「VPS」で自分専用環境
Ansibleスキルを年収に
「ITエンジニア転職」

コメント