ansible-playbookコマンドの使い方|インベントリ・playbook作成からLinuxサーバー自動化の実践例まで

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOME > Linux技術 リナックスマスター.JP(Linuxマスター.JP) > Linuxtips > ansible-playbookコマンドの使い方|インベントリ・playbook作成からLinuxサーバー自動化の実践例まで
「サーバーに同じ設定を何台も手作業で適用している」「設定漏れがあとから発覚して障害になった」——こういった経験をしたことがある管理者は少なくありません。
台数が増えるほど手作業は限界になり、冪等性のない手順書はいつか破綻します。

この記事では、Linuxサーバーの構成管理・自動化ツールとして実務で広く使われている ansible-playbook コマンド の使い方を解説します。
インベントリの書き方から playbook の基本構文、変数・ハンドラー・ロールの使い方、site.yml × import_playbook による Playbook 一元管理、Playbookの役割別・オペレーション別の分割パターン、commonロールによるベースライン設定の統一、GitHub Actions との連携、トラブルシュートまで、実務で使える形でまとめています。

動作確認環境:RHEL 9.4 / AlmaLinux 9.4 / Ubuntu 24.04 LTS(Ansible 2.16)

この記事のポイント

・ansible-playbookはYAMLのplaybookでサーバーを冪等設定できる
・インベントリでホスト一覧を定義してplaybookで操作対象を指定する
・--checkでドライラン、-v/-vvvでデバッグが本番適用前の基本
・ハンドラーで「変更時だけ再起動」を安全に制御できる
・site.yml×import_playbookで役割別・オペレーション別Playbookを一元管理できる
・import_playbookはPlaybook全体・import_tasksはtask列のみを読む別物
・commonロールをhosts:allで全ホストにベースライン設定を適用できる
・roleは「何を設定するか」、Playbookは「どこに配るか」で責任を分ける
・GitHub Actionsと連携してPlaybook検証・デプロイを自動化できる


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Ansibleとansible-playbookコマンドとは

Ansibleは Red Hat が開発するオープンソースの構成管理・自動化ツールです。
エージェントレス(管理対象サーバー側に専用ソフトを入れない方式)で動作し、SSH(Linuxの場合)でリモートサーバーに接続して設定を適用します。管理対象のサーバー側には Python が入っていれば追加ソフトウェアは不要という点が、他のツールと比較して導入のハードルを下げています。

ansible-playbook は、Ansibleが提供するコマンドの中核であり、YAML形式で書かれた「playbook」と呼ばれる手順書を読み込んでサーバーへ適用します。コマンド1回で何十台のサーバーを同時に設定でき、何度実行しても同じ結果になる冪等性(べきとうせい)が最大の強みです。

Ansibleには複数のコマンドがありますが、それぞれの役割はこのようになっています。
コマンド 役割
ansible アドホックな単発コマンド実行
ansible-playbook yamlファイルで定義した手順を実行(本記事のメイン)
ansible-inventory インベントリの確認・デバッグ
ansible-galaxy ロールやコレクションの管理
ansible-vault 機密情報の暗号化

Ansibleのインストール方法

1. RHEL 9・AlmaLinux 9・Rocky Linux 9の場合

EPEL リポジトリから Ansible をインストールします。

# EPELリポジトリの有効化 sudo dnf install -y epel-release # Ansibleのインストール sudo dnf install -y ansible # バージョン確認 ansible --version

2. Ubuntu 24.04 LTSの場合

Ubuntu では apt もしくは PPA から Ansible をインストールできます。

# 公式PPAを追加してからインストール(最新版を使う場合) sudo apt-add-repository --yes --update ppa:ansible/ansible sudo apt install -y ansible # または標準リポジトリから(バージョンは古い場合あり) sudo apt install -y ansible # バージョン確認 ansible --version

3. pipを使ってインストールする場合

DNF/apt が使えない環境や、最新版を使いたい場合は pip でもインストールできます。Python の仮想環境(venv)に閉じ込めると OS 側の Python 環境を汚さずに済みます。

# 仮想環境の作成とAnsibleのインストール python3 -m venv ~/ansible-env source ~/ansible-env/bin/activate pip install ansible ansible-lint # バージョン確認 ansible --version ansible-lint --version

実行例(AlmaLinux 9.4上での出力):

