Configuration Management with Ansible
Ansibleによる構成管理 — 包括的技術ガイド
カテゴリ: Linux システム管理
対象レベル: 中級〜上級
最終更新: 2026年4月
目次
- はじめに — なぜ構成管理が必要か
- Ansibleの概要と歴史
- アーキテクチャ — 全体像
- 3.1 コントロールノード
- 3.2 マネージドノード
- 3.3 インベントリ
- 3.4 モジュール
- 3.5 プラグイン
- 3.6 APIとAnsible Automation Platform
- インストールとセットアップ
- 4.1 コントロールノードのインストール
- 4.2 SSH鍵の設定
- 4.3 ansible.cfg の設定
- インベントリ管理
- 5.1 静的インベントリ (INI形式)
- 5.2 静的インベントリ (YAML形式)
- 5.3 動的インベントリ
- 5.4 インベントリ変数
- アドホックコマンド
- YAMLとJinja2の基礎
- 7.1 YAML構文
- 7.2 Jinja2テンプレート
- プレイブックの構造
- 8.1 プレイ (Play)
- 8.2 タスク (Task)
- 8.3 ハンドラ (Handler)
- 8.4 変数 (Variables)
- 8.5 ファクト (Facts)
- 8.6 条件分岐 (when)
- 8.7 ループ (loop)
- ロールとAnsible Galaxy
- 9.1 ロールの構造
- 9.2 ロールの作成
- 9.3 Ansible Galaxy
- Ansible Vault — 機密情報の管理
- 主要モジュール詳解
- 11.1 パッケージ管理 (apt / yum / dnf)
- 11.2 サービス管理 (service / systemd)
- 11.3 ファイル操作 (file / copy / template)
- 11.4 ユーザー管理 (user / group)
- 11.5 コマンド実行 (command / shell / raw)
- 11.6 その他の重要モジュール
- エラーハンドリング
- べき等性 (Idempotency)
- IaC ベストプラクティス
- Ansibleと他ツールの比較
- 実践的なプレイブック例
- トラブルシューティング
- 参考資料
1. はじめに
1.1 手動管理の限界
数台のサーバーを管理している場合、SSHでログインして手動でコマンドを実行することは現実的です。しかし、サーバーが数十台、数百台、数千台になると次のような問題が発生します。
| 課題 | 内容 |
|---|---|
| スケーラビリティ | 手動作業では追いつかない台数になる |
| 一貫性の欠如 | 設定のドリフト(構成ずれ)が発生しやすい |
| 属人化 | 担当者しか手順を知らない |
| 監査困難 | 「誰が何をいつ変更したか」の追跡が困難 |
| ヒューマンエラー | タイポや手順の誤りによる障害リスク |
| ドキュメント陳腐化 | 実態と手順書が乖離する |
1.2 構成管理ツールが解決すること
構成管理ツール(Configuration Management Tool; CMT)は以下を実現します。
- コードによるインフラの定義 (Infrastructure as Code; IaC)
- 宣言的または手続き的な状態の記述
- 自動化された繰り返し可能な実行
- バージョン管理によるインフラ変更の追跡
- テスト可能なインフラ定義
2. Ansibleの概要と歴史
2.1 概要
Ansible(アンシブル)は Red Hat が開発するオープンソースの構成管理・プロビジョニング・アプリケーションデプロイツールです。
主な特徴は以下の通りです。
| 特徴 | 説明 |
|---|---|
| エージェントレス | マネージドノードにエージェントソフトウェアのインストール不要 |
| SSH/WinRM ベース | 既存の通信プロトコルを利用 |
| YAML による記述 | 人間が読み書きしやすいフォーマット |
| べき等性 | 何度実行しても同じ結果になる設計 |
| 豊富なモジュール | 5,000以上のビルトインモジュール |
| マルチプラットフォーム | Linux, Windows, ネットワーク機器, クラウドに対応 |
2.2 歴史
2012年 Michael DeHaan が Ansible を創設
2013年 Ansible, Inc. 設立
2015年 Red Hat が Ansible, Inc. を買収
2019年 Ansible Engine 2.8 リリース、コレクション機能の強化
2021年 Ansible Automation Platform 2.0 リリース
2023年 ansible-core 2.15、コレクションベースアーキテクチャの成熟
2024年 ansible-core 2.17、Python 3.12 サポート強化
2.3 Ansible のエコシステム
┌─────────────────────────────────────────────────────────┐
│ Ansible Ecosystem │
│ │
│ ┌─────────────┐ ┌──────────────┐ ┌───────────────┐ │
│ │ansible-core │ │ Collections │ │ AWX / │ │
│ │(エンジン本体) │ │ (モジュール群) │ │ AAP │ │
│ └─────────────┘ └──────────────┘ └───────────────┘ │
│ ┌─────────────┐ ┌──────────────┐ ┌───────────────┐ │
│ │Ansible Vault│ │Ansible Galaxy│ │ Molecule │ │
│ │(暗号化) │ │(共有リポジトリ) │ │ (テスト) │ │
│ └─────────────┘ └──────────────┘ └───────────────┘ │
└─────────────────────────────────────────────────────────┘
3. アーキテクチャ
3.1 全体アーキテクチャ図
┌─────────────────────────────────┐
│ Control Node │
│ (Ansible がインストールされた │
│ 管理用サーバーまたはPC) │
│ │
│ ┌──────────┐ ┌─────────────┐ │
│ │Inventory │ │ Playbooks │ │
│ │ (静的/動的)│ │ (YAML) │ │
│ └──────────┘ └─────────────┘ │
│ ┌──────────┐ ┌─────────────┐ │
│ │ Modules │ │ Variables │ │
│ │(Python等) │ │ & Vault │ │
│ └──────────┘ └─────────────┘ │
└──────────┬──────────────────────┘
│ SSH / WinRM
┌────────────────┼────────────────┐
│ │ │
┌────────▼──────┐ ┌───────▼──────┐ ┌──────▼────────┐
│ Managed Node │ │ Managed Node │ │ Managed Node │
│ web01 │ │ db01 │ │ app01 │
│ (Linux/UNIX) │ │ (Linux/UNIX) │ │ (Windows) │
└───────────────┘ └──────────────┘ └───────────────┘
3.2 コントロールノード (Control Node)
コントロールノードは Ansible がインストールされ、プレイブックや ad-hoc コマンドを実行するマシンです。
要件:
- Linux/macOS/UNIX系 OS(Windowsはコントロールノードとして非サポート、WSL2は可)
- Python 3.9 以上(ansible-core 2.15+)
- SSH クライアント
主要な設定ファイルの場所:
/etc/ansible/ansible.cfg # システム全体の設定
~/.ansible.cfg # ユーザー設定(優先度高)
./ansible.cfg # カレントディレクトリ(最高優先度)
3.3 マネージドノード (Managed Nodes)
マネージドノードは Ansible に管理される対象のサーバーです。
要件 (Linux の場合):
- SSH サーバー (OpenSSH)
- Python 2.7 または 3.5+ (一部モジュールは raw モジュールを使用すれば不要)
- sudo / su (特権昇格が必要な場合)
エージェントレスの仕組み:
1. Ansible がモジュール(Pythonスクリプト)を生成
2. SCP/SFTP でマネージドノードの /tmp に転送
3. SSH でモジュールを実行
4. 実行結果を JSON で返却
5. 一時ファイルを削除
3.4 インベントリ (Inventory)
インベントリは管理対象ホストの一覧と、それらのグループ化を定義するファイルまたはスクリプトです。詳細はセクション5で解説します。
3.5 モジュール (Modules)
モジュールは Ansible が各タスクを実行するための実行単位です。2024年現在、公式コレクション含め 7,000以上のモジュールが利用可能です。
モジュールの分類:
┌─────────────────────────────────────────┐
│ Module Categories │
├──────────────────┬──────────────────────┤
│ System │ Files │
│ user, group, │ file, copy, │
│ hostname, cron │ template, fetch │
├──────────────────┼──────────────────────┤
│ Package Mgmt │ Service │
│ apt, yum, dnf, │ service, systemd, │
│ pip, gem │ supervisorctl │
├──────────────────┼──────────────────────┤
│ Network │ Cloud │
│ uri, get_url, │ amazon.aws.*, │
│ firewalld │ azure.*,gcp.* │
├──────────────────┼──────────────────────┤
│ Database │ Commands │
│ mysql_db, │ command, shell, │
│ postgresql_db │ raw, script │
└──────────────────┴──────────────────────┘
3.6 プラグイン (Plugins)
モジュールと似ていますが、Ansible エンジン自体の動作を拡張します。
| プラグイン種別 | 役割 | 例 |
|---|---|---|
| Connection | 接続方式の定義 | ssh, local, docker, winrm |
| Inventory | インベントリソース | aws_ec2, gcp_compute |
| Callback | 実行結果の出力形式 | yaml, json, minimal |
| Filter | Jinja2 フィルタの追加 | to_yaml, from_json |
| Lookup | 外部データの取得 | env, file, password |
| Vars | 変数の読み込み元 | host_group_vars |
4. インストールとセットアップ
4.1 コントロールノードのインストール
Ubuntu / Debian
# システムパッケージの更新
sudo apt update && sudo apt upgrade -y
# 依存パッケージのインストール
sudo apt install -y python3 python3-pip python3-venv software-properties-common
# 方法1: pip によるインストール(推奨)
python3 -m pip install --user ansible
# バージョン確認
ansible --version
# 出力例:
# ansible [core 2.17.0]
# config file = /home/user/.ansible.cfg
# configured module search path = ['/home/user/.ansible/plugins/modules', ...]
# ansible python module location = /home/user/.local/lib/python3.11/site-packages/ansible
# ansible collection location = /home/user/.ansible/collections:/usr/share/ansible/collections
# executable location = /home/user/.local/bin/ansible
# python version = 3.11.4
# jinja version = 3.1.2
# libyaml = True
# 方法2: apt リポジトリ経由
sudo apt-add-repository --yes --update ppa:ansible/ansible
sudo apt install -y ansible
RHEL / CentOS / Rocky Linux / AlmaLinux
# EPEL リポジトリの有効化
sudo dnf install -y epel-release
# Ansible のインストール
sudo dnf install -y ansible
# または pip 経由(最新版)
sudo dnf install -y python3 python3-pip
python3 -m pip install --user ansible
# バージョン確認
ansible --version
macOS
# Homebrew 経由(推奨)
brew install ansible
# pip 経由
pip3 install ansible
仮想環境でのインストール(推奨: プロジェクト分離)
# 仮想環境の作成
python3 -m venv ~/.venv/ansible
source ~/.venv/ansible/bin/activate
# Ansible のインストール
pip install ansible
# 必要なコレクションのインストール
ansible-galaxy collection install amazon.aws
ansible-galaxy collection install community.general
# requirements.yml を使った一括インストール
cat > requirements.yml << 'EOF'
collections:
- name: community.general
version: ">=7.0.0"
- name: amazon.aws
version: ">=7.0.0"
- name: community.mysql
version: ">=3.0.0"
EOF
ansible-galaxy collection install -r requirements.yml
4.2 SSH鍵の設定
Ansible はデフォルトで SSH 公開鍵認証を使用します。
# SSH鍵ペアの生成(まだない場合)
ssh-keygen -t ed25519 -C "ansible-control" -f ~/.ssh/ansible_ed25519
# パスフレーズは空でも設定しても良い(セキュリティ要件に応じて)
# マネージドノードへの公開鍵配布
# 方法1: ssh-copy-id(簡単)
ssh-copy-id -i ~/.ssh/ansible_ed25519.pub user@web01
ssh-copy-id -i ~/.ssh/ansible_ed25519.pub user@web02
ssh-copy-id -i ~/.ssh/ansible_ed25519.pub user@db01
# 方法2: Ansible の authorized_key モジュールでの管理(後述)
# SSH エージェントの設定(パスフレーズ付き鍵の場合)
eval $(ssh-agent)
ssh-add ~/.ssh/ansible_ed25519
# 接続テスト
ssh -i ~/.ssh/ansible_ed25519 user@web01 "hostname"
# 出力: web01
4.3 ansible.cfg の設定
# ~/.ansible.cfg または プロジェクトディレクトリの ansible.cfg
[defaults]
# インベントリファイルのパス
inventory = ./inventory
# SSH接続のデフォルトユーザー
remote_user = ansible
# SSH秘密鍵のパス
private_key_file = ~/.ssh/ansible_ed25519
# 並列実行数(デフォルト: 5)
forks = 20
# SSH接続タイムアウト(秒)
timeout = 30
# ホスト鍵チェックの無効化(開発環境のみ。本番では有効にすること)
host_key_checking = False
# ログの出力先
log_path = ./ansible.log
# コールバックプラグイン(出力形式)
stdout_callback = yaml
# ファクト収集のキャッシュ
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_facts_cache
fact_caching_timeout = 86400
# roles のパス
roles_path = ./roles:~/.ansible/roles
# retry ファイルを作成しない
retry_files_enabled = False
# Python インタープリタの自動検出
interpreter_python = auto_silent
[privilege_escalation]
# sudo による特権昇格を有効化
become = True
become_method = sudo
become_user = root
# パスワードなしの sudo を設定していない場合は True に
become_ask_pass = False
[ssh_connection]
# SSH 接続のパイプライン化(パフォーマンス向上)
pipelining = True
# SSH 引数のカスタマイズ
ssh_args = -C -o ControlMaster=auto -o ControlPersist=60s
# ControlPath の設定(接続の再利用)
control_path = %(directory)s/%%h-%%r
[inventory]
# インベントリのキャッシュを有効化
cache = True
cache_plugin = jsonfile
cache_connection = /tmp/ansible_inventory_cache
cache_timeout = 3600
4.4 接続テスト
# ping モジュールでの接続確認(ICMP ping ではなく Python の動作確認)
ansible all -m ping
# 出力例:
# web01 | SUCCESS => {
# "changed": false,
# "ping": "pong"
# }
# web02 | SUCCESS => {
# "changed": false,
# "ping": "pong"
# }
# db01 | SUCCESS => {
# "changed": false,
# "ping": "pong"
# }
# 特定グループのみ
ansible webservers -m ping
# ファクト情報の取得テスト
ansible web01 -m setup | head -30
# 出力例(抜粋):
# web01 | SUCCESS => {
# "ansible_facts": {
# "ansible_all_ipv4_addresses": ["192.168.1.101"],
# "ansible_architecture": "x86_64",
# "ansible_distribution": "Ubuntu",
# "ansible_distribution_version": "22.04",
# "ansible_hostname": "web01",
# "ansible_kernel": "5.15.0-87-generic",
# ...
# }
# }
5. インベントリ管理
5.1 静的インベントリ — INI 形式
# inventory/hosts
# グループなしのホスト(ungrouped)
192.168.1.100
# [グループ名] でグループを定義
[webservers]
web01 ansible_host=192.168.1.101 ansible_port=22
web02 ansible_host=192.168.1.102
web03 ansible_host=192.168.1.103
# 連番パターン(web01〜web05 を一括定義)
[appservers]
app[01:05].example.com
# データベースサーバー
[dbservers]
db01 ansible_host=192.168.1.201 ansible_user=dbadmin
db02 ansible_host=192.168.1.202
# ロードバランサー
[loadbalancers]
lb01 ansible_host=192.168.1.10
# グループの変数定義
[webservers:vars]
http_port=80
https_port=443
max_clients=200
# グループの親子関係(メタグループ)
[production:children]
webservers
appservers
dbservers
loadbalancers
[staging:children]
webservers
# Windowsホストの場合
[windows]
winserver01 ansible_host=192.168.1.50 ansible_connection=winrm ansible_winrm_transport=ntlm
5.2 静的インベントリ — YAML 形式(推奨)
# inventory/hosts.yml
all:
vars:
ansible_user: ansible
ansible_private_key_file: ~/.ssh/ansible_ed25519
children:
production:
children:
webservers:
hosts:
web01:
ansible_host: 192.168.1.101
nginx_port: 80
nginx_ssl_port: 443
web02:
ansible_host: 192.168.1.102
nginx_port: 80
nginx_ssl_port: 443
vars:
# webservers グループ共通の変数
app_env: production
max_connections: 1000
dbservers:
hosts:
db01:
ansible_host: 192.168.1.201
db_role: primary
db02:
ansible_host: 192.168.1.202
db_role: replica
vars:
mysql_version: "8.0"
mysql_port: 3306
loadbalancers:
hosts:
lb01:
ansible_host: 192.168.1.10
staging:
children:
webservers:
hosts:
web-stg01:
ansible_host: 192.168.2.101
vars:
app_env: staging
max_connections: 100
5.3 host_vars と group_vars ディレクトリ
project/
├── inventory/
│ ├── hosts.yml
│ ├── group_vars/
│ │ ├── all.yml # 全ホスト共通の変数
│ │ ├── all/
│ │ │ ├── vars.yml # ディレクトリ形式も可
│ │ │ └── vault.yml # 暗号化変数(Vault)
│ │ ├── webservers.yml # webservers グループの変数
│ │ └── dbservers.yml # dbservers グループの変数
│ └── host_vars/
│ ├── web01.yml # web01 固有の変数
│ └── db01.yml # db01 固有の変数
# inventory/group_vars/all.yml
---
ntp_servers:
- 0.jp.pool.ntp.org
- 1.jp.pool.ntp.org
dns_servers:
- 8.8.8.8
- 8.8.4.4
timezone: Asia/Tokyo
common_packages:
- vim
- curl
- wget
- git
- net-tools
- htop
# inventory/group_vars/webservers.yml
---
nginx_version: "1.25"
nginx_worker_processes: auto
nginx_worker_connections: 1024
ssl_certificate_path: /etc/ssl/certs/server.crt
ssl_key_path: /etc/ssl/private/server.key
app_deploy_path: /var/www/html
app_owner: www-data
app_group: www-data
# inventory/host_vars/web01.yml
---
# web01 固有の設定
nginx_server_name: web01.example.com
nginx_custom_log: /var/log/nginx/web01_access.log
backup_enabled: true
5.4 動的インベントリ
動的インベントリはスクリプトや Ansible プラグインを使って、クラウドや CMDB などの外部ソースからホスト情報を動的に取得します。
AWS EC2 動的インベントリ
# amazon.aws コレクションのインストール
ansible-galaxy collection install amazon.aws
# AWS 認証情報の設定
export AWS_ACCESS_KEY_ID="AKIAIOSFODNN7EXAMPLE"
export AWS_SECRET_ACCESS_KEY="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
export AWS_REGION="ap-northeast-1"
# inventory/aws_ec2.yml(プラグイン設定ファイル)
plugin: amazon.aws.aws_ec2
# リージョン
regions:
- ap-northeast-1
- ap-northeast-3
# フィルタリング(running インスタンスのみ)
filters:
instance-state-name: running
tag:Environment: production
# ホスト名の設定
hostnames:
- tag:Name
- private-ip-address
# グループ化のルール
keyed_groups:
# タグ値でグループ化
- key: tags.Role
prefix: role
separator: "_"
# インスタンスタイプでグループ化
- key: instance_type
prefix: type
# AZ でグループ化
- key: placement.availability_zone
prefix: az
# グループのカスタマイズ
groups:
webservers: "'web' in tags.Role"
dbservers: "'db' in tags.Role"
# 変数のカスタマイズ
compose:
ansible_host: private_ip_address
ec2_region: placement.region
# 動的インベントリのテスト
ansible-inventory -i inventory/aws_ec2.yml --list
ansible-inventory -i inventory/aws_ec2.yml --graph
# 出力例(--graph):
# @all:
# |--@role_web:
# | |--web01.ap-northeast-1.compute.internal
# | |--web02.ap-northeast-1.compute.internal
# |--@role_db:
# | |--db01.ap-northeast-1.compute.internal
# |--@type_t3_medium:
# | |--web01.ap-northeast-1.compute.internal
# | |--web02.ap-northeast-1.compute.internal
5.5 インベントリの確認コマンド
# インベントリの一覧表示(JSON形式)
ansible-inventory --list
# グラフ形式での表示
ansible-inventory --graph
# 特定ホストの変数確認
ansible-inventory --host web01
# 出力例:
# {
# "ansible_host": "192.168.1.101",
# "ansible_user": "ansible",
# "app_env": "production",
# "nginx_port": 80
# }
# 特定グループのホスト一覧
ansible webservers --list-hosts
# 出力例:
# hosts (2):
# web01
# web02
6. アドホックコマンド
アドホックコマンドはプレイブックを作成せずに、コマンドラインから直接 Ansible モジュールを実行する方法です。一時的な作業や確認に使用します。
6.1 基本構文
ansible <対象ホスト/グループ> [オプション] -m <モジュール名> -a <引数>
6.2 よく使うアドホックコマンド
# ---- 接続確認 ----
ansible all -m ping
# ---- コマンド実行 ----
# command モジュール(シェル機能なし)
ansible webservers -m command -a "uptime"
# 出力例:
# web01 | CHANGED | rc=0 >>
# 10:23:45 up 30 days, 2:15, 1 user, load average: 0.12, 0.08, 0.05
# web02 | CHANGED | rc=0 >>
# 10:23:45 up 30 days, 2:16, 1 user, load average: 0.08, 0.07, 0.04
# shell モジュール(シェル機能あり:パイプ、リダイレクト等)
ansible webservers -m shell -a "ps aux | grep nginx | wc -l"
# ---- パッケージ管理 ----
# パッケージのインストール
ansible webservers -m apt -a "name=nginx state=present" --become
# 出力例:
# web01 | CHANGED => {
# "cache_update_time": 1712345678,
# "changed": true,
# ...
# }
# パッケージのアップデート(apt cache更新付き)
ansible webservers -m apt -a "name=nginx state=latest update_cache=yes" --become
# 複数パッケージのインストール
ansible all -m apt -a "name='vim,curl,wget' state=present" --become
# ---- サービス管理 ----
# サービスの起動
ansible webservers -m service -a "name=nginx state=started" --become
# サービスの再起動
ansible webservers -m service -a "name=nginx state=restarted" --become
# サービスの有効化
ansible webservers -m service -a "name=nginx enabled=yes" --become
# ---- ファイル操作 ----
# ファイルのコピー
ansible webservers -m copy -a "src=/tmp/test.conf dest=/etc/nginx/test.conf mode=0644" --become
# ファイルの削除
ansible webservers -m file -a "path=/tmp/old_file.txt state=absent" --become
# ディレクトリの作成
ansible all -m file -a "path=/opt/myapp state=directory mode=0755 owner=ansible group=ansible" --become
# ---- ユーザー管理 ----
# ユーザーの作成
ansible all -m user -a "name=deploy comment='Deploy User' shell=/bin/bash state=present" --become
# ---- システム情報の取得 ----
# ディスク使用量の確認
ansible all -m command -a "df -h"
# メモリ使用量
ansible all -m command -a "free -m"
# ---- ファクトの収集 ----
# 全ファクト情報の取得
ansible web01 -m setup
# 特定のファクトのみ取得(フィルタリング)
ansible web01 -m setup -a "filter=ansible_distribution*"
# 出力例:
# web01 | SUCCESS => {
# "ansible_facts": {
# "ansible_distribution": "Ubuntu",
# "ansible_distribution_file_parsed": true,
# "ansible_distribution_file_path": "/etc/os-release",
# "ansible_distribution_major_version": "22",
# "ansible_distribution_release": "jammy",
# "ansible_distribution_version": "22.04"
# }
# }
# ---- 並列数と接続オプション ----
# 並列実行数を指定(デフォルト: 5)
ansible all -m ping -f 20
# 特定のSSHユーザーで接続
ansible webservers -m ping -u deploy
# パスワード認証(テスト環境のみ推奨)
ansible webservers -m ping --ask-pass
# sudo 昇格
ansible webservers -m command -a "whoami" --become
# 出力: root
6.3 アドホックコマンドのオプション一覧
| オプション | 短縮形 | 説明 |
|---|---|---|
--module-name | -m | 使用するモジュール名 |
--args | -a | モジュールへの引数 |
--become | -b | 特権昇格(sudo)を有効化 |
--become-user | 昇格先ユーザー(デフォルト: root) | |
--user | -u | SSH 接続ユーザー |
--forks | -f | 並列実行数 |
--limit | -l | 対象ホストの絞り込み |
--check | -C | ドライラン(実際には変更しない) |
--diff | -D | 変更内容の差分表示 |
--verbose | -v/-vv/-vvv | 詳細出力 |
7. YAMLとJinja2の基礎
7.1 YAML 構文
Ansible のプレイブックは YAML で記述します。YAML の基本を理解することが Ansible 習得の前提です。
# ---- 基本データ型 ----
# 文字列
string_single: Hello World
string_quoted: "Hello World"
string_literal: 'Hello World'
# 数値
integer: 42
float: 3.14
# 真偽値
boolean_true: true # または yes, True, TRUE, on
boolean_false: false # または no, False, FALSE, off
# null
null_value: null # または ~
# ---- リスト(配列)----
# フロー形式
packages_flow: [vim, curl, wget, git]
# ブロック形式(推奨)
packages_block:
- vim
- curl
- wget
- git
# ---- ディクショナリ(マップ)----
# フロー形式
user_flow: {name: john, uid: 1001, shell: /bin/bash}
# ブロック形式(推奨)
user_block:
name: john
uid: 1001
shell: /bin/bash
# ---- ネスト構造 ----
servers:
webservers:
- name: web01
ip: 192.168.1.101
ports:
- 80
- 443
- name: web02
ip: 192.168.1.102
ports:
- 80
- 443
dbservers:
- name: db01
ip: 192.168.1.201
# ---- 複数行文字列 ----
# | : 改行を保持(リテラルブロック)
multiline_literal: |
server {
listen 80;
server_name example.com;
}
# > : 改行を空白に変換(折りたたみブロック)
multiline_folded: >
This is a long string that
will be folded into one line.
# 結果: "This is a long string that will be folded into one line."
# ---- アンカーとエイリアス(DRY原則)----
# アンカーの定義(&)
default_user: &default_user
shell: /bin/bash
groups: sudo
state: present
# エイリアスの参照(*)
users:
- name: alice
<<: *default_user
uid: 1001
- name: bob
<<: *default_user
uid: 1002
shell: /bin/zsh # オーバーライド可能
7.2 Jinja2 テンプレートエンジン
Ansible は変数の展開とテンプレート処理に Jinja2 を使用します。
変数の参照
# プレイブック内での変数参照
- name: ユーザー {{ username }} を作成
user:
name: "{{ username }}"
home: "/home/{{ username }}"
shell: "{{ user_shell | default('/bin/bash') }}"
フィルタ
# 大文字/小文字変換
- debug:
msg: "{{ 'hello world' | upper }}" # HELLO WORLD
msg: "{{ 'HELLO WORLD' | lower }}" # hello world
# デフォルト値
- debug:
msg: "{{ undefined_var | default('default_value') }}"
# リストの結合
- debug:
msg: "{{ ['a', 'b', 'c'] | join(', ') }}" # a, b, c
# 型変換
- debug:
msg: "{{ '42' | int }}" # 42 (整数)
msg: "{{ 42 | string }}" # "42" (文字列)
msg: "{{ some_var | bool }}" # True/False
# JSON/YAML 変換
- debug:
msg: "{{ data | to_json }}"
msg: "{{ data | to_yaml }}"
msg: "{{ json_string | from_json }}"
# ファイルパス操作
- debug:
msg: "{{ '/etc/nginx/nginx.conf' | basename }}" # nginx.conf
msg: "{{ '/etc/nginx/nginx.conf' | dirname }}" # /etc/nginx
# リスト操作
- debug:
msg: "{{ [3, 1, 4, 1, 5] | sort }}" # [1, 1, 3, 4, 5]
msg: "{{ [3, 1, 4, 1, 5] | unique }}" # [3, 1, 4, 5]
msg: "{{ packages | select('match', 'python.*') | list }}"
# 文字列操作
- debug:
msg: "{{ 'Hello World' | replace('World', 'Ansible') }}"
msg: "{{ hostname | regex_replace('^web', 'app') }}"
# ハッシュ/暗号化
- debug:
msg: "{{ 'mypassword' | password_hash('sha512') }}"
テスト (Tests)
# 変数の状態チェック
- name: 変数が定義されているか確認
debug:
msg: "username is defined"
when: username is defined
- name: リストかどうか確認
debug:
msg: "it's a list"
when: packages is iterable and packages is not string
- name: 数値の比較
debug:
msg: "large number"
when: count is gt 100 # greater than
# よく使うテスト
# is defined : 変数が定義されている
# is undefined : 変数が未定義
# is none : null/None
# is string : 文字列型
# is number : 数値型
# is iterable : イテラブル(リスト等)
# is mapping : ディクショナリ型
# is file : ファイルが存在
# is directory : ディレクトリが存在
# is version('2.0', '>=') : バージョン比較
テンプレートファイル (.j2)
{# templates/nginx.conf.j2 #}
{# コメント #}
user {{ nginx_user | default('www-data') }};
worker_processes {{ nginx_worker_processes | default('auto') }};
events {
worker_connections {{ nginx_worker_connections | default(1024) }};
}
http {
{# SSL設定(条件付き) #}
{% if ssl_enabled | default(false) %}
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
{% endif %}
{# バーチャルホストの設定(ループ) #}
{% for vhost in virtual_hosts %}
server {
listen {{ vhost.port | default(80) }};
server_name {{ vhost.server_name }};
root {{ vhost.root | default('/var/www/html') }};
access_log /var/log/nginx/{{ vhost.server_name }}_access.log;
error_log /var/log/nginx/{{ vhost.server_name }}_error.log;
{% if vhost.ssl | default(false) %}
listen 443 ssl;
ssl_certificate {{ vhost.ssl_cert }};
ssl_certificate_key {{ vhost.ssl_key }};
{% endif %}
location / {
try_files $uri $uri/ =404;
}
}
{% endfor %}
}
8. プレイブックの構造
8.1 プレイブックの全体構造
# site.yml — プレイブックの例
---
# ============================================================
# プレイ1: Webサーバーのセットアップ
# ============================================================
- name: Webサーバーのセットアップ # プレイ名(必須)
hosts: webservers # 対象ホスト/グループ
become: true # sudo 昇格
gather_facts: true # ファクト収集(デフォルト: true)
any_errors_fatal: false # 1つのホストでエラーが出ても続行
serial: 2 # 一度に処理するホスト数(ローリングアップデート)
max_fail_percentage: 20 # 許容失敗率 (%)
# プレイレベルの変数
vars:
nginx_version: "1.25"
app_port: 8080
# 変数ファイルの読み込み
vars_files:
- vars/common.yml
- vars/webserver.yml
# ハンドラ(タスクの notify で呼び出される)
handlers:
- name: Nginx を再起動
service:
name: nginx
state: restarted
- name: Nginx の設定をリロード
service:
name: nginx
state: reloaded
# 前処理タスク(ロールの実行前に実行)
pre_tasks:
- name: apt キャッシュを更新
apt:
update_cache: yes
cache_valid_time: 3600
# メインタスク
tasks:
- name: Nginx のインストール
apt:
name: "nginx={{ nginx_version }}*"
state: present
notify: Nginx を再起動 # ハンドラの呼び出し
- name: Nginx の設定ファイルを配置
template:
src: templates/nginx.conf.j2
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
backup: yes
notify: Nginx の設定をリロード
- name: Nginx を起動し有効化
service:
name: nginx
state: started
enabled: yes
# 後処理タスク(ロールの実行後に実行)
post_tasks:
- name: デプロイ完了の通知
debug:
msg: "{{ inventory_hostname }} のセットアップが完了しました"
# ============================================================
# プレイ2: DBサーバーのセットアップ
# ============================================================
- name: DBサーバーのセットアップ
hosts: dbservers
become: true
roles:
- common
- mysql
8.2 タスク (Task) の詳細
tasks:
# --- 基本的なタスク ---
- name: パッケージのインストール
apt:
name: vim
state: present
# --- タグの付与(選択的実行に使用)---
- name: セキュリティアップデートの適用
apt:
upgrade: dist
tags:
- security
- updates
# --- register: タスクの実行結果を変数に保存 ---
- name: Nginx のステータス確認
command: systemctl status nginx
register: nginx_status
ignore_errors: yes # エラーを無視して続行
- name: Nginx のステータスを表示
debug:
var: nginx_status.stdout_lines
# --- changed_when / failed_when: 変更/失敗の判定をカスタマイズ ---
- name: カスタムスクリプトの実行
command: /opt/scripts/check_app.sh
register: app_check
changed_when: "'Updated' in app_check.stdout"
failed_when: app_check.rc > 1
# --- delegate_to: 別ホストで実行 ---
- name: ロードバランサーからホストを切り離す
command: /usr/local/bin/lb-remove.sh {{ inventory_hostname }}
delegate_to: lb01
# --- run_once: 1つのホストでのみ実行 ---
- name: データベースのマイグレーション
command: /opt/app/manage.py migrate
run_once: true
delegate_to: app01
# --- block: 複数タスクのグループ化 ---
- block:
- name: 設定ファイルのバックアップ
copy:
src: /etc/nginx/nginx.conf
dest: /etc/nginx/nginx.conf.bak
remote_src: yes
- name: 新しい設定の適用
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
- name: 設定のテスト
command: nginx -t
rescue:
# エラー発生時の回復処理
- name: バックアップから復元
copy:
src: /etc/nginx/nginx.conf.bak
dest: /etc/nginx/nginx.conf
remote_src: yes
always:
# 成功/失敗に関わらず常に実行
- name: ステータスの記録
lineinfile:
path: /var/log/deploy.log
line: "{{ ansible_date_time.iso8601 }}: Deploy attempted on {{ inventory_hostname }}"
8.3 ハンドラ (Handler)
ハンドラは notify で呼び出され、プレイの最後に一度だけ実行されます(複数のタスクから notify されても1回)。
handlers:
# 基本的なハンドラ
- name: Nginx を再起動
service:
name: nginx
state: restarted
# ハンドラの連鎖(listen を使用)
- name: Nginx の設定を検証
command: nginx -t
listen: "nginx 設定変更"
- name: Nginx をリロード
service:
name: nginx
state: reloaded
listen: "nginx 設定変更"
tasks:
- name: 設定ファイルの更新
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: "nginx 設定変更" # 両方のハンドラが順番に実行される
# ハンドラを即時実行
- name: 証明書の更新
copy:
src: server.crt
dest: /etc/ssl/certs/server.crt
notify: Nginx を再起動
# flush_handlers: その場でハンドラを実行
- name: ハンドラを即時実行
meta: flush_handlers
8.4 変数 (Variables)
変数の優先順位(低い順 → 高い順)
1. role defaults (roles/x/defaults/main.yml)
2. inventory file or script group vars
3. inventory group_vars/all
4. playbook group_vars/all
5. inventory group_vars/*
6. playbook group_vars/*
7. inventory file or script host vars
8. inventory host_vars/*
9. playbook host_vars/*
10. host facts / cached set_facts
11. play vars
12. play vars_prompt
13. play vars_files
14. role vars (roles/x/vars/main.yml)
15. block vars (only for tasks in block)
16. task vars (only for the task)
17. include_vars
18. set_facts / registered vars
19. role (and include_role) params
20. include params
21. extra vars (ansible-playbook -e) ← 最高優先度
# 変数の定義方法
# --- プレイレベル ---
- hosts: all
vars:
app_name: myapp
app_version: "2.3.1"
app_config:
debug: false
log_level: INFO
allowed_hosts:
- "*.example.com"
- localhost
vars_files:
- vars/secrets.yml # 暗号化ファイルも読める(Vault)
tasks:
# --- set_fact: 動的な変数定義 ---
- name: インストールパスを設定
set_fact:
install_path: "/opt/{{ app_name }}/{{ app_version }}"
config_path: "/etc/{{ app_name }}"
# --- include_vars: 条件付き変数ファイル読み込み ---
- name: OS固有の変数を読み込む
include_vars: "vars/{{ ansible_os_family | lower }}.yml"
# --- vars_prompt: 実行時に入力 ---
vars_prompt:
- name: deploy_password
prompt: "デプロイパスワードを入力してください"
private: yes # 入力を非表示
confirm: yes # 確認入力
# --- extra_vars: コマンドラインから渡す ---
# ansible-playbook site.yml -e "app_version=3.0.0 env=production"
# または JSON 形式
# ansible-playbook site.yml -e '{"app_version": "3.0.0", "env": "production"}'
# または変数ファイル
# ansible-playbook site.yml -e @vars/override.yml
8.5 ファクト (Facts)
ファクトはマネージドノードから収集するシステム情報です。
tasks:
# よく使うファクト
- debug:
msg: |
ホスト名 : {{ ansible_hostname }}
FQDN : {{ ansible_fqdn }}
IP アドレス : {{ ansible_default_ipv4.address }}
OS : {{ ansible_distribution }} {{ ansible_distribution_version }}
カーネル : {{ ansible_kernel }}
CPU コア数 : {{ ansible_processor_vcpus }}
メモリ(MB) : {{ ansible_memtotal_mb }}
ディスク : {{ ansible_devices.sda.size | default('N/A') }}
Python : {{ ansible_python_version }}
# カスタムファクト(/etc/ansible/facts.d/ に配置)
# /etc/ansible/facts.d/myapp.fact
# [application]
# version=2.3.1
# install_date=2026-01-15
#
# 参照: {{ ansible_local.myapp.application.version }}
# ファクトのキャッシュ
# ansible.cfg で fact_caching を設定すると再収集不要になる
8.6 条件分岐 (when)
tasks:
# --- OS による条件分岐 ---
- name: Nginx のインストール (Debian系)
apt:
name: nginx
state: present
when: ansible_os_family == "Debian"
- name: Nginx のインストール (RedHat系)
dnf:
name: nginx
state: present
when: ansible_os_family == "RedHat"
# --- 複数条件 (AND) ---
- name: 本番環境のUbuntu 22.04にのみ実行
command: /opt/security/harden.sh
when:
- ansible_distribution == "Ubuntu"
- ansible_distribution_version == "22.04"
- env == "production"
# --- 複数条件 (OR) ---
- name: CentOS または AlmaLinux の場合
dnf:
name: epel-release
state: present
when: ansible_distribution == "CentOS" or ansible_distribution == "AlmaLinux"
# または filter 構文
- name: CentOS または AlmaLinux の場合(filter)
dnf:
name: epel-release
state: present
when: ansible_distribution in ["CentOS", "AlmaLinux", "Rocky"]
# --- register 結果による条件分岐 ---
- name: アプリのプロセス確認
command: pgrep myapp
register: myapp_pid
ignore_errors: yes
- name: アプリが起動していない場合のみ起動
command: /opt/myapp/start.sh
when: myapp_pid.rc != 0
# --- 変数の存在チェック ---
- name: カスタム設定の適用(変数が定義されている場合のみ)
template:
src: custom.conf.j2
dest: /etc/myapp/custom.conf
when: custom_config is defined and custom_config | length > 0
# --- バージョン比較 ---
- name: Python 3.9以上の場合のみ実行
command: /opt/scripts/new_feature.py
when: ansible_python_version is version('3.9', '>=')
8.7 ループ (loop)
tasks:
# --- 基本的なループ ---
- name: 複数パッケージのインストール
apt:
name: "{{ item }}"
state: present
loop:
- vim
- curl
- wget
- git
- htop
# --- 変数リストを使ったループ ---
- name: 複数ユーザーの作成
user:
name: "{{ item.name }}"
uid: "{{ item.uid }}"
shell: "{{ item.shell | default('/bin/bash') }}"
groups: "{{ item.groups | default([]) }}"
state: present
loop: "{{ users }}"
# vars/users.yml:
# users:
# - name: alice
# uid: 1001
# groups: ["sudo", "docker"]
# - name: bob
# uid: 1002
# shell: /bin/zsh
# --- loop_control: ループの制御 ---
- name: 複数のサービスを管理
service:
name: "{{ item.name }}"
state: "{{ item.state }}"
enabled: "{{ item.enabled }}"
loop:
- {name: nginx, state: started, enabled: true}
- {name: mysql, state: started, enabled: true}
- {name: redis, state: started, enabled: true}
- {name: postfix, state: stopped, enabled: false}
loop_control:
label: "{{ item.name }}" # ログの見やすさのため名前のみ表示
pause: 1 # 各イテレーション間の待機時間(秒)
# --- with_fileglob: ファイルのグロブパターン ---
- name: 設定ファイルの一括配置
copy:
src: "{{ item }}"
dest: /etc/myapp/conf.d/
with_fileglob:
- "files/conf.d/*.conf"
# --- with_dict: ディクショナリのループ ---
- name: 環境変数の設定
lineinfile:
path: /etc/environment
line: "{{ item.key }}={{ item.value }}"
with_dict:
PATH: /usr/local/bin:/usr/bin:/bin
JAVA_HOME: /usr/lib/jvm/java-17
APP_ENV: production
# --- with_nested / product: 直積ループ ---
- name: ユーザーとグループの組み合わせで設定
command: "adduser {{ item.0 }} {{ item.1 }}"
with_nested:
- ['alice', 'bob']
- ['developers', 'testers']
# --- until: リトライループ ---
- name: アプリが起動するまで待機
uri:
url: http://localhost:8080/health
status_code: 200
register: health_check
until: health_check.status == 200
retries: 10 # 最大10回
delay: 5 # 5秒間隔
9. ロールとAnsible Galaxy
9.1 ロールの概要
ロール (Role) はプレイブックの要素(タスク、変数、ハンドラ、テンプレート等)を再利用可能な単位にパッケージ化する仕組みです。
9.2 ロールのディレクトリ構造
roles/
└── nginx/ # ロール名
├── tasks/
│ ├── main.yml # メインタスク(必須)
│ ├── install.yml # インストールタスク(include 用)
│ └── configure.yml # 設定タスク(include 用)
├── handlers/
│ └── main.yml # ハンドラ定義
├── templates/
│ ├── nginx.conf.j2 # Jinja2 テンプレート
│ └── vhost.conf.j2
├── files/
│ ├── ssl/
│ │ ├── server.crt # 静的ファイル
│ │ └── server.key
│ └── index.html
├── vars/
│ └── main.yml # ロール変数(高優先度)
├── defaults/
│ └── main.yml # デフォルト変数(低優先度・上書き可)
├── meta/
│ └── main.yml # ロールのメタデータと依存関係
├── tests/
│ ├── inventory
│ └── test.yml # テスト用プレイブック
└── README.md
9.3 ロールの作成
# ロールのスケルトン生成
ansible-galaxy role init roles/nginx
# 出力:
# - Role roles/nginx was created successfully
ansible-galaxy role init roles/mysql
ansible-galaxy role init roles/common
roles/common/defaults/main.yml
---
# デフォルト変数(優先度が低く、インベントリやプレイブックで上書き可能)
common_packages:
- vim
- curl
- wget
- git
- net-tools
- htop
- unzip
- tmux
common_timezone: Asia/Tokyo
ntp_servers:
- 0.jp.pool.ntp.org
- 1.jp.pool.ntp.org
- 2.jp.pool.ntp.org
sysctl_params:
net.ipv4.ip_forward: 0
net.core.somaxconn: 1024
vm.swappiness: 10
disable_services:
- bluetooth
- cups
enable_services:
- cron
- rsyslog
roles/common/tasks/main.yml
---
- name: 共通タスクの読み込み
include_tasks: "{{ item }}"
loop:
- packages.yml
- timezone.yml
- sysctl.yml
- ntp.yml
- security.yml
roles/common/tasks/packages.yml
---
- name: apt キャッシュの更新
apt:
update_cache: yes
cache_valid_time: 3600
when: ansible_os_family == "Debian"
- name: 共通パッケージのインストール (Debian系)
apt:
name: "{{ common_packages }}"
state: present
when: ansible_os_family == "Debian"
- name: 共通パッケージのインストール (RedHat系)
dnf:
name: "{{ common_packages }}"
state: present
when: ansible_os_family == "RedHat"
- name: 不要なパッケージの削除
apt:
name:
- telnet
- rsh-client
state: absent
when: ansible_os_family == "Debian"
roles/nginx/defaults/main.yml
---
nginx_user: www-data
nginx_worker_processes: auto
nginx_worker_connections: 1024
nginx_keepalive_timeout: 65
nginx_gzip: true
nginx_vhosts:
- server_name: "{{ ansible_fqdn }}"
root: /var/www/html
port: 80
ssl: false
ssl_enabled: false
ssl_certificate: /etc/ssl/certs/ssl-cert-snakeoil.pem
ssl_certificate_key: /etc/ssl/private/ssl-cert-snakeoil.key
roles/nginx/tasks/main.yml
---
- name: Nginx のインストール
include_tasks: install.yml
tags: [install]
- name: Nginx の設定
include_tasks: configure.yml
tags: [configure]
- name: Nginx の起動と有効化
service:
name: nginx
state: started
enabled: yes
tags: [service]
roles/nginx/tasks/install.yml
---
- name: Nginx のインストール (Debian系)
apt:
name: nginx
state: present
update_cache: yes
when: ansible_os_family == "Debian"
notify: Nginx を再起動
- name: Nginx のインストール (RedHat系)
dnf:
name: nginx
state: present
when: ansible_os_family == "RedHat"
notify: Nginx を再起動
roles/nginx/tasks/configure.yml
---
- name: Nginx メイン設定の配置
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
validate: '/usr/sbin/nginx -t -c %s'
notify: Nginx の設定をリロード
- name: デフォルト設定の削除
file:
path: /etc/nginx/sites-enabled/default
state: absent
notify: Nginx の設定をリロード
- name: バーチャルホスト設定の配置
template:
src: vhost.conf.j2
dest: "/etc/nginx/sites-available/{{ item.server_name }}.conf"
owner: root
group: root
mode: '0644'
loop: "{{ nginx_vhosts }}"
notify: Nginx の設定をリロード
- name: バーチャルホストの有効化
file:
src: "/etc/nginx/sites-available/{{ item.server_name }}.conf"
dest: "/etc/nginx/sites-enabled/{{ item.server_name }}.conf"
state: link
loop: "{{ nginx_vhosts }}"
notify: Nginx の設定をリロード
roles/nginx/handlers/main.yml
---
- name: Nginx を再起動
service:
name: nginx
state: restarted
- name: Nginx の設定をリロード
service:
name: nginx
state: reloaded
roles/nginx/meta/main.yml
---
galaxy_info:
author: yourname
description: Nginx web server setup role
license: MIT
min_ansible_version: "2.14"
platforms:
- name: Ubuntu
versions:
- "20.04"
- "22.04"
- name: EL
versions:
- "8"
- "9"
galaxy_tags:
- nginx
- webserver
# ロールの依存関係(先に実行される)
dependencies:
- role: common
- role: firewall
vars:
firewall_allowed_ports:
- 80
- 443
9.4 ロールの使用
# site.yml
---
- name: 全サーバーの共通設定
hosts: all
become: true
roles:
- common # シンプルな呼び出し
- name: Webサーバーの設定
hosts: webservers
become: true
roles:
# 変数を渡してロールを呼び出す
- role: nginx
vars:
nginx_worker_processes: 4
ssl_enabled: true
nginx_vhosts:
- server_name: app.example.com
root: /var/www/app
port: 80
# include_role: タスクと同じレベルで条件分岐できる
- role: ssl_certbot
when: ssl_enabled | default(false)
- name: DBサーバーの設定
hosts: dbservers
become: true
roles:
- role: mysql
vars:
mysql_root_password: "{{ vault_mysql_root_password }}"
mysql_databases:
- name: appdb
encoding: utf8mb4
mysql_users:
- name: appuser
password: "{{ vault_mysql_app_password }}"
priv: "appdb.*:ALL"
9.5 Ansible Galaxy
Ansible Galaxy はコミュニティが作成したロールやコレクションを共有するプラットフォームです。
# ロールの検索
ansible-galaxy role search nginx
# ロールのインストール
ansible-galaxy role install geerlingguy.nginx
# 特定バージョンのインストール
ansible-galaxy role install geerlingguy.mysql,3.3.1
# requirements.yml によるバルクインストール
cat > requirements.yml << 'EOF'
roles:
- name: geerlingguy.nginx
version: "3.2.0"
- name: geerlingguy.mysql
version: "3.3.1"
- src: https://github.com/example/ansible-role-myapp.git
scm: git
version: main
name: myapp
collections:
- name: community.general
version: ">=7.0.0"
- name: community.mysql
version: ">=3.0.0"
- name: amazon.aws
version: ">=7.0.0"
EOF
ansible-galaxy install -r requirements.yml
ansible-galaxy collection install -r requirements.yml
# インストール済みロールの一覧
ansible-galaxy role list
# 出力例:
# - geerlingguy.nginx, 3.2.0
# - geerlingguy.mysql, 3.3.1
# ロールの削除
ansible-galaxy role remove geerlingguy.nginx
# コレクション関連
ansible-galaxy collection install community.general
ansible-galaxy collection list
ansible-galaxy collection install community.general --upgrade
10. Ansible Vault
10.1 Vault の概要
Ansible Vault はパスワード、APIキー、証明書などの機密情報を AES-256 で暗号化して安全に管理する機能です。
10.2 ファイルの暗号化と復号
# ---- ファイルの暗号化 ----
# 新規暗号化ファイルの作成
ansible-vault create vars/secrets.yml
# パスワードの入力を求められる
# エディタが開き、内容を編集
# 既存ファイルの暗号化
ansible-vault encrypt vars/secrets.yml
# 暗号化後のファイルの内容(例):
# $ANSIBLE_VAULT;1.1;AES256
# 66386439353236336462626566653766353265656
# 32623261313762366534353938623165363...
# ---- ファイルの確認 ----
ansible-vault view vars/secrets.yml
# パスワードを入力すると平文で表示
# ---- ファイルの編集 ----
ansible-vault edit vars/secrets.yml
# パスワードを入力するとエディタが開く
# ---- ファイルの復号 ----
ansible-vault decrypt vars/secrets.yml
# ---- パスワードの変更 ----
ansible-vault rekey vars/secrets.yml
# 古いパスワードと新しいパスワードを入力
# ---- 文字列の暗号化(inline暗号化)----
ansible-vault encrypt_string 'MySecretPassword123' --name 'db_password'
# 出力:
# db_password: !vault |
# $ANSIBLE_VAULT;1.1;AES256
# 66386439353236336462626566...
# Encryption successful
10.3 Vault パスワードの管理
# ---- パスワードファイルの使用 ----
# パスワードファイルの作成
echo 'VaultPassword123!' > ~/.vault_pass
chmod 600 ~/.vault_pass
# パスワードファイルを使ったプレイブック実行
ansible-playbook site.yml --vault-password-file ~/.vault_pass
# ansible.cfg での設定
# [defaults]
# vault_password_file = ~/.vault_pass
# ---- パスワードスクリプトの使用 ----
# 例: AWS Secrets Manager からパスワードを取得
cat > /usr/local/bin/vault_pass.sh << 'EOF'
#!/bin/bash
aws secretsmanager get-secret-value \
--secret-id ansible/vault-password \
--query SecretString \
--output text
EOF
chmod +x /usr/local/bin/vault_pass.sh
ansible-playbook site.yml --vault-password-file /usr/local/bin/vault_pass.sh
# ---- 複数 Vault ID の使用 ----
# Vault ID でラベル付けして管理
ansible-vault encrypt vars/prod_secrets.yml --vault-id production@~/.vault_pass_prod
ansible-vault encrypt vars/dev_secrets.yml --vault-id development@~/.vault_pass_dev
# 実行時に複数の Vault ID を指定
ansible-playbook site.yml \
--vault-id production@~/.vault_pass_prod \
--vault-id development@~/.vault_pass_dev
10.4 Vault の実践的な使用例
# vars/secrets.yml(暗号化前の内容)
---
vault_db_root_password: "MyRootPass123!"
vault_db_app_password: "AppDbPass456!"
vault_api_key: "sk-1234567890abcdef"
vault_ssl_cert: |
-----BEGIN CERTIFICATE-----
MIIDXTCCAkWgAwIBAgIJALxxx...
-----END CERTIFICATE-----
vault_ssl_key: |
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0B...
-----END PRIVATE KEY-----
# group_vars/all/vars.yml(平文)
---
db_host: db01.example.com
db_port: 3306
db_name: appdb
# group_vars/all/vault.yml(暗号化)
# ansible-vault encrypt group_vars/all/vault.yml
---
vault_db_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
66386439353236336462626566653766353265...
# プレイブックでの使用
- name: データベースのセットアップ
hosts: dbservers
vars_files:
- vars/secrets.yml # Vault で暗号化されたファイル
tasks:
- name: MySQL root パスワードの設定
mysql_user:
name: root
password: "{{ vault_db_root_password }}" # Vault 変数を参照
state: present
# Vault 付きのプレイブック実行
ansible-playbook site.yml --ask-vault-pass
# または
ansible-playbook site.yml --vault-password-file ~/.vault_pass
11. 主要モジュール詳解
11.1 パッケージ管理モジュール
apt モジュール (Debian/Ubuntu)
tasks:
# パッケージのインストール
- name: Nginx のインストール
apt:
name: nginx
state: present # present/latest/absent/build-dep
# 特定バージョンのインストール
- name: Nginx 特定バージョンのインストール
apt:
name: "nginx=1.25.3-1~jammy"
state: present
allow_downgrade: yes # ダウングレードを許可
# キャッシュ更新付きインストール
- name: パッケージをインストール(キャッシュ更新付き)
apt:
name: "{{ item }}"
state: present
update_cache: yes
cache_valid_time: 3600 # 1時間キャッシュが有効なら更新しない
loop: "{{ packages }}"
# 複数パッケージの一括インストール
- name: 開発ツールのインストール
apt:
name:
- build-essential
- python3-dev
- libssl-dev
- libffi-dev
state: present
# パッケージのアップグレード
- name: セキュリティアップデートの適用
apt:
upgrade: safe # safe/full/dist/no
update_cache: yes
# パッケージの削除(設定ファイルも含めて削除)
- name: Apache の完全削除
apt:
name: apache2
state: absent
purge: yes # 設定ファイルも削除
# 未使用パッケージの削除
- name: autoremove の実行
apt:
autoremove: yes
autoclean: yes
dnf/yum モジュール (RHEL/CentOS/Rocky)
tasks:
# DNF でのインストール(RHEL8+)
- name: Nginx のインストール (RHEL系)
dnf:
name: nginx
state: present
# EPEL リポジトリ経由でのインストール
- name: EPEL パッケージのインストール
dnf:
name:
- epel-release
- htop
- jq
state: present
# グループインストール
- name: 開発ツールグループのインストール
dnf:
name: "@Development Tools"
state: present
# リポジトリを指定してインストール
- name: 特定リポジトリからインストール
dnf:
name: mypackage
enablerepo: myrepo
# ローカルRPMのインストール
- name: ローカルRPMのインストール
dnf:
name: /tmp/mypackage-1.0.rpm
state: present
disable_gpg_check: yes
# pip モジュール(Python パッケージ)
- name: Python パッケージのインストール
pip:
name:
- flask
- sqlalchemy
- gunicorn
version: ">=2.0"
state: present
virtualenv: /opt/myapp/venv
virtualenv_python: python3
11.2 サービス管理モジュール
service モジュール
tasks:
# サービスの起動
- name: Nginx の起動
service:
name: nginx
state: started # started/stopped/restarted/reloaded
# 自動起動の設定
- name: Nginx の自動起動有効化
service:
name: nginx
enabled: yes
# 起動と有効化を同時に
- name: Nginx の起動と有効化
service:
name: nginx
state: started
enabled: yes
systemd モジュール(より高機能)
tasks:
# systemd サービスの起動
- name: アプリサービスの起動
systemd:
name: myapp
state: started
enabled: yes
daemon_reload: yes # systemd デーモンのリロード
# systemd ユニットファイルの配置後にリロード
- name: カスタムユニットファイルの配置
copy:
src: myapp.service
dest: /etc/systemd/system/myapp.service
mode: '0644'
notify: systemd reload
# ハンドラでの使用
handlers:
- name: systemd reload
systemd:
daemon_reload: yes
# サービスのマスク(起動禁止)
- name: 不要なサービスのマスク
systemd:
name: postfix
masked: yes
# タイマーの管理
- name: systemd タイマーの有効化
systemd:
name: "{{ item }}"
state: started
enabled: yes
loop:
- backup.timer
- cleanup.timer
11.3 ファイル操作モジュール
file モジュール
tasks:
# ファイルの属性変更
- name: 設定ファイルのパーミッション設定
file:
path: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
state: file # file/directory/link/hard/touch/absent
# ディレクトリの作成(parents=-p相当)
- name: アプリディレクトリの作成
file:
path: "{{ item }}"
state: directory
owner: "{{ app_user }}"
group: "{{ app_group }}"
mode: '0755'
loop:
- /opt/myapp
- /opt/myapp/logs
- /opt/myapp/data
- /var/log/myapp
# シンボリックリンクの作成
- name: シンボリックリンクの作成
file:
src: /opt/myapp/current/bin/myapp
dest: /usr/local/bin/myapp
state: link
# ファイル/ディレクトリの削除
- name: 一時ファイルの削除
file:
path: /tmp/deploy_artifacts
state: absent
# タイムスタンプの更新(touch)
- name: ロックファイルの作成
file:
path: /var/run/deploy.lock
state: touch
mode: '0644'
copy モジュール
tasks:
# コントロールノードからファイルをコピー
- name: 設定ファイルのコピー
copy:
src: files/nginx.conf # roles/nginx/files/ または playbook の files/ から
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
backup: yes # 既存ファイルをバックアップ
# 内容を直接指定してファイルを作成
- name: シンプルな設定ファイルの作成
copy:
content: |
# Auto-generated by Ansible - DO NOT EDIT MANUALLY
APP_ENV={{ app_env }}
APP_PORT={{ app_port }}
DB_HOST={{ db_host }}
dest: /etc/myapp/config
owner: "{{ app_user }}"
mode: '0640'
# リモートホスト上でのファイルコピー
- name: 設定ファイルのバックアップ
copy:
src: /etc/nginx/nginx.conf
dest: /etc/nginx/nginx.conf.bak
remote_src: yes # マネージドノード上でのコピー
# ディレクトリのコピー
- name: ディレクトリの再帰的コピー
copy:
src: files/conf.d/ # 末尾の / でディレクトリの内容のみをコピー
dest: /etc/nginx/conf.d/
owner: root
group: root
mode: '0644'
directory_mode: '0755'
template モジュール
tasks:
# Jinja2 テンプレートのレンダリングとコピー
- name: Nginx 設定テンプレートの配置
template:
src: templates/nginx.conf.j2 # .j2 は省略可能
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
backup: yes
validate: '/usr/sbin/nginx -t -c %s' # 配置前の検証コマンド
notify: Nginx の設定をリロード
# バーチャルホスト設定のテンプレート配置
- name: バーチャルホスト設定の配置
template:
src: templates/vhost.conf.j2
dest: "/etc/nginx/sites-available/{{ item.server_name }}.conf"
owner: root
group: root
mode: '0644'
loop: "{{ nginx_vhosts }}"
notify: Nginx の設定をリロード
# 環境変数ファイルのテンプレート
- name: アプリの環境変数ファイル生成
template:
src: templates/app.env.j2
dest: /etc/myapp/environment
owner: "{{ app_user }}"
group: "{{ app_group }}"
mode: '0640'
lineinfile / blockinfile モジュール
tasks:
# ファイルの特定行を追加/変更
- name: /etc/hosts にエントリを追加
lineinfile:
path: /etc/hosts
line: "192.168.1.100 app.example.com"
state: present
# 正規表現で行を検索して置換
- name: SSH の PermitRootLogin を無効化
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^#?PermitRootLogin'
line: 'PermitRootLogin no'
state: present
backup: yes
notify: SSH の再起動
# ブロック単位の挿入
- name: sysctl 設定ブロックの追加
blockinfile:
path: /etc/sysctl.conf
marker: "# {mark} ANSIBLE MANAGED BLOCK - Network Tuning"
block: |
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.ip_local_port_range = 10000 65000
net.core.netdev_max_backlog = 65536
state: present
notify: sysctl の適用
11.4 ユーザー管理モジュール
tasks:
# ユーザーの作成
- name: アプリケーションユーザーの作成
user:
name: "{{ item.name }}"
uid: "{{ item.uid | default(omit) }}"
comment: "{{ item.comment | default('') }}"
shell: "{{ item.shell | default('/bin/bash') }}"
home: "{{ item.home | default('/home/' + item.name) }}"
groups: "{{ item.groups | default([]) }}"
append: "{{ item.append | default(true) }}" # グループの追加(上書きしない)
password: "{{ item.password | default('!') | password_hash('sha512') }}"
state: present
create_home: yes
loop: "{{ users }}"
# サービスユーザー(ログインなし)の作成
- name: Nginx 実行ユーザーの作成
user:
name: www-data
system: yes # システムユーザー
shell: /usr/sbin/nologin
home: /var/www
create_home: no
state: present
# ユーザーの削除
- name: 退職者アカウントの削除
user:
name: "{{ item }}"
state: absent
remove: yes # ホームディレクトリも削除
force: yes # 実行中プロセスがあっても削除
loop: "{{ removed_users }}"
# グループの管理
- name: アプリグループの作成
group:
name: "{{ item.name }}"
gid: "{{ item.gid | default(omit) }}"
state: present
loop:
- {name: developers, gid: 2001}
- {name: operators, gid: 2002}
- {name: docker, gid: 999}
# SSH authorized_key の管理
- name: SSH 公開鍵の設定
authorized_key:
user: "{{ item.user }}"
key: "{{ item.key }}"
state: present
exclusive: "{{ item.exclusive | default(false) }}"
loop: "{{ ssh_keys }}"
# vars:
# ssh_keys:
# - user: alice
# key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA..."
# - user: bob
# key: "{{ lookup('file', '~/.ssh/bob.pub') }}"
# sudoers の設定
- name: sudoers ファイルの設定
copy:
content: |
# Ansible 管理ユーザー
ansible ALL=(ALL) NOPASSWD: ALL
# Operators グループ
%operators ALL=(ALL) NOPASSWD: /usr/bin/systemctl, /usr/bin/journalctl
dest: /etc/sudoers.d/ansible-managed
owner: root
group: root
mode: '0440'
validate: '/usr/sbin/visudo -cf %s'
11.5 コマンド実行モジュール
command モジュール(推奨)
tasks:
# シンプルなコマンド実行
- name: アプリのビルド
command: make build
args:
chdir: /opt/myapp/src # カレントディレクトリの変更
# 実行結果の取得
- name: 現在のカーネルバージョン取得
command: uname -r
register: kernel_version
changed_when: false # 状態変更なしとしてマーク
- debug:
msg: "カーネルバージョン: {{ kernel_version.stdout }}"
# ファイルが存在しない場合のみ実行
- name: アプリの初期化(未実行の場合のみ)
command: /opt/myapp/bin/init.sh
args:
creates: /opt/myapp/.initialized # このファイルが存在すればスキップ
shell モジュール(パイプ、リダイレクト等が必要な場合)
tasks:
# パイプを使ったコマンド
- name: ログの集計
shell: "grep ERROR /var/log/myapp.log | wc -l"
register: error_count
changed_when: false
# ヒアドキュメントの使用
- name: SQL スクリプトの実行
shell: |
mysql -u root -p{{ db_password }} << 'EOF'
CREATE DATABASE IF NOT EXISTS appdb CHARACTER SET utf8mb4;
GRANT ALL ON appdb.* TO 'appuser'@'localhost';
FLUSH PRIVILEGES;
EOF
args:
executable: /bin/bash
no_log: true # ログに出力しない(パスワード保護)
# 環境変数の設定
- name: 環境変数付きでコマンドを実行
shell: "./deploy.sh"
args:
chdir: /opt/myapp
executable: /bin/bash
environment:
APP_ENV: production
DB_HOST: "{{ db_host }}"
API_KEY: "{{ vault_api_key }}"
no_log: true
raw モジュール(Python 不要の環境向け)
tasks:
# Python がインストールされていない最小構成の環境向け
- name: Python のインストール(Bootstrap)
raw: "apt-get install -y python3"
become: yes
11.6 その他の重要モジュール
uri モジュール(HTTP リクエスト)
tasks:
# GET リクエスト
- name: ヘルスチェック
uri:
url: "http://{{ ansible_host }}:8080/health"
method: GET
status_code: 200
return_content: yes
register: health_response
# POST リクエスト(API 呼び出し)
- name: デプロイ通知
uri:
url: "{{ slack_webhook_url }}"
method: POST
body_format: json
body:
text: "{{ inventory_hostname }} のデプロイが完了しました"
status_code: 200
no_log: true
# 認証付き API 呼び出し
- name: API からデータを取得
uri:
url: "https://api.example.com/v1/config"
method: GET
headers:
Authorization: "Bearer {{ vault_api_token }}"
Content-Type: "application/json"
status_code: 200
return_content: yes
register: api_response
no_log: true
- set_fact:
api_config: "{{ api_response.json }}"
get_url モジュール(ファイルダウンロード)
tasks:
- name: アプリのバイナリダウンロード
get_url:
url: "https://releases.example.com/myapp/{{ app_version }}/myapp-linux-amd64"
dest: "/usr/local/bin/myapp"
mode: '0755'
checksum: "sha256:abc123..." # チェックサム検証
timeout: 60
- name: RPM パッケージのダウンロード
get_url:
url: "https://packages.example.com/myapp-{{ version }}.rpm"
dest: "/tmp/myapp.rpm"
owner: root
group: root
mode: '0644'
cron モジュール
tasks:
- name: バックアップ cron ジョブの設定
cron:
name: "Daily Database Backup" # ジョブの識別名
minute: "0"
hour: "2"
day: "*"
month: "*"
weekday: "*"
job: "/opt/scripts/backup.sh >> /var/log/backup.log 2>&1"
user: backup
state: present
- name: 古いログの定期削除
cron:
name: "Cleanup old logs"
minute: "30"
hour: "3"
job: "find /var/log/myapp -name '*.log' -mtime +30 -delete"
state: present
- name: cron ジョブの削除
cron:
name: "Old Job"
state: absent
git モジュール
tasks:
- name: アプリのソースコードのデプロイ
git:
repo: "https://github.com/example/myapp.git"
dest: /opt/myapp/releases/{{ deploy_version }}
version: "{{ git_tag | default('main') }}"
depth: 1 # shallow clone
force: yes
accept_hostkey: yes
register: git_result
- name: デプロイしたバージョンのシンボリックリンク
file:
src: "/opt/myapp/releases/{{ deploy_version }}"
dest: /opt/myapp/current
state: link
when: git_result.changed
12. エラーハンドリング
12.1 エラーハンドリングの基本
tasks:
# ---- ignore_errors: エラーを無視して続行 ----
- name: オプショナルなサービスの停止
service:
name: old_service
state: stopped
ignore_errors: yes # サービスが存在しなくてもエラーにしない
# ---- failed_when: 失敗条件のカスタマイズ ----
- name: アプリの起動確認
command: /opt/myapp/bin/check_status.sh
register: status_result
failed_when:
- status_result.rc != 0
- "'CRITICAL' in status_result.stdout"
# ---- changed_when: 変更判定のカスタマイズ ----
- name: バージョン確認(変更なし)
command: myapp --version
register: version_output
changed_when: false # 常に "ok" と表示(changed にしない)
# ---- any_errors_fatal: 1台でも失敗したら全体を停止 ----
# プレイレベルで設定
- hosts: dbservers
any_errors_fatal: true
tasks:
- name: DB マイグレーション
command: /opt/app/manage.py migrate
12.2 block/rescue/always によるエラーハンドリング
tasks:
- name: アプリデプロイのエラーハンドリング
block:
# メイン処理
- name: デプロイ前のメンテナンスモード有効化
uri:
url: "http://localhost/api/maintenance"
method: POST
body_format: json
body: {enabled: true}
- name: アプリの停止
service:
name: myapp
state: stopped
- name: アプリのアップデート
git:
repo: "{{ app_repo }}"
dest: "{{ app_dir }}"
version: "{{ app_version }}"
- name: データベースのマイグレーション
command: /opt/myapp/manage.py migrate
args:
chdir: "{{ app_dir }}"
- name: アプリの起動
service:
name: myapp
state: started
- name: メンテナンスモードの無効化
uri:
url: "http://localhost/api/maintenance"
method: POST
body_format: json
body: {enabled: false}
rescue:
# エラー発生時の回復処理
- name: エラーログの取得
command: journalctl -u myapp -n 50
register: error_log
- name: エラーレポートの送信
uri:
url: "{{ slack_webhook }}"
method: POST
body_format: json
body:
text: |
:red_circle: {{ inventory_hostname }} でデプロイに失敗しました
エラー: {{ ansible_failed_task.name }}
ログ: {{ error_log.stdout[-500:] }}
- name: 前バージョンへのロールバック
git:
repo: "{{ app_repo }}"
dest: "{{ app_dir }}"
version: "{{ previous_version }}"
- name: アプリの再起動(前バージョン)
service:
name: myapp
state: restarted
- name: メンテナンスモードの解除
uri:
url: "http://localhost/api/maintenance"
method: POST
body_format: json
body: {enabled: false}
always:
# 成功・失敗に関わらず必ず実行
- name: デプロイ結果のログ記録
lineinfile:
path: /var/log/deploy_history.log
line: >
{{ ansible_date_time.iso8601 }}
host={{ inventory_hostname }}
version={{ app_version }}
result={{ ansible_failed_task is defined | ternary('FAILED', 'SUCCESS') }}
create: yes
12.3 リトライとタイムアウト
tasks:
# ---- retries/delay: リトライ設定 ----
- name: アプリの起動確認(リトライ付き)
uri:
url: "http://{{ ansible_host }}:8080/health"
status_code: 200
register: health_check
until: health_check.status == 200
retries: 12
delay: 5
# 最大 60秒 (12回 × 5秒) 待機
# ---- wait_for: ポート/ファイル/条件の待機 ----
- name: MySQL の起動待機
wait_for:
host: "{{ ansible_host }}"
port: 3306
timeout: 60
state: started
msg: "MySQL が起動しませんでした"
- name: アプリのソケット待機
wait_for:
path: /var/run/myapp/myapp.sock
timeout: 30
state: present
- name: ファイルの消滅を待機(プロセスの完了確認)
wait_for:
path: /tmp/migration.lock
state: absent
timeout: 300
# ---- async/poll: 非同期実行 ----
- name: 時間のかかる処理を非同期実行
command: /opt/scripts/long_running_task.sh
async: 600 # 最大待機時間(秒)
poll: 0 # 結果を後でチェック(即座に次のタスクへ)
register: long_task
# 他のタスクをここで実行...
- name: 非同期タスクの完了確認
async_status:
jid: "{{ long_task.ansible_job_id }}"
register: job_result
until: job_result.finished
retries: 60
delay: 10
12.4 デバッグとトラブルシューティング
tasks:
# debug モジュールによる変数の確認
- name: 変数の内容を確認
debug:
var: nginx_vhosts # 変数名を直接指定
- name: メッセージを表示
debug:
msg: "現在のユーザー: {{ ansible_user_id }}, 環境: {{ app_env }}"
verbosity: 2 # -vv 以上の時のみ表示
# assert モジュールによる前提条件の確認
- name: 前提条件のアサーション
assert:
that:
- ansible_memtotal_mb >= 2048
- ansible_processor_vcpus >= 2
- app_version is defined
- app_version is match("^[0-9]+\.[0-9]+\.[0-9]+$")
fail_msg: "サーバーの要件を満たしていません: メモリ {{ ansible_memtotal_mb }}MB, CPU {{ ansible_processor_vcpus }}コア"
success_msg: "前提条件を満たしています"
12.5 実行オプションとデバッグフラグ
# ---- 詳細出力レベル ----
ansible-playbook site.yml -v # 基本的な詳細情報
ansible-playbook site.yml -vv # より詳細なデバッグ
ansible-playbook site.yml -vvv # SSH 接続情報も表示
ansible-playbook site.yml -vvvv # 最大詳細(ネットワークデバッグ)
# ---- ドライラン ----
ansible-playbook site.yml --check
# 出力例:
# PLAY [Webサーバーのセットアップ] ************************************
# TASK [Nginx のインストール] *************************************
# ok: [web01] ← 変更なし
# TASK [Nginx の設定ファイルを配置] *******************************
# changed: [web01] ← この変更が行われる予定
# PLAY RECAP ****************************************************
# web01: ok=5 changed=1 unreachable=0 failed=0
# ---- 差分表示 ----
ansible-playbook site.yml --check --diff
# 出力例(ファイルの差分):
# --- before: /etc/nginx/nginx.conf
# +++ after: /etc/nginx/nginx.conf
# @@ -1,5 +1,6 @@
# worker_processes auto;
# +worker_rlimit_nofile 65535;
# events {
# ---- 特定タスクから開始 ----
ansible-playbook site.yml --start-at-task="Nginx の設定ファイルを配置"
# ---- 特定タグのみ実行 ----
ansible-playbook site.yml --tags "install,configure"
ansible-playbook site.yml --skip-tags "debug"
# ---- 対象ホストの絞り込み ----
ansible-playbook site.yml --limit "web01,web02"
ansible-playbook site.yml --limit "webservers:!web03" # web03 以外
# ---- ステップ実行 ----
ansible-playbook site.yml --step
# 各タスクの前に実行確認を求める
# ---- 構文チェック ----
ansible-playbook site.yml --syntax-check
# ---- リストオプション ----
ansible-playbook site.yml --list-tasks # タスク一覧
ansible-playbook site.yml --list-hosts # 対象ホスト一覧
ansible-playbook site.yml --list-tags # タグ一覧
13. べき等性 (Idempotency)
13.1 べき等性とは
べき等性(Idempotency)とは、同じ操作を何度実行しても結果が変わらないという性質です。Ansible では、すでに望ましい状態であれば変更を加えません。
初回実行: 状態A (古い) → 状態B (望ましい) ... changed: 1
2回目実行: 状態B (望ましい) → 状態B (変化なし) ... ok: 1
3回目実行: 状態B (望ましい) → 状態B (変化なし) ... ok: 1
13.2 べき等性の実例
# ---- べき等なタスク ----
# ① apt: state=present → インストール済みなら何もしない
- name: Nginx インストール(べき等)
apt:
name: nginx
state: present # ← "install" ではなく "present(現在の状態)"
# ② user: → ユーザーが存在すれば何もしない
- name: ユーザー作成(べき等)
user:
name: deploy
state: present
# ③ template: → ファイルが同じ内容なら何もしない
- name: 設定ファイルの配置(べき等)
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
# ④ file: → ディレクトリが存在すれば何もしない
- name: ディレクトリ作成(べき等)
file:
path: /opt/myapp
state: directory
# ---- べき等でないタスク(注意が必要)----
# ✗ command/shell は基本的にべき等でない
- name: ファイルの追記(非べき等!)
shell: echo "new entry" >> /etc/hosts
# 毎回実行されるたびに追記される
# ✓ 対策: creates/removes や lineinfile を使う
- name: /etc/hosts へのエントリ追加(べき等)
lineinfile:
path: /etc/hosts
line: "192.168.1.100 app.example.com"
state: present
# ✗ 初期化スクリプトの複数回実行(非べき等!)
- name: DB 初期化(非べき等!)
command: /opt/app/init_db.sh
# ✓ 対策: creates を使ってフラグファイルで制御
- name: DB 初期化(べき等化)
command: /opt/app/init_db.sh
args:
creates: /opt/app/.db_initialized # このファイルが存在すればスキップ
- name: 初期化完了フラグの作成
file:
path: /opt/app/.db_initialized
state: touch
13.3 check モードとべき等性の確認
# check モードでの確認
ansible-playbook site.yml --check
# すべてのタスクが "ok" であれば、現在の状態が望ましい状態と一致している
# 実行例(初回):
# PLAY RECAP ****
# web01: ok=4 changed=6 unreachable=0 failed=0
# 実行例(2回目以降:べき等が保たれている場合):
# PLAY RECAP ****
# web01: ok=10 changed=0 unreachable=0 failed=0
14. IaCベストプラクティス
14.1 プロジェクト構造のベストプラクティス
ansible-project/
├── ansible.cfg # プロジェクト設定
├── requirements.yml # 依存コレクション/ロール
│
├── inventory/
│ ├── production/
│ │ ├── hosts.yml # 本番インベントリ
│ │ ├── group_vars/
│ │ │ ├── all/
│ │ │ │ ├── vars.yml # 共通変数
│ │ │ │ └── vault.yml # 暗号化変数
│ │ │ ├── webservers.yml
│ │ │ └── dbservers.yml
│ │ └── host_vars/
│ │ ├── web01.yml
│ │ └── db01.yml
│ └── staging/
│ ├── hosts.yml
│ └── group_vars/
│ └── all.yml
│
├── playbooks/
│ ├── site.yml # マスタープレイブック
│ ├── webservers.yml # Webサーバー専用
│ ├── dbservers.yml # DBサーバー専用
│ └── maintenance/
│ ├── update.yml # OSアップデート
│ └── backup.yml # バックアップ
│
├── roles/
│ ├── common/ # 全サーバー共通
│ ├── nginx/ # Nginx ロール
│ ├── mysql/ # MySQL ロール
│ └── myapp/ # アプリロール
│
├── library/ # カスタムモジュール
├── filter_plugins/ # カスタムフィルタ
└── tests/
├── molecule/ # Molecule テスト
└── integration/ # 統合テスト
14.2 変数管理のベストプラクティス
# ✓ ロールの defaults/ でデフォルト値を定義(上書き可能)
# roles/nginx/defaults/main.yml
nginx_port: 80
nginx_ssl_port: 443
nginx_worker_processes: auto
# ✓ 環境固有の値は group_vars/host_vars で上書き
# inventory/production/group_vars/webservers.yml
nginx_worker_processes: 4
# ✓ 機密情報は必ず Vault で暗号化
# group_vars/all/vault.yml(暗号化済み)
vault_db_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
...
# ✓ Vault 変数には vault_ プレフィックスを付ける
# group_vars/all/vars.yml(平文)
db_password: "{{ vault_db_password }}" # Vault 変数を通常変数でラップ
14.3 セキュリティのベストプラクティス
# ---- 1. no_log でパスワードを保護 ----
- name: MySQL パスワードの設定
mysql_user:
name: root
password: "{{ db_root_password }}"
state: present
no_log: true # タスクの出力をログに残さない
# ---- 2. become は必要な時のみ ----
# プレイレベルで become: false をデフォルトにして
# 必要なタスクのみで become: true を指定
- hosts: webservers
become: false # デフォルトは非昇格
tasks:
- name: ヘルスチェック(昇格不要)
uri:
url: http://localhost/health
- name: Nginx の再起動(昇格必要)
service:
name: nginx
state: restarted
become: true # このタスクのみ昇格
# ---- 3. validate で設定ファイルの検証 ----
- name: nginx.conf の配置
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
validate: '/usr/sbin/nginx -t -c %s'
- name: sudoers の配置
template:
src: sudoers.j2
dest: /etc/sudoers.d/myconf
validate: '/usr/sbin/visudo -cf %s'
# ---- 4. 最小権限の原則 ----
# SSH 鍵の設定
- name: Ansible 用 SSH 鍵の設定
authorized_key:
user: ansible
key: "{{ lookup('file', 'files/ansible.pub') }}"
exclusive: yes # 他の鍵を排除(管理を明確化)
14.4 パフォーマンスのベストプラクティス
# ansible.cfg でのパフォーマンス最適化
[defaults]
# 並列実行数を増やす(サーバー台数に応じて調整)
forks = 50
# ファクトキャッシュの有効化(再収集を省略)
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_facts
fact_caching_timeout = 86400
# gathering の最適化
gathering = smart # キャッシュが有効ならファクト収集をスキップ
[ssh_connection]
# SSH 接続のパイプライン化(パフォーマンス大幅向上)
pipelining = True
# ControlMaster による接続の再利用
ssh_args = -C -o ControlMaster=auto -o ControlPersist=60s
# プレイブック内でのパフォーマンス最適化
# ファクト収集が不要な場合は無効化
- hosts: all
gather_facts: false
tasks: ...
# 必要なファクトのみ収集
- hosts: all
gather_facts: true
gather_subset:
- min # 最小限のファクトのみ
- hardware # ハードウェア情報も取得
tasks: ...
# 並列実行の制御(ローリングアップデート)
- hosts: webservers
serial: "30%" # 一度に30%ずつ更新(Canary デプロイ)
max_fail_percentage: 10
tasks: ...
14.5 コード品質のベストプラクティス
# ---- ansible-lint によるコード品質チェック ----
pip install ansible-lint
# プレイブックの linting
ansible-lint site.yml
# プロジェクト全体の linting
ansible-lint
# 出力例:
# [yaml] Too many blank lines (2 > 1)
# site.yml:15
# [package-latest] Package installed with 'latest' not 'present'
# roles/nginx/tasks/main.yml:12
# ---- .ansible-lint 設定ファイル ----
cat > .ansible-lint << 'EOF'
---
profile: moderate # minimal/basic/moderate/safety/shared/production
# 無効化するルール
skip_list:
- "yaml[line-length]" # 行長チェックを無効化
# カスタムルールの追加
rulesdir:
- ./custom_lint_rules/
EOF
# ---- yamllint によるYAML構文チェック ----
pip install yamllint
cat > .yamllint << 'EOF'
extends: default
rules:
line-length:
max: 120
truthy:
allowed-values: ['true', 'false', 'yes', 'no']
EOF
yamllint site.yml
yamllint roles/
14.6 テストのベストプラクティス
# ---- Molecule によるロールのテスト ----
pip install molecule molecule-docker
# ロールのテスト初期化
cd roles/nginx
molecule init scenario --driver-name docker
# テストシナリオの実行
molecule test # full test: create → converge → verify → destroy
# 個別ステップの実行
molecule create # テスト用コンテナを起動
molecule converge # ロールをコンテナに適用
molecule verify # テストを実行
molecule destroy # コンテナを削除
# molecule/default/molecule.yml
# molecule/default/molecule.yml
---
dependency:
name: galaxy
driver:
name: docker
platforms:
- name: ubuntu-22-04
image: geerlingguy/docker-ubuntu2204-ansible:latest
pre_build_image: true
- name: rockylinux-9
image: geerlingguy/docker-rockylinux9-ansible:latest
pre_build_image: true
provisioner:
name: ansible
verifier:
name: ansible
# molecule/default/verify.yml
---
- name: Nginx ロールの検証
hosts: all
tasks:
- name: Nginx が起動しているか確認
command: systemctl is-active nginx
changed_when: false
- name: ポート 80 が Listen しているか確認
wait_for:
host: localhost
port: 80
timeout: 5
- name: HTTP レスポンスの確認
uri:
url: http://localhost/
status_code: 200
14.7 Git によるバージョン管理
# ---- .gitignore ----
cat > .gitignore << 'EOF'
# 暗号化されていない機密情報
*secret*
*password*
!*vault* # vault ファイルは含める(暗号化済み)
# ローカル設定
*.retry
.ansible/
# ログファイル
*.log
# ファクトキャッシュ
.fact_cache/
/tmp/
# Python
__pycache__/
*.pyc
.venv/
EOF
# コミット前のチェック
ansible-lint
yamllint .
ansible-playbook --syntax-check site.yml
# pre-commit フックの設定
pip install pre-commit
cat > .pre-commit-config.yaml << 'EOF'
repos:
- repo: https://github.com/ansible/ansible-lint
rev: v24.2.0
hooks:
- id: ansible-lint
- repo: https://github.com/adrienverge/yamllint
rev: v1.35.1
hooks:
- id: yamllint
EOF
pre-commit install
15. Ansibleと他ツールの比較
15.1 主要構成管理ツールの比較
| 項目 | Ansible | Puppet | Chef | SaltStack | Terraform |
|---|---|---|---|---|---|
| アーキテクチャ | エージェントレス | エージェント型 | エージェント型 | エージェント型/レス | エージェントレス |
| 通信プロトコル | SSH/WinRM | TLS/MQ | HTTPS | ZeroMQ/HTTPS | HTTPS API |
| 設定言語 | YAML | Puppet DSL | Ruby (DSL) | YAML/Python | HCL |
| 実行モデル | Push | Pull | Pull | Push/Pull | Push |
| 学習コスト | 低 | 高 | 高 | 中 | 中 |
| べき等性 | ○(設計依存) | ◎(標準) | ◎(標準) | ○(設計依存) | ◎(標準) |
| Windows 対応 | △(WinRM) | ○ | ○ | △ | ○(プロバイダ依存) |
| コミュニティ | 非常に大きい | 大きい | 中程度 | 中程度 | 非常に大きい |
| 商用版 | AAP (Red Hat) | Puppet Enterprise | Chef Automate | SaltStack Enterprise | Terraform Cloud |
| 主な用途 | 構成管理/デプロイ | 構成管理 | 構成管理 | 構成管理/オーケストレーション | インフラプロビジョニング |
15.2 Ansible vs Terraform の使い分け
┌─────────────────────────────────────────────────────────┐
│ インフラ管理の役割分担 │
│ │
│ Terraform (プロビジョニング) │
│ ┌────────────────────────────────────────────────┐ │
│ │ VM, Network, Storage, DNS, LB, Security Group │ │
│ │ → 「リソースの作成・削除」が得意 │ │
│ └────────────────────────────────────────────────┘ │
│ ↓ │
│ Ansible (構成管理) │
│ ┌────────────────────────────────────────────────┐ │
│ │ OS設定, パッケージ, サービス, デプロイ │ │
│ │ → 「作成済みサーバーの設定変更」が得意 │ │
│ └────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
典型的なワークフロー:
1. Terraform でインフラを作成 (EC2, VPC, etc.)
2. Ansible で OS/ミドルウェアを設定
3. Ansible でアプリをデプロイ
15.3 Push型 vs Pull型
| 観点 | Push型 (Ansible) | Pull型 (Puppet/Chef) |
|---|---|---|
| 設定適用のタイミング | 管理者が実行時 | エージェントが定期的に |
| 新規サーバーの設定 | 手動またはCI/CDで実行 | エージェントが自動で取得 |
| スケール | コントロールノードに負荷集中 | 分散処理が得意 |
| ネットワーク障害 | 適用不可(接続できない) | キャッシュで対応可能 |
| セキュリティ | SSHのみ開放でOK | エージェントのポートが必要 |
| デバッグ | 実行時のログが直接確認可能 | エージェントのログを確認 |
16. 実践的なプレイブック例
16.1 LAMP スタックの完全セットアップ
# playbooks/lamp_stack.yml
---
- name: LAMP スタックのセットアップ
hosts: webservers
become: true
vars:
php_version: "8.2"
mysql_root_password: "{{ vault_mysql_root_password }}"
app_db_name: myapp
app_db_user: myapp_user
app_db_password: "{{ vault_app_db_password }}"
app_domain: "{{ inventory_hostname }}.example.com"
app_deploy_path: /var/www/myapp
pre_tasks:
- name: apt キャッシュの更新
apt:
update_cache: yes
cache_valid_time: 3600
tasks:
# --- Apache のセットアップ ---
- name: Apache のインストール
apt:
name:
- apache2
- apache2-utils
state: present
- name: Apache モジュールの有効化
apache2_module:
name: "{{ item }}"
state: present
loop:
- rewrite
- ssl
- headers
notify: Apache の再起動
# --- PHP のセットアップ ---
- name: PHP PPA の追加
apt_repository:
repo: "ppa:ondrej/php"
state: present
update_cache: yes
- name: PHP と必要な拡張モジュールのインストール
apt:
name:
- "php{{ php_version }}"
- "php{{ php_version }}-mysql"
- "php{{ php_version }}-curl"
- "php{{ php_version }}-gd"
- "php{{ php_version }}-mbstring"
- "php{{ php_version }}-xml"
- "php{{ php_version }}-zip"
- "php{{ php_version }}-fpm"
- libapache2-mod-fcgid
state: present
# --- MySQL のセットアップ ---
- name: MySQL のインストール
apt:
name:
- mysql-server
- python3-pymysql
state: present
- name: MySQL サービスの起動と有効化
service:
name: mysql
state: started
enabled: yes
- name: MySQL root パスワードの設定
mysql_user:
name: root
host: localhost
password: "{{ mysql_root_password }}"
login_unix_socket: /var/run/mysqld/mysqld.sock
state: present
no_log: true
- name: アプリ用データベースの作成
mysql_db:
name: "{{ app_db_name }}"
encoding: utf8mb4
collation: utf8mb4_unicode_ci
login_user: root
login_password: "{{ mysql_root_password }}"
state: present
no_log: true
- name: アプリ用 MySQL ユーザーの作成
mysql_user:
name: "{{ app_db_user }}"
host: localhost
password: "{{ app_db_password }}"
priv: "{{ app_db_name }}.*:ALL"
login_user: root
login_password: "{{ mysql_root_password }}"
state: present
no_log: true
# --- アプリのデプロイ ---
- name: アプリディレクトリの作成
file:
path: "{{ app_deploy_path }}"
state: directory
owner: www-data
group: www-data
mode: '0755'
- name: Apache バーチャルホスト設定
template:
src: templates/apache_vhost.conf.j2
dest: "/etc/apache2/sites-available/{{ app_domain }}.conf"
owner: root
group: root
mode: '0644'
notify: Apache の設定をリロード
- name: バーチャルホストの有効化
command: "a2ensite {{ app_domain }}"
args:
creates: "/etc/apache2/sites-enabled/{{ app_domain }}.conf"
notify: Apache の設定をリロード
- name: デフォルトサイトの無効化
command: a2dissite 000-default
args:
removes: /etc/apache2/sites-enabled/000-default.conf
notify: Apache の設定をリロード
- name: アプリの設定ファイル生成
template:
src: templates/app_config.php.j2
dest: "{{ app_deploy_path }}/config.php"
owner: www-data
group: www-data
mode: '0640'
no_log: true
handlers:
- name: Apache の再起動
service:
name: apache2
state: restarted
- name: Apache の設定をリロード
service:
name: apache2
state: reloaded
post_tasks:
- name: Apache のステータス確認
command: apache2ctl configtest
changed_when: false
- name: デプロイ完了の確認
uri:
url: "http://{{ ansible_default_ipv4.address }}/health.php"
status_code: 200
register: health_check
retries: 5
delay: 3
until: health_check.status == 200
16.2 ローリングアップデートの実装
# playbooks/rolling_update.yml
---
- name: ローリングアップデート
hosts: webservers
become: true
serial: 1 # 1台ずつ更新
max_fail_percentage: 0 # 1台でも失敗したら停止
vars:
app_version: "{{ new_version | mandatory }}"
lb_host: lb01
tasks:
# 1. ロードバランサーから切り離す
- name: LB からサーバーを切り離す
uri:
url: "http://{{ lb_host }}/api/servers/{{ inventory_hostname }}/disable"
method: POST
status_code: 200
delegate_to: "{{ lb_host }}"
- name: 既存接続の切断待機
pause:
seconds: 30
# 2. アプリの停止
- name: アプリの停止
service:
name: myapp
state: stopped
# 3. アップデートの実行
- name: 新バージョンのダウンロード
get_url:
url: "https://releases.example.com/myapp/{{ app_version }}/myapp.tar.gz"
dest: "/tmp/myapp_{{ app_version }}.tar.gz"
checksum: "{{ release_checksum }}"
- name: バックアップの作成
copy:
src: /opt/myapp/current/
dest: "/opt/myapp/backup_{{ ansible_date_time.epoch }}/"
remote_src: yes
- name: 新バージョンの展開
unarchive:
src: "/tmp/myapp_{{ app_version }}.tar.gz"
dest: /opt/myapp/releases/
remote_src: yes
- name: シンボリックリンクの更新
file:
src: "/opt/myapp/releases/myapp-{{ app_version }}"
dest: /opt/myapp/current
state: link
force: yes
# 4. アプリの起動と確認
- name: アプリの起動
service:
name: myapp
state: started
- name: アプリの起動確認
uri:
url: "http://localhost:8080/health"
status_code: 200
register: health
until: health.status == 200
retries: 10
delay: 5
# 5. ロードバランサーに復帰
- name: LB にサーバーを復帰
uri:
url: "http://{{ lb_host }}/api/servers/{{ inventory_hostname }}/enable"
method: POST
status_code: 200
delegate_to: "{{ lb_host }}"
- name: 一時ファイルの削除
file:
path: "/tmp/myapp_{{ app_version }}.tar.gz"
state: absent
17. トラブルシューティング
17.1 よくある問題と解決策
| 問題 | 原因 | 解決策 |
|---|---|---|
UNREACHABLE エラー | SSH 接続失敗 | SSH設定、ファイアウォール、ホスト名解決を確認 |
Permission denied | sudo設定が不十分 | sudoers 設定、become設定を確認 |
Python not found | Pythonが未インストール | raw モジュールでPythonをインストール |
Module not found | コレクションが未インストール | ansible-galaxy collection install を実行 |
Template error | Jinja2 構文エラー | --check と -vv で詳細確認 |
fact not found | ファクト収集失敗 | gather_facts: true と -vvv で確認 |
Vault decrypt failed | パスワード不一致 | Vault パスワードを確認 |
host_key_checking エラー | 未知のホスト鍵 | known_hosts への追加または host_key_checking=False |
17.2 デバッグコマンド集
# ---- 接続テスト ----
# SSH 直接接続テスト
ssh -i ~/.ssh/ansible_ed25519 -v ansible@web01
# Ansible 経由の接続テスト
ansible web01 -m ping -vvv
# ---- 変数とファクトの確認 ----
# ファクトの確認
ansible web01 -m setup | python3 -m json.tool | less
# 特定ファクトの確認
ansible web01 -m setup -a "filter=ansible_network_interfaces"
# インベントリの変数確認
ansible-inventory --host web01 | python3 -m json.tool
# ---- プレイブックのデバッグ ----
# 構文チェック
ansible-playbook site.yml --syntax-check
# ドライラン+差分表示
ansible-playbook site.yml --check --diff
# タスク一覧の確認
ansible-playbook site.yml --list-tasks
# ステップ実行(各タスクで確認)
ansible-playbook site.yml --step
# デバッグレベルの最大化
ansible-playbook site.yml -vvvv 2>&1 | tee /tmp/ansible_debug.log
# ---- 特定タスクのデバッグ ----
# 特定タスクから実行開始
ansible-playbook site.yml --start-at-task="Nginx の設定ファイルを配置" -vv
# ---- ログの確認 ----
# Ansible ログ(ansible.cfg で設定した場合)
tail -f ./ansible.log
# マネージドノードのログ
ansible web01 -m command -a "journalctl -xe --no-pager -n 50"
17.3 パフォーマンス改善のチェックリスト
# SSH 接続のパフォーマンス確認
time ssh web01 "echo test"
# Ansible の実行時間を測定
time ansible-playbook site.yml
# profile_tasks コールバックで各タスクの時間を計測
ANSIBLE_CALLBACK_WHITELIST=profile_tasks ansible-playbook site.yml
# または ansible.cfg で常時有効化
# [defaults]
# callbacks_enabled = profile_tasks, timer
18. 参考資料
18.1 公式ドキュメント
| リソース | URL |
|---|---|
| Ansible ドキュメント | https://docs.ansible.com/ |
| ansible-core ドキュメント | https://docs.ansible.com/ansible-core/latest/ |
| モジュールインデックス | https://docs.ansible.com/ansible/latest/collections/index.html |
| Ansible Galaxy | https://galaxy.ansible.com/ |
| Ansible GitHub | https://github.com/ansible/ansible |
18.2 推奨コレクション
# requirements.yml
collections:
- name: community.general # 汎用モジュール集
- name: community.mysql # MySQL 管理
- name: community.postgresql # PostgreSQL 管理
- name: ansible.posix # POSIX システム管理
- name: amazon.aws # AWS 管理
- name: google.cloud # GCP 管理
- name: azure.azcollection # Azure 管理
- name: kubernetes.core # Kubernetes 管理
- name: community.docker # Docker 管理
18.3 学習リソース
| 種別 | タイトル | 説明 |
|---|---|---|
| 書籍 | Ansible for DevOps (Jeff Geerling) | 実践的な Ansible の教科書 |
| 書籍 | Ansible: Up and Running | 公式に近い包括的ガイド |
| コース | Red Hat DO374 (Developing Advanced Automation with Ansible) | 公式トレーニング |
| 認定 | Red Hat Certified Specialist in Ansible Automation | Ansible の公式認定試験 |
| GitHub | https://github.com/geerlingguy | 豊富な実践的ロールのサンプル |
| Blog | https://www.jeffgeerling.com/ | Ansible の実践的な記事 |
18.4 バージョン対応表
| ansible-core | Python サポート | 主な変更点 |
|---|---|---|
| 2.17 | 3.10-3.12 | Python 3.12 対応、コレクション安定化 |
| 2.16 | 3.9-3.12 | パフォーマンス改善 |
| 2.15 | 3.9-3.11 | EL7 サポート終了 |
| 2.14 | 3.9-3.11 | core モジュールの分離完了 |
| 2.13 | 3.8-3.10 | コレクションアーキテクチャ成熟 |
まとめ
Ansible は「シンプルさ」と「強力さ」を両立した構成管理ツールです。本記事で解説した主要ポイントを振り返ります。
┌─────────────────────────────────────────────────────────┐
│ Ansible 学習ロードマップ │
│ │
│ 入門 → インストール・インベントリ・アドホックコマンド │
│ 基礎 → プレイブック・YAML・変数・条件・ループ │
│ 中級 → ロール・Vault・エラーハンドリング・べき等性 │
│ 上級 → 動的インベントリ・カスタムモジュール・Molecule・CI/CD │
│ 実践 → 大規模運用・AWX/AAP・パフォーマンスチューニング │
└─────────────────────────────────────────────────────────┘
重要な設計原則:
- べき等性を常に意識する — 何度実行しても安全な設計
- 機密情報は必ず Vault で暗号化する — コードとして安全に管理
- ロールで再利用性を高める — DRY (Don't Repeat Yourself)
- バージョン管理と CI/CD に組み込む — コードとして品質を保つ
- check モードでテストしてから本番適用 — 安全な変更管理
Ansible は構成管理の自動化だけでなく、アプリケーションデプロイ、クラウドインフラ管理、ネットワーク機器の設定管理など、幅広い用途に活用できる強力なツールです。本記事を出発点として、実際の環境で積み重ねることで確かなスキルが身につきます。
本記事は ansible-core 2.17 を基準に執筆しました。
最終更新: 2026年4月