[admin@controller ~]$ ansible --version ansible [core 2.16.3] config file = /etc/ansible/ansible.cfg configured module search path = ['/home/admin/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] ansible python module location = /usr/lib/python3.11/site-packages/ansible ansible collection location = /home/admin/.ansible/collections:/usr/share/ansible/collections executable location = /usr/bin/ansible python version = 3.11.7 jinja2 version = 3.1.2 libyaml = True

インベントリの書き方

インベントリは、Ansible が操作する対象サーバーの一覧を定義するファイルです。デフォルトパスは /etc/ansible/hosts ですが、-i オプションで任意のファイルを指定するのが実務では一般的です。

1. INI形式インベントリの基本

# /etc/ansible/hosts または任意の inventory.ini # 単独のホスト指定 web01.example.com 192.168.10.11 # グループ化 [webservers] web01.example.com web02.example.com [dbservers] db01.example.com ansible_user=dbadmin ansible_port=2222 # グループのグループ(親グループ) [datacenter:children] webservers dbservers

2. YAML形式インベントリ(推奨)

YAML形式はより読みやすく、変数との親和性が高いため実務では推奨されます。

# inventory.yml all: children: webservers: hosts: web01.example.com: ansible_user: ec2-user web02.example.com: ansible_user: ec2-user dbservers: hosts: db01.example.com: ansible_user: dbadmin ansible_port: 2222 vars: ansible_ssh_private_key_file: ~/.ssh/id_rsa

3. インベントリの確認

# インベントリ内のホスト一覧を表示 ansible-inventory -i inventory.yml --list # グラフ形式で確認 ansible-inventory -i inventory.yml --graph # 疎通確認(pingモジュール) ansible -i inventory.yml webservers -m ping

playbookの基本構文と作成方法

1. playbookの最小構成

playbook は YAML 形式で記述する「自動化の設計書」です。以下が最小限の構成です。

# site.yml --- - name: Webサーバー初期設定 hosts: webservers become: yes # sudo で実行 tasks: - name: Apacheのインストール ansible.builtin.dnf: name: httpd state: present - name: Apacheの起動と自動起動有効化 ansible.builtin.service: name: httpd state: started enabled: yes

YAML の構造として覚えておくべきポイントを整理します。

・hosts:操作するグループまたはホスト名(インベントリと一致させる)
・become:yes にすると sudo(root 権限)で実行
・tasks:実行するタスクのリスト
・name:タスクの説明文(ログに表示される)
・モジュール名:実際に行う操作(dnf, service, copy 等)

2. when条件でOSごとに処理を切り替える

実務では RHEL 系と Ubuntu 系が混在する環境が少なくありません。when 条件を使うと、OS種別によってモジュールを切り替えられます。

tasks: - name: Apacheのインストール(RHEL系) ansible.builtin.dnf: name: httpd state: present when: ansible_os_family == "RedHat" - name: Apacheのインストール(Debian系) ansible.builtin.apt: name: apache2 state: present when: ansible_os_family == "Debian"

ansible_os_family は Gathering Facts で自動取得される変数です。このように同一 playbook でマルチOS環境に対応できます。

3. よく使うモジュール一覧

モジュール 役割 使用例
ansible.builtin.dnf RHEL系パッケージ管理 Apache, nginxのインストール
ansible.builtin.apt Debian系パッケージ管理 Ubuntu環境でのインストール
ansible.builtin.service サービス管理 起動・停止・自動起動設定
ansible.builtin.copy ファイルのコピー 設定ファイルの配布
ansible.builtin.template テンプレートからファイル生成 Jinja2変数展開付きの設定配布
ansible.builtin.user ユーザー管理 ユーザー作成・削除・グループ追加
ansible.builtin.file ファイル・ディレクトリ管理 パーミッション設定・シンボリックリンク
ansible.builtin.lineinfile ファイル内の行編集 設定ファイルの特定行変更
ansible.builtin.command 任意コマンドの実行 専用モジュールがない処理
ansible.builtin.shell シェル経由でコマンド実行 パイプ・リダイレクトを含む処理

ansible-playbookコマンドの基本的な使い方

1. 基本実行

# 基本実行 ansible-playbook -i inventory.yml site.yml # SSH鍵を指定して実行 ansible-playbook -i inventory.yml site.yml --private-key=~/.ssh/id_rsa # sudo パスワードを対話的に入力する場合 ansible-playbook -i inventory.yml site.yml --ask-become-pass

2. 実行前のドライラン(--check)

--check オプションは実際には変更を行わず、何が変わるかを事前確認するためのモードです。本番環境への適用前に必ず使う習慣をつけましょう。--diff を組み合わせると、設定ファイルの変更行が diff 形式で表示されるためさらに確認しやすくなります。

# ドライラン(変更は行わず確認のみ) ansible-playbook -i inventory.yml site.yml --check # ドライランと差分表示を組み合わせる(より詳細) ansible-playbook -i inventory.yml site.yml --check --diff

3. 特定のホストやグループだけ実行(--limit)

# 特定ホストのみ実行 ansible-playbook -i inventory.yml site.yml --limit web01.example.com # 特定グループのみ実行 ansible-playbook -i inventory.yml site.yml --limit webservers # 複数ホストをカンマ区切りで指定 ansible-playbook -i inventory.yml site.yml --limit "web01.example.com,web02.example.com" # パターンマッチでホストを絞る(ワイルドカード使用可) ansible-playbook -i inventory.yml site.yml --limit "web*"

4. 特定タスクだけ実行(タグ機能)

大規模な playbook では、特定のタスクだけを実行したい場面があります。タグ機能を使うと、対象を絞り込めます。

# playbook にタグを付ける例 --- - name: Webサーバー設定 hosts: webservers become: yes tasks: - name: Apacheのインストール ansible.builtin.dnf: name: httpd state: present tags: install - name: 設定ファイルのコピー ansible.builtin.copy: src: httpd.conf dest: /etc/httpd/conf/httpd.conf tags: config # installタグのタスクのみ実行 ansible-playbook -i inventory.yml site.yml --tags install # configタグのタスクをスキップ ansible-playbook -i inventory.yml site.yml --skip-tags config

タグを実行する前に、playbook 内に定義されているタグの種類を確認しておくと安全です。

# 定義されているタグ一覧を事前確認する ansible-playbook -i inventory.yml site.yml --list-tags

実行例:

playbook: site.yml play #1 (webservers): Webサーバー設定 TAGS: [] TASK TAGS: [config, install, service] play #2 (dbservers): DBサーバー設定 TAGS: [] TASK TAGS: [config, install]

タグの命名規約をプロジェクト初期から決めておくと、メンバーが増えても混乱を防げます。実務でよく使われる分け方は次の3パターンです。

・機能タグ:webserver, database, monitoring のように「何を設定するか」で分類する
・操作タグ:install, configure, restart のように「どのオペレーションか」で分類する
・neverタグ:通常実行ではスキップし、--tags never を明示したときだけ動かす特殊タグ。初回セットアップのみ実行したい初期化処理などに活用できる

5. 冗長ログでデバッグ(-v / -vvv)

# 標準の詳細ログ ansible-playbook -i inventory.yml site.yml -v # さらに詳細なデバッグ情報(SSH接続情報も表示) ansible-playbook -i inventory.yml site.yml -vvv # 最大詳細ログ(機密情報も表示されるため開発環境限定・本番では使用禁止) ansible-playbook -i inventory.yml site.yml -vvvv

実務でよく使う構成パターン

1. 変数を使って設定値を管理する

ハードコーディングを避け、変数で設定値を管理することで playbook の再利用性が大幅に上がります。

# site.yml --- - name: Webサーバー設定 hosts: webservers become: yes vars: http_port: 80 max_clients: 200 server_name: "{{ inventory_hostname }}" tasks: - name: httpdのインストール ansible.builtin.dnf: name: httpd state: present - name: 設定ファイルをテンプレートから生成 ansible.builtin.template: src: httpd.conf.j2 dest: /etc/httpd/conf/httpd.conf owner: root group: root mode: '0644'

変数の優先順位(低→高)を理解しておくと、環境ごとの上書きが意図通りに動くようになります。

・group_vars/all:全グループ共通の変数ファイル
・group_vars/グループ名:グループ別の変数ファイル
・host_vars/ホスト名:ホスト別の変数ファイル
・playbook内のvars:playbook単位の変数
・--extra-vars(-e):コマンドライン引数(最高優先度)

2. ハンドラーで変更があった時だけ再起動する

設定ファイルが変更されたときだけサービスを再起動したい——この要件を安全に実装するのがハンドラーです。

--- - name: Apacheの設定と起動 hosts: webservers become: yes handlers: - name: apache再起動 ansible.builtin.service: name: httpd state: restarted tasks: - name: Apacheのインストール ansible.builtin.dnf: name: httpd state: present - name: 設定ファイルのコピー ansible.builtin.copy: src: httpd.conf dest: /etc/httpd/conf/httpd.conf notify: apache再起動 # 変更があった時だけハンドラーを呼び出す

ハンドラーは、notify で指定した処理が「変更(changed)」になった時のみ、playbook の末尾で1度だけ実行されます。複数のタスクが同じハンドラーを notify しても、1回しか実行されないため、無駄な再起動を防ぎます。

ハンドラーが発火したとき、実行ログには通常タスクとは別に RUNNING HANDLERS セクションが表示されます。

TASK [設定ファイルのコピー] ***************************************************** changed: [web01.example.com] changed: [web02.example.com] RUNNING HANDLERS *********************************************************** TASK [apache再起動] ********************************************************** changed: [web01.example.com] changed: [web02.example.com] PLAY RECAP ***************************************************************** web01.example.com : ok=3 changed=2 unreachable=0 failed=0 skipped=0 web02.example.com : ok=3 changed=2 unreachable=0 failed=0 skipped=0

設定ファイルに変更がなかった場合(2回目の実行など)、RUNNING HANDLERS セクション自体が出力されず、不要な再起動が走らないことが確認できます。

3. 実行結果の確認とデバッグ

実サーバー上での実行結果(出力例)を確認しておきます。

[admin@controller ~]$ ansible-playbook -i inventory.yml site.yml PLAY [Webサーバー初期設定] **************************************************** TASK [Gathering Facts] ********************************************************* ok: [web01.example.com] ok: [web02.example.com] TASK [Apacheのインストール] ***************************************************** changed: [web01.example.com] changed: [web02.example.com] TASK [Apacheの起動と自動起動有効化] ******************************************** changed: [web01.example.com] changed: [web02.example.com] PLAY RECAP ********************************************************************* web01.example.com : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 web02.example.com : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

各タスクのステータスの意味を押さえておきましょう。

・ok:変更なし(すでに正しい状態)
・changed:変更を適用した
・failed:エラーが発生した
・unreachable:SSH接続できなかった
・skipped:条件(when)によりスキップ

4. ローリングデプロイ(serialオプション)

本番に10台のWebサーバーがある状態でPlaybookを実行すると、デフォルトでは全台に一斉に変更が適用されます。万が一障害が発生した場合のリスクを下げるために、serial オプションで1回に更新する台数を絞るのが実務でよく使われるパターンです。

# site.yml --- - name: Webサーバーの構成適用 hosts: webservers serial: 2 # 一度に2台ずつ更新 max_fail_percentage: 30 # 30%超失敗で中断 become: yes roles: - nginx

max_fail_percentage を設定しておくと、一定割合以上のサーバーで失敗が発生した時点でPlaybookが中断されます。無言で全台に壊れた設定が広がる事態を防ぐための安全装置です。

ロールを使ってplaybookを整理する

playbook が大きくなってきたら、ロール(Role)を使って機能ごとに分割します。ロールは Ansible の推奨する構成管理パターンで、再利用性が大幅に向上します。

1. ロールのディレクトリ構造

# ansible-galaxy コマンドでロールの雛形を作成 ansible-galaxy init roles/webserver # 生成されるディレクトリ構造 roles/ └── webserver/ ├── tasks/ │ └── main.yml # メインのタスク定義 ├── handlers/ │ └── main.yml # ハンドラー定義 ├── templates/ │ └── httpd.conf.j2 # Jinja2テンプレート ├── files/ ├── vars/ │ └── main.yml # 変数定義(上書き不可の固定変数) ├── defaults/ │ └── main.yml # デフォルト変数(呼び出し側から上書き可能) ├── meta/ │ └── main.yml # ロールのメタ情報 └── README.md

defaults/main.yml と vars/main.yml の使い分けは初学者が迷いやすい箇所です。

・defaults/main.yml:呼び出し側から上書き可能なデフォルト変数(ポート番号・ファイルパス・フラグなど)
・vars/main.yml:role内部で固定する変数(上書き不可。内部定数・計算済み値など)

大半の変数は defaults/ に置き、本当に上書きを禁止したいものだけ vars/ に入れるのが実務上の基本です。呼び出し側が環境別にポート番号やパスを変えられるよう設計することで、roleの再利用性が高まります。

2. ロールをplaybookから呼び出す

# site.yml(ロール呼び出し版) --- - name: Webサーバーの構成 hosts: webservers become: yes roles: - webserver # roles/webserver/ を自動的に読み込む - firewall # roles/firewall/ も適用

3. ansible-galaxy collectionsでサードパーティ製ロールを活用する

自作ロール以外にも、ansible-galaxy コミュニティが公開している高品質なコレクションを活用できます。

# コレクションのインストール(例:Nginx公式コレクション) ansible-galaxy collection install nginxinc.nginx_core # インストール済みコレクション一覧 ansible-galaxy collection list

社内で使うロールをプロジェクト内の requirements.yml に記述しておくと、CI/CD環境でも一括インストールできて便利です。

4. roleとPlaybookの責任分担を理解する

Ansibleを使い込むにつれ、「この処理はroleに書くべきか、Playbookに書くべきか」という判断に迷うことがあります。判断の基準はシンプルです。
書く場所 責任の問いかけ 具体例
role このサービスを設定するために何をするか Nginxのインストール・設定ファイル配布・起動
Playbook このグループのホストに何を配るか webserversグループにnginxとfirewalldを渡す
roleは「設定の手順書」、Playbookは「どのホストにその手順書を渡すか」を決める指示書です。role内に hosts: の指定を書かないのはこのためです。roleは接続先のホストを知らなくてよく、Playbookが接続先を決めてroleを渡す構造になっています。

この責任境界を守ると、roleは別プロジェクトへの移植が容易になります。Nginxの設定を変えた際の変更が roles/nginx/ 配下だけに閉じるため、プルリクエストのdiffが整理されてチームレビューのコストが下がります。逆に、role内に hosts: やホスト特有の処理を書き込むほど、その恩恵が失われていきます。

もう一つの鉄則が「1ミドルウェア1role」です。「Webサーバー全部入り」のようなroleにnginx・php-fpm・certbotをすべて詰め込むと、nginxだけを別プロジェクトで使い回したいときに丸ごとコピーするしかなくなります。roleの境界はミドルウェア単位で切ることで、再利用性と変更の影響範囲を最小に保てます。

site.ymlとimport_playbookでPlaybookを一元管理する

台数が5台のうちは1本のPlaybookに全設定を書いても問題ありません。しかし担当サーバーが増えるにつれ、1本に詰め込み続けた結果、ファイルが1,000行を超えてから誰も触れなくなった——という状況は現場でよく見られます。具体的には次のような問題が出てきます。

・実行範囲を絞れない:WebサーバーだけOSのパッケージを更新したいのに、DBサーバーの設定まで走ってしまう
・変更が怖くなる:1行変えただけで全サーバーに影響するため、誰も触れなくなる
・レビューが回らない:1,000行のPlaybookをPull Requestで差分確認するのは現実的ではない
・再利用ができない:新しいプロジェクトに同じ設定を持ち出したいとき、コピペしか手段がなくなる

webservers・dbservers・lb といった役割ごとにPlaybookを分割し始めると、「どのPlaybookをどの順で実行するか」を管理する仕組みが必要になります。その答えが site.yml × import_playbook の設計です。

1. site.ymlとimport_playbookの基本構成

site.yml はAnsibleプロジェクトの慣習的なエントリーポイントファイルです。このファイル自体は設定をほとんど持たず、役割別Playbookを import_playbook で束ねる「目次」として機能します。

# プロジェクト構成例 . ├── site.yml ← エントリーポイント ├── webservers.yml ← Webサーバー設定Playbook ├── dbservers.yml ← DBサーバー設定Playbook ├── lb.yml ← ロードバランサー設定Playbook ├── inventory/ │ ├── staging/ │ │ ├── hosts │ │ └── group_vars/ │ └── production/ │ ├── hosts │ └── group_vars/ └── roles/ ├── nginx/ ├── mysql/ └── haproxy/

# site.yml --- # 1. まずロードバランサーを設定 - import_playbook: lb.yml # 2. Webサーバー群の設定 - import_playbook: webservers.yml # 3. DBサーバー群の設定 - import_playbook: dbservers.yml

import_playbook の記述順が実行順序になります。site.yml を1本実行するだけで全サーバーへの設定配布が完了する構造です。各Playbookは独立した hosts: 指定を持つため、それぞれの担当サーバーに対してのみ適用されます。

インベントリをstaging/productionでディレクトリ分けしておくと、-i で渡すパスを変えるだけで環境を切り替えられます。Playbookのコードは共通のままにしておき、環境差異は group_vars/ 内のファイルで吸収するのが実務での定番です。

# staging環境への適用 ansible-playbook -i inventory/staging/hosts site.yml # 本番環境への適用 ansible-playbook -i inventory/production/hosts site.yml

2. include_playbookとimport_playbookの違い

import_playbook と include_playbook は似た見た目ですが、評価タイミングが根本的に異なります。
項目 import_playbook(推奨) include_playbook
評価タイミング 実行前(静的解析時) 実行中(動的)
--list-tasksとの互換性 対応(タスク一覧が確認できる) 非対応(実行しないと展開されない)
--checkドライランとの互換性 正常動作 不完全(実行時展開のため)
ループ内での使用 不可 可(loop:と組み合わせられる)
when:の使用 不可(静的展開のため構文エラー) 可(動的に切り替えられる)
タグの伝播 import_playbook自体にタグを付けると子Playbookのtask全体に伝播 同様だが実行時評価のため挙動が異なる場合あり
site.ymlのエントリーポイント設計では import_playbookを使う のが基本です。ansible-playbook --list-tasks site.yml で実行されるタスク全体を事前に確認でき、--check(ドライラン)も正常に動作するためです。include_playbook は「どのPlaybookを実行するかをループや変数で動的に決めたい」という特殊ケースに限定するのが現場での使い分けです。

【注意】Ansible 2.12以降、include_playbook は廃止されています。Ansible 2.16環境では利用できないため、動的に条件で呼び出しを切り替えたい場合は、後述する「タグを使って特定Playbookだけ実行する」や「環境別エントリーポイントの分離」で対応してください。

【import_playbookとimport_tasksの違い】混同しやすいですが、import_playbook と import_tasks は対象が根本的に異なります。import_playbook は hosts: を含むPlaybook全体を読み込みます。一方 import_tasks は hosts: を持たないtaskの列だけを読み込む別物です。site.ymlから役割別ファイルを束ねる用途には必ず import_playbook を使い、role内部でタスクファイルを分割する場合のみ import_tasks を使う、という使い分けを徹底してください。

3. 環境別エントリーポイントの分離

stagingと本番で同じPlaybookを使いたいが、誤って本番に流してしまうリスクを下げたい場合は、エントリーポイントを環境ごとに分けます。

# プロジェクト構成(環境分離版) . ├── site.yml ← 全環境一括(CI/CD用など) ├── staging.yml ← staging専用エントリーポイント ├── production.yml ← 本番専用エントリーポイント ├── webservers.yml ├── dbservers.yml └── inventory/ ├── staging/ │ └── hosts └── production/ └── hosts

# staging.yml --- - import_playbook: webservers.yml - import_playbook: dbservers.yml # staging実行 ansible-playbook -i inventory/staging/hosts staging.yml # 本番実行 ansible-playbook -i inventory/production/hosts production.yml

エントリーポイントを分けることで「stagingに流すつもりが本番インベントリを指定してしまった」という誤適用を構造的に防ぎやすくなります。インベントリの指定ミスには気づきにくいため、このような設計上の工夫が現場では重要です。

4. タグを使って特定Playbookだけ実行する

import_playbook にタグを付けると、その子Playbookのタスク全体にタグが伝播します。これを利用すると --tags オプションで特定の役割だけを実行できます。

# site.yml(タグ付き) --- - import_playbook: lb.yml tags: lb - import_playbook: webservers.yml tags: web - import_playbook: dbservers.yml tags: db # Webサーバーの設定だけ実行 ansible-playbook -i inventory/hosts site.yml --tags web # 実行対象のタスク一覧を事前確認 ansible-playbook -i inventory/hosts site.yml --tags web --list-tasks

site.ymlから実行しながら「今日はwebだけ」という粒度での制御ができるため、デプロイの柔軟性が高まります。--list-tags で利用可能なタグを事前確認する習慣をつけると、意図しないタスクのスキップも防げます。

# site.yml で利用可能なタグ一覧を確認する ansible-playbook -i inventory/hosts site.yml --list-tags # webタグのタスク一覧を事前確認してから実行する ansible-playbook -i inventory/hosts site.yml --tags web --list-tasks ansible-playbook -i inventory/hosts site.yml --tags web

5. Playbookのオペレーション別分割パターン

ホストグループ別の分割(webservers.yml / dbservers.yml)が基本パターンですが、同じサーバー群でも「誰がいつ実行するか」によって分割する方法もあります。初回セットアップ・アプリデプロイ・パッチ適用は、実行頻度もリスクも異なります。

# オペレーション別分割の構造例 playbooks/ ├── setup.yml # 初回構築(サーバー追加時のみ実行) ├── deploy.yml # アプリデプロイ(頻繁に実行) └── patch.yml # OSパッチ適用(月次)

「誰がいつ実行するか」によってPlaybookを選ぶ設計にすると、開発チームが deploy.yml だけを実行できる権限設計(AWX・Ansible Automation Controller との相性が良い)につながります。セットアップとデプロイでリスクプロファイルが大きく異なるため、1ファイルに混在させず分離しておくと、誤った操作がサービスに影響するリスクを設計レベルで下げられます。

6. commonロールで全ホストのベースラインを統一する

どの分割パターンを選んでも、site.ymlの先頭でcommon.ymlを実行し、全ホストに共通設定を適用するのが実務の定石です。「どのサーバーでもSSHアクセスできる」「どのサーバーでもログのタイムスタンプが揃っている」という状態をインフラ全体で保証するのがcommonロールの役割です。

commonロールに含める典型的な設定:
・ユーザー作成と公開鍵配置:運用担当者のSSHアクセス設定を全ホストで統一する
・タイムゾーンとNTP設定:ログのタイムスタンプを揃えてログ分析を容易にする
・最低限のパッケージインストール:vim, rsync, wget等の運用ツールを全台に配置する
・sshd_configのセキュリティ強化:rootログイン禁止・PasswordAuthentication noを全台統一する

# playbooks/common.yml --- - hosts: all become: yes roles: - common

hosts: all とすることで、inventoryのすべてのホストに共通設定が適用されます。site.ymlを設計する際は、このcommon.ymlを必ず先頭に置くようにします。コメントで意図を明記しておくと、後から読んだチームメンバーにも実行順序の理由が伝わります。

# site.yml(commonロールを先頭に置く構成) --- # 全ホストのベースライン設定(必ず最初に実行) - import_playbook: playbooks/common.yml # インフラ基盤レイヤー - import_playbook: playbooks/dbservers.yml # アプリケーションレイヤー(DBより後) - import_playbook: playbooks/webservers.yml # 監視設定(全サービスが起動してから) - import_playbook: playbooks/monitoring.yml

7. 3層構成WebサーバーへのPlaybook適用実践例

ロードバランサー1台(lb01)、Webサーバー2台(web01・web02)、DBサーバー1台(db01)の構成で、site.yml設計の実際を確認します。

# inventory/production/hosts [lb] lb01 ansible_host=192.168.10.10 [webservers] web01 ansible_host=192.168.10.21 web02 ansible_host=192.168.10.22 [dbservers] db01 ansible_host=192.168.10.31 [all:vars] ansible_user=deploy ansible_ssh_private_key_file=~/.ssh/deploy_key

# site.yml(3層構成完成形) --- # 1. 全4台にベースライン設定(NTP・ユーザー・SSH設定) - import_playbook: playbooks/common.yml # 2. DBを先に構成(WebサーバーからDBへの接続情報が必要なため) - import_playbook: playbooks/dbservers.yml # 3. Webサーバーは必ずDBの後で構成する - import_playbook: playbooks/webservers.yml # 4. LBはWebが起動してから設定(バックエンドIPをヘルスチェック後に登録) - import_playbook: playbooks/lb.yml

各Playbookのロール構成は次のとおりです。

# playbooks/common.yml --- - hosts: all become: yes roles: - common # playbooks/dbservers.yml --- - hosts: dbservers become: yes roles: - mysql # playbooks/webservers.yml --- - hosts: webservers become: yes roles: - nginx - app # playbooks/lb.yml --- - hosts: lb become: yes roles: - haproxy

ansible-playbook -i inventory/production/hosts site.yml を実行すると、4台のサーバーが依存関係の順番に沿って設定されます。Webサーバーだけ再設定したいときは ansible-playbook -i inventory/production/hosts playbooks/webservers.yml を直接実行します。

8. site.yml設計でよくある3つの落とし穴

import_playbookで設計する際に陥りやすいミスを確認しておきます。

【落とし穴1】site.ymlにPlayを直接書いてしまう

site.ymlをエントリーポイントとして設計するなら、その中に tasks: や roles: を直書きしないのが鉄則です。

# NG: site.ymlにPlayを直接書く --- - name: Webサーバーの設定 hosts: webservers roles: - nginx # OK: import_playbookで委譲する --- - import_playbook: webservers.yml

小規模なうちは問題になりませんが、Playが増えるとsite.ymlが数百行に膨れ上がり、どのサーバーにどの設定が当たるかを追うだけで消耗します。最初からimport_playbookで委譲する設計にしておくと、後の整理が格段に楽になります。

【落とし穴2】環境ごとにroleを複製する

設定値を環境ごとに変えたいために roles/nginx-staging/ と roles/nginx-production/ を作ってしまうケースがあります。roleのコードは1つに保ち、環境差異は group_vars/ かroleの defaults/main.yml で吸収するのが正しい設計です。roleを複製すると、片方を更新した際にもう一方への反映が漏れる「二重メンテナンス」が発生します。

【落とし穴3】roleの中でhostsを指定する

roleはhostsを知らない設計が正しいため、role内のtasksにhostやdelegateを埋め込むとroleの再利用性が下がります。「どのホストに適用するか」の制御は、必ず呼び出し元のPlaybookに委ねましょう。

CI/CDへの組み込み(GitHub Actions連携)

PlaybookをGitで管理するだけでは不十分です。「誰がいつ実行したかが追跡できない」「lint違反のあるPlaybookが本番に流れてしまう」——こうした問題が手動実行への依存で必ず起きます。GitHub ActionsにPlaybookを組み込むことで、PRのたびに構文チェックが自動で走り、mainブランチへのマージを実行トリガーにできます。

1. セルフホストランナーをコントロールノードに使う

GitHubがホストする標準ランナーはNATの外側に位置するため、プライベートなサーバーへのSSH接続ができません。社内ネットワーク内またはVPNアクセス可能なサーバーにセルフホストランナーを配置し、Ansibleのコントロールノードとして使うのが最もシンプルな設計です。

セルフホストランナーから対象サーバーへのSSH(22/tcp)疎通は、Linux ポート確認の全コマンドを参考にして事前に確認してください。

2. PRトリガーで構文チェックとlintを自動実行する

# .github/workflows/ansible-syntax-check.yml name: Ansible Syntax Check on: pull_request: paths: - 'playbooks/**' - 'roles/**' - 'inventory/**' jobs: syntax-check: runs-on: self-hosted steps: - uses: actions/checkout@v4 - name: Playbookの構文チェック run: | ansible-playbook playbooks/site.yml --inventory inventory/production/hosts.ini --syntax-check env: ANSIBLE_HOST_KEY_CHECKING: "False" - name: ansible-lintの実行 run: | ansible-lint playbooks/site.yml --profile production

lint違反があるブランチはジョブが失敗してマージをブロックします。PRレビューと同時に品質ゲートが設けられるため、構文エラーが本番まで流れてくることがなくなります。

3. mainマージ後にdry-runと本番適用を行う

本番への自動適用は「mainへのpush」をトリガーにして、dry-runと本番適用の2段階に分けます。

# .github/workflows/ansible-deploy.yml name: Ansible Deploy on: push: branches: - main jobs: dry-run: runs-on: self-hosted steps: - uses: actions/checkout@v4 - name: SSH鍵の配置 run: | mkdir -p ~/.ssh echo "${{ secrets.ANSIBLE_SSH_PRIVATE_KEY }}" > ~/.ssh/ansible_rsa chmod 600 ~/.ssh/ansible_rsa - name: Vaultパスワードファイル作成 run: printf '%s' "${{ secrets.ANSIBLE_VAULT_PASSWORD }}" > /tmp/vault_pass.txt - name: dry-run(--check --diff) run: | ansible-playbook playbooks/site.yml --inventory inventory/production/hosts.ini --vault-password-file /tmp/vault_pass.txt --check --diff --private-key ~/.ssh/ansible_rsa env: ANSIBLE_HOST_KEY_CHECKING: "False" - name: Vaultパスワードファイル削除 if: always() run: rm -f /tmp/vault_pass.txt deploy: needs: dry-run runs-on: self-hosted environment: production # 承認者によるレビューゲート steps: - uses: actions/checkout@v4 # ... (dry-runと同様にPlaybook本番適用)

注意:認証情報(SSHキー・Vaultパスワード)をワークフローYAMLに直接記述することは禁止です。必ずGitHubシークレット経由で渡してください。printf '%s' を使うことで、echo で発生する末尾改行もなくせます。

environment: production にEnvironment protection rulesで承認者を設定しておくと、dry-run完了後に本番適用ジョブが自動開始せず、担当者がGitHub上で承認するまで待機します。

よくあるエラーと対処法

1. SSH接続エラー「UNREACHABLE」

# エラー例 fatal: [web01.example.com]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh", "unreachable": true} # 疎通確認 ansible -i inventory.yml web01.example.com -m ping # SSHで直接接続テスト ssh -i ~/.ssh/id_rsa admin@web01.example.com # インベントリの接続情報を確認 ansible-inventory -i inventory.yml --host web01.example.com

接続に失敗する場合の主な原因を確認します。

・SSH鍵の指定ミス:ansible_ssh_private_key_file が正しいか確認
・known_hostsへの未登録:初回接続時は ansible_host_key_checking=false を一時的に設定
・ファイアウォールのポートブロック:Linux ポート確認の全コマンド で22番ポートの状態を確認
・ユーザー名の誤り:ansible_user の設定を見直す

2. become(sudo)権限エラー

# エラー例 fatal: [web01.example.com]: FAILED! => {"msg": "Missing sudo password"} # 対処1:インタラクティブにパスワードを入力 ansible-playbook -i inventory.yml site.yml --ask-become-pass # 対処2:sudoersでパスワードなしを設定(NOPASSWD) # /etc/sudoers に以下を追加(visudo で編集) # ansibleuser ALL=(ALL) NOPASSWD: ALL

3. モジュールの実行に失敗する「MODULE FAILURE」

# エラー例 fatal: [web01.example.com]: FAILED! => {"changed": false, "msg": "No package matching 'httpd' found available"} # 対処:パッケージリポジトリの確認 # -vvv でより詳細なエラー内容を確認 ansible-playbook -i inventory.yml site.yml -vvv # 手動でパッケージ確認(アドホックコマンド) ansible -i inventory.yml webservers -m shell -a "dnf list available httpd" --become

4. Vault暗号化ファイルの復号に失敗する

ansible-vault で暗号化した変数ファイルを使っているときに「Decryption failed」が出る場合、パスワードの不一致が原因のほぼ全てです。CI/CD環境でGitHubシークレット経由でパスワードを渡す場合は、末尾改行の混入に要注意です。

# 問題:echo は末尾に改行を付与するためパスワードが一致しない echo "$VAULT_PASSWORD" > /tmp/vault_pass.txt # NG # 解決:printf '%s' で末尾改行を除去してから書き出す printf '%s' "$VAULT_PASSWORD" > /tmp/vault_pass.txt # OK # 手動でVaultファイルを検証する ansible-vault decrypt group_vars/production/vault.yml --ask-vault-pass

5. 冪等性が担保されていない処理を書いてしまう

command モジュールや shell モジュールは冪等性がないため、毎回実行されます。同じ処理を繰り返してもサーバーの状態が変わらない書き方を意識しましょう。

# NGパターン(毎回ユーザーを作ろうとする) - name: ユーザー作成 ansible.builtin.shell: useradd appuser # OKパターン(すでに存在していれば変更なし) - name: ユーザー作成(冪等) ansible.builtin.user: name: appuser state: present shell: /bin/bash

6. import_playbookにwhen:を付けてエラーになる

# NG: import_playbookにwhen:は使えない(Ansible 2.12以降include_playbookも廃止) - import_playbook: webservers.yml when: env == "production" # ERROR # OK: エントリーポイントを環境別に分離する # staging.yml / production.yml を別ファイルとして用意する(h3 3参照)

import_playbook は静的解析時に展開されるため、実行時変数を参照する when: が使えません。この制約が問題になる場合は、環境別エントリーポイント(staging.yml / production.yml)に分割する設計を検討してください。

7. 「Could not match supplied host pattern」

インベントリに存在しないホスト名・グループ名をPlaybookの hosts: に指定した場合に発生します。

# 警告例 [WARNING]: Could not match supplied host pattern, ignoring: webservers [WARNING]: No hosts matched, nothing to do # インベントリのグループ構成を確認する ansible-inventory -i inventory.yml --graph # 特定グループのホスト一覧を確認する ansible-inventory -i inventory.yml --list-hosts webservers

Playbookの hosts: webservers とインベントリのグループ名が大文字小文字も含めて完全一致していることを確認してください。また、ansible-playbook をsite.ymlのあるディレクトリ以外から実行すると import_playbook の相対パスが解決されずエラーになる場合があります。常にプロジェクトルートから実行するか、絶対パスで指定する習慣をつけておくと安全です。

8. 「ERROR! 'import_playbook' is not a valid attribute for a Play」が出る

import_playbookはPlaybookのトップレベルにしか書けません。tasksブロックの中やroleの中に書こうとするとこのエラーになります。site.ymlやwebservers.ymlの直下に書いていることを確認してください。

# NG:hostsと同列に書こうとしている(Playbookの中のPlay定義内) - hosts: webservers import_playbook: other.yml # これは不可 # OK:トップレベルに書く(hostsと並列でなく独立したリスト項目として) - import_playbook: playbooks/webservers.yml - hosts: monitoring roles: - prometheus

9. 「ERROR! the file ... does not exist」が出る

import_playbookのパスはsite.ymlからの相対パスで解決されます。実行時のカレントディレクトリではなく、site.ymlの置き場所(通常はプロジェクトルート)からの相対パスです。

# 実行は常にプロジェクトルートから行う cd /home/deploy/ansible-project ansible-playbook -i inventory/production/hosts site.yml # site.yml が /home/deploy/ansible-project/site.yml にある場合 # playbooks/webservers.yml は # /home/deploy/ansible-project/playbooks/webservers.yml を参照する

site.ymlとは別のディレクトリから ansible-playbook /path/to/site.yml と絶対パスで実行した場合も、相対パスの起点はsite.ymlの場所になります。常にプロジェクトルートからの実行を習慣にしてください。

10. site.ymlを実行したのに一部のPlaybookがスキップされる

import_playbookで読み込んだPlaybookの hosts: に指定したグループがインベントリに存在しない場合、そのPlaybookは「0台に対して実行」という扱いでスキップされます。エラーにはならないため気づきにくい挙動です。

# 対象ホスト一覧を事前に確認してスキップを事前検出する ansible-playbook --list-hosts site.yml # インベントリのグループ一覧を確認する ansible-inventory -i inventory/production/hosts --graph

ansible-playbook --list-hosts site.yml で対象ホスト一覧を事前確認する習慣をつけておくと、「実行したのに設定が反映されていない」という見えにくいミスを防げます。

11. import_playbookとimport_tasksを混同する

site.yml内で import_tasks を書いてしまうケースが初学者に多く見られます。import_tasks は hosts: を持たないtaskの列だけを読み込むもので、Playbook全体(hosts:・roles:・tasks: を含む)を読み込む import_playbook とは対象が異なります。

# NG: site.ymlでimport_tasksを使ってしまう --- - import_tasks: webservers.yml # hostsを含むPlaybookには使えない # OK: Playbook全体を読み込む場合はimport_playbook --- - import_playbook: webservers.yml # import_tasksが適切な場面:role内部でのtaskファイル分割 # roles/nginx/tasks/main.yml --- - import_tasks: install.yml # tasks/install.yml のtask列を読む - import_tasks: configure.yml # tasks/configure.yml のtask列を読む

site.yml → import_playbook → 役割別Playbook → role(import_tasks)という経路を守ることで、静的解析・ドライラン・タスク一覧確認がすべて正常に動作します。

ansible-playbookの主要オプション早見表

やりたいこと コマンド・オプション
基本実行 ansible-playbook -i inventory.yml site.yml
ドライラン(変更なし確認) ansible-playbook -i inventory.yml site.yml --check
差分付きドライラン ansible-playbook -i inventory.yml site.yml --check --diff
特定ホストのみ実行 ansible-playbook -i inventory.yml site.yml --limit web01
タグ指定で部分実行 ansible-playbook -i inventory.yml site.yml --tags install
sudo パスワードを対話入力 ansible-playbook -i inventory.yml site.yml --ask-become-pass
変数をコマンドラインで渡す ansible-playbook -i inventory.yml site.yml -e "env=production"
デバッグログの表示 ansible-playbook -i inventory.yml site.yml -vvv
並列実行数を制限(デフォルト5) ansible-playbook -i inventory.yml site.yml -f 2
ステップ実行(タスクごとに確認) ansible-playbook -i inventory.yml site.yml --step
ローリングデプロイ(N台ずつ) playbook内で serial: N を指定
タスク一覧を事前確認 ansible-playbook -i inventory.yml site.yml --list-tasks
対象ホスト一覧を事前確認 ansible-playbook -i inventory.yml site.yml --list-hosts
複数Playbookをエントリーポイントで束ねる site.yml に import_playbook を羅列する

本記事のまとめ

ansible-playbook コマンドは、Linux サーバーの構成管理を「手作業からコード」へ転換する強力なツールです。YAML 形式の playbook でサーバーの「あるべき状態」を定義し、何度実行しても同じ結果になる冪等性が最大の強みです。さらに GitHub Actions と組み合わせることで、構文チェックから本番適用までを自動化し、手動実行の属人化リスクを設計で解消できます。

やること ポイント
インベントリ定義 ターゲットサーバーをINI/YAML形式でグループ化して管理する
本番適用前の確認 --check --diffでドライランと変更差分を視覚化する
変更時だけ再起動 ハンドラー(handlers)でサービス再起動を安全に制御する
playbookの整理・再利用 ロール(roles)で機能ごとに分割して管理する
roleとPlaybookの責任分担 roleは「何を設定するか」、Playbookは「どこに配るか」で責任を分ける
1ミドルウェア1role roleを役割単位で分割して再利用性と変更の影響範囲を最小に保つ
roleの変数設計 上書き可能な設定はdefaults/・固定値はvars/に分けて管理する
段階的なデプロイ serialオプションで一度に更新する台数を制限してリスクを下げる
複数Playbookの一元管理 site.yml×import_playbookでエントリーポイントを1本に集約する
import_playbookとimport_tasksの使い分け Playbook全体はimport_playbook・task列のみはimport_tasksで読み込む
オペレーション別分割 setup/deploy/patchでPlaybookを分割して実行権限と責任を分ける
ベースライン設定の統一 commonロールをhosts:allで全ホストに適用してSSH・NTP・パッケージを統一する
環境間の誤適用を防ぐ staging.yml/production.ymlを分けてエントリーポイントを分離する
CI/CDへの組み込み GitHub Actions+セルフホストランナーでPlaybook検証・デプロイを自動化
エラー発生時のデバッグ -vvvで詳細ログを確認し、原因を特定してから対処する
SSH 接続の基礎については Linux ポート確認の全コマンド、サービス管理については systemd-analyze で起動時間計測、パッケージ管理については rpm コマンドの使い方 も合わせて参照してください。

手作業で30分かかる初期設定が、ansible-playbook 1回で3分に短縮された——そういう体験が、自動化への確信を生みます。まずは手元の検証環境で試してみてください。
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、
Linux Master Pro Seminar(2日間ハンズオン)では Ansible・systemd・セキュリティ設定まで、
実際のサーバーを触りながら自動化と構成管理を習得できます。

>> セミナー詳細・お申込みはこちら

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。