Ansible入門|サーバー構成管理をPlaybookで自動化する基本と実践

kento_morota 15分で読めます
社内のAI・IT活用、技術がわかる相手に無料相談。 相談 →
目次

新しいサーバーを1台追加するたびに、以前の手順書を見ながらパッケージを入れ、設定ファイルをコピーし、ユーザーを作り……気づけば半日が過ぎている。しかも「前回入れたはずの設定が今回のサーバーには入っていない」といった差分が積み重なり、本番の2台がいつの間にか微妙に違う状態になっている。こうした悩みに対する定番の答えがAnsibleです。

この記事では、手作業セットアップの限界と「冪等性」という考え方、Ansibleがエージェント不要で動く仕組み、インベントリ・Playbook・ロールという3つの構造、Nginxとアプリを配置する最小のPlaybook例、Terraformとの役割分担、そしてansible-vaultによる秘密情報の扱いまでを解説します。IaC全体の比較はIaCとは?インフラのコード化入門、Terraformの基本はTerraform入門で扱っているので、ここではAnsibleに集中します。

手作業セットアップの限界と冪等性

手順書は「実行した人」に依存する

手順書ベースの運用が破綻するのは、手順書が正しくても、実行するたびに結果が変わるからです。コマンドの打ち間違い、手順の飛ばし、OSのバージョン違いによる挙動の差、「ついでに」入れた設定。これらが積もると、同じ役割のサーバーが同じ状態ではなくなり、「Aでは動くのにBでは動かない」というトラブルの温床になります。さらに、手順書を書いた本人が離れると、誰も再現できなくなります。

冪等性:何度実行しても同じ結果になる

構成管理ツールの核となる考え方が冪等性(べきとうせい)です。「Nginxをインストールする」というコマンドを2回実行すると、2回目はエラーになるか二重にインストールしようとしますが、「Nginxがインストールされた状態にする」というあるべき状態の宣言なら、何度実行しても結果は同じです。すでにその状態ならAnsibleは何もせず「ok」と報告し、違っていれば修正して「changed」と報告します。

この性質があるため、Ansibleは「新規構築」だけでなく「設定の一括変更」「意図しない変更の検出と修復(ドリフト検出)」にも使えます。毎晩Playbookを流しておけば、誰かが手で変えた設定は翌朝には戻っています。

Ansibleの仕組み|エージェントレスとPush型

SSHで入ってPythonを実行するだけ

Chefや旧来のPuppetは、管理対象のサーバーにエージェントを常駐させ、エージェントが中央サーバーから設定を取りに行く(Pull型)方式でした。Ansibleは逆に、管理者の手元(コントロールノード)からSSHで対象サーバーに接続し、小さなPythonスクリプト(モジュール)を転送して実行し、結果を受け取ります(Push型)。対象サーバーに必要なのはSSH接続とPythonだけで、専用のエージェントもポートも不要です。

この設計が中小規模の運用に向いている理由は次のとおりです。

  • 既存のサーバーに何も入れずに始められる。SSHで入れる相手ならすぐ管理対象にできる。
  • 中央サーバーの構築や維持が不要。ノートPCやCIランナーがコントロールノードになる。
  • SSHの鍵管理や踏み台経由の接続を、そのままAnsibleでも使える。
# インストール(macOS/Linux。pipxで隔離して入れるのが管理しやすい)
pipx install ansible

# 疎通確認:インベントリの全ホストにpingモジュールを実行
ansible all -i inventory.ini -m ping

# アドホックに1コマンド実行(-b は become=sudo)
ansible web -i inventory.ini -b -m apt -a "name=nginx state=present update_cache=yes"

インベントリ・Playbook・ロールの構造

3つの部品の役割

部品役割ファイルの例
インベントリ「どのサーバーに」を定義する。ホスト一覧とグループ分け、接続情報inventory.iniinventory/production.yml
Playbook「どのグループに、どの順で、何をするか」を定義するYAMLsite.ymldeploy.yml
ロール「Nginxの設定」のような再利用可能な作業のまとまり。タスク・テンプレート・変数・ハンドラを決まったディレクトリ構成で持つroles/nginx/roles/app/
# inventory.ini:グループごとにホストを列挙し、グループ変数を付ける
[web]
web1 ansible_host=10.0.11.21
web2 ansible_host=10.0.11.22

[db]
db1 ansible_host=10.0.21.5

[web:vars]
ansible_user=ops
ansible_ssh_common_args='-o ProxyJump=bastion'

# ディレクトリ構成の例
.
├── inventory.ini
├── site.yml
├── group_vars/
│   └── web.yml            # webグループ共通の変数
└── roles/
    ├── nginx/
    │   ├── tasks/main.yml
    │   ├── templates/app.conf.j2
    │   └── handlers/main.yml
    └── app/
        ├── tasks/main.yml
        └── templates/app.service.j2

最初はsite.yml1枚にすべて書いても構いません。タスクが増えて見通しが悪くなったら、役割ごとにロールへ切り出します。ロールの構造は決まっているため、他の人が書いたロールも同じ場所を見れば理解できるのが利点です。

最小Playbook例|Nginxとアプリの配置

Nginxロール:インストール・設定・再読み込み

# roles/nginx/tasks/main.yml
- name: Nginxをインストール
  ansible.builtin.apt:
    name: nginx
    state: present
    update_cache: yes

- name: サイト設定を配置(テンプレートから生成)
  ansible.builtin.template:
    src: app.conf.j2
    dest: /etc/nginx/sites-available/app.conf
    mode: "0644"
  notify: reload nginx

- name: サイトを有効化
  ansible.builtin.file:
    src: /etc/nginx/sites-available/app.conf
    dest: /etc/nginx/sites-enabled/app.conf
    state: link
  notify: reload nginx

- name: Nginxを起動・自動起動に設定
  ansible.builtin.service:
    name: nginx
    state: started
    enabled: yes

# roles/nginx/handlers/main.yml
- name: reload nginx
  ansible.builtin.service:
    name: nginx
    state: reloaded

# roles/nginx/templates/app.conf.j2(変数はgroup_varsから)
server {
    listen 80;
    server_name {{ server_name }};
    location / {
        proxy_pass http://127.0.0.1:{{ app_port }};
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

ここで重要なのがnotifyhandlersの関係です。設定ファイルが「変更されたときだけ」Nginxをリロードし、変更がなければ何もしません。これが冪等性を保ちながらサービスを不必要に再起動しない仕組みです。Nginx自体の設定項目はLinux×Nginx入門を参照してください。

アプリロールとsite.yml

# roles/app/tasks/main.yml(Gitからコードを取得しsystemdで起動する例)
- name: アプリ用ユーザーを作成
  ansible.builtin.user:
    name: app
    system: yes
    shell: /usr/sbin/nologin

- name: コードを取得
  ansible.builtin.git:
    repo: "{{ app_repo }}"
    dest: /opt/app
    version: "{{ app_version }}"
  notify: restart app

- name: 依存をインストール
  ansible.builtin.pip:
    requirements: /opt/app/requirements.txt
    virtualenv: /opt/app/.venv

- name: systemdユニットを配置
  ansible.builtin.template:
    src: app.service.j2
    dest: /etc/systemd/system/app.service
  notify: restart app

- name: アプリを起動
  ansible.builtin.systemd:
    name: app
    state: started
    enabled: yes
    daemon_reload: yes

# site.yml
- hosts: web
  become: yes
  roles:
    - nginx
    - app

# 実行。--check は変更を適用せず差分だけ表示(ドライラン)、--diff で内容を表示
ansible-playbook -i inventory.ini site.yml --check --diff
ansible-playbook -i inventory.ini site.yml

本番に流す前に必ず--check --diffで「何が変わるか」を確認する習慣をつけてください。systemdユニットの書き方はsystemdとは?Linuxのサービス管理で扱っています。

Terraformとの役割分担

「箱を作る」のがTerraform、「中身を整える」のがAnsible

TerraformとAnsibleはどちらもIaCツールですが、得意な層が違います。Terraformはクラウドのリソース(VPC、EC2、RDS、ロードバランサー)を作成・変更・削除する「インフラのプロビジョニング」に強く、Ansibleは作られたサーバーのOSの中(パッケージ、設定ファイル、サービス、ユーザー)を整える「構成管理」に強い。両方使う場合の典型的な流れは次のとおりです。

  1. TerraformでEC2やネットワークを作る。出力(IPアドレスやタグ)をAnsibleのインベントリに渡す。
  2. AnsibleでOS設定、ミドルウェア、アプリを配置する。
  3. 以後、インフラの変更はTerraform、サーバー内の変更はAnsibleで行い、手作業を排除する。
やりたいこと使うツール理由
サーバーを3台に増やすTerraformクラウドAPIの操作
全サーバーのNginx設定を変えるAnsibleOS内の設定変更
セキュリティグループの穴をふさぐTerraformクラウドリソースの属性
OSのセキュリティ更新を一斉適用するAnsibleパッケージ操作
コンテナ化されたアプリをKubernetesに配るどちらも不向き(GitOps系ツール)コンテナ環境ではイメージが「構成」を担う

コンテナ中心の環境では、サーバー内の構成はDockerイメージに焼き込まれるため、Ansibleの出番は「ホストOSの初期設定」程度に減ります。その世界での配置の考え方はGitOps入門で扱っています。逆に、EC2やVPS上で直接アプリを動かす構成では、Ansibleが最も費用対効果の高い自動化手段です。

秘密情報の扱い|ansible-vault

パスワードを平文でGitに入れない

Playbookにはデータベースのパスワードや外部APIのキーが必要になりますが、平文でリポジトリに入れてはいけません。Ansibleに同梱されているansible-vaultは、変数ファイルをパスワードで暗号化し、実行時に復号します。暗号化されたファイルはGitにコミットでき、復号用のパスワードだけを別経路(パスワードマネージャー、CIのシークレット)で管理します。

# 秘密変数ファイルを暗号化して作成
ansible-vault create group_vars/web/vault.yml
# 中身(エディタが開く)
# vault_db_password: "S3cr3t!"

# 既存ファイルの編集・閲覧
ansible-vault edit group_vars/web/vault.yml
ansible-vault view group_vars/web/vault.yml

# 実行時にパスワードを渡す(対話入力 or パスワードファイル)
ansible-playbook -i inventory.ini site.yml --ask-vault-pass
ansible-playbook -i inventory.ini site.yml --vault-password-file ~/.vault_pass

# 平文の変数ファイル側では vault_ 接頭辞の変数を参照する(検索性のため)
# group_vars/web/vars.yml
# db_password: "{{ vault_db_password }}"

より大規模になったら、VaultやAWS Parameter Storeから実行時に取得するlookupプラグインへ移行します。秘密情報の管理方針全体はシークレット管理入門を参照してください。

トラブル事例:Playbookを流したら本番の設定が消えた

症状:Nginxの設定変更をAnsibleで適用したところ、本番で動いていた別サイトの設定が消え、そのサイトが停止した。

原因:本番サーバーには、Ansible導入前に手作業で追加した2つ目のサイト設定がsites-enabledに置かれていた。Playbookは「Ansibleが管理する設定以外は削除する」タスク(不要ファイルの掃除)を含んでおり、手作業で入れた設定が「管理外」として消された。ステージングには手作業の設定がなかったため、事前確認で気づけなかった。

対処:バックアップから設定を復元して復旧。恒久対策として、(1)Ansible導入時に既存サーバーの設定をすべて棚卸しし、Playbookに取り込む、(2)本番への初回適用は必ず--check --diffで削除される項目を確認する、(3)ステージングを本番と同じ手順で作り直し、環境差をなくす、の3点を実施した。「あるべき状態を宣言する」ツールは、宣言されていないものを容赦なく扱う、という性質を理解しておく必要があります。

Ansible導入の進め方

  1. まず1台のステージングサーバーを対象に、Nginx+アプリのPlaybookを書き、何度流しても「changed=0」になることを確認する。
  2. 既存の本番サーバーの設定を棚卸しし、Playbookに反映する。差分は--check --diffで確認する。
  3. 本番に適用し、以後の変更はすべてPlaybook経由にする。手作業での変更を禁止する。
  4. PlaybookをGitで管理し、変更はプルリクエストでレビューする。秘密情報はansible-vaultで暗号化する。
  5. CIから定期実行して、設定のズレ(ドリフト)を検出・修復する。

まとめ

Ansibleは、SSHとPythonだけで動くエージェントレスの構成管理ツールで、「あるべき状態を宣言し、何度流しても同じ結果になる」冪等性によって、手作業セットアップの再現性の問題を解消します。インベントリで対象を、Playbookで手順を、ロールで再利用単位を定義し、notifyhandlersで変更時だけサービスを再読み込みする。Terraformでクラウドの箱を作り、Ansibleで中身を整えるという分担を守り、秘密情報はansible-vaultで暗号化してGitに置く。これが基本形です。

まずは開発用のサーバーを1台用意し、この記事のNginx+アプリのPlaybookを流して「changed=0」になるまで整えてみてください。手順書に依存しない運用への移行や、Terraform・Ansibleを組み合わせたインフラ自動化の設計にお困りの際は、Harmonic Societyのシステム開発・インフラ支援にご相談ください。

#Ansible#構成管理#自動化#IaC

Harmonic Society

この記事の内容、自社の業務でも活かせそうですか?

ローカルLLM・AI・クラウドなどの技術導入を、要件整理からPoC・社内展開まで代表エンジニアが伴走します。オンライン対応・全国OK。まずは30分の無料相談から。売り込みはしません。

共有:
無料メルマガ

週1回、最新の技術記事をお届け

AI・クラウド・開発の最新記事を毎週月曜にメールでお届けします。登録は無料、いつでも解除できます。

プライバシーポリシーに基づき管理します

関連記事

Related / 9 articles

  1. プログラミング

    DDoS攻撃の仕組みと対策入門|レイヤー別の防御とCDN・クラウドの活用

    DDoS攻撃をボリューム型・プロトコル型・アプリ層に分けて仕組みを解説し、自前サーバーで防げない理由、CloudflareやAWS Shieldの標準防御、オリジンIPの隠し方、レートリミットとBot対策、攻撃を受けたときの初動、費用が跳ね上がるDenial of Walletへの備えまでわかります。

  2. プログラミング

    WAFとは?仕組み・導入パターン・誤検知対策|Webアプリを攻撃から守る実践ガイド

    WAFがファイアウォールやIDSと何が違うのか、シグネチャとマネージドルールの仕組み、Cloudflare WAF・AWS WAF・ModSecurityの比較、フォーム送信がブロックされる誤検知の調査と例外設定、ログ監視、WAFが代替できないことまで実践的に解説します。

  3. プログラミング

    セキュリティヘッダー入門|CSP・HSTS・X-Frame-Optionsの設定と効果を実践解説

    CSP・HSTS・X-Frame-Options・X-Content-Type-Optionsなど主要セキュリティヘッダーが防ぐ攻撃と、CSPのReport-Onlyからの段階導入、nonce/hash、HSTS preloadの不可逆リスク、Nginx・Next.js・Astroでの設定例、確認方法を解説します。

  4. プログラミング

    クラウドの通信費(Egress)入門|データ転送量課金の仕組みと転送コストを抑える設計

    クラウドの「受信無料・送信有料」の原則、AZ間・リージョン間・インターネット向けの単価差、NATゲートウェイ処理料の罠、CDNで転送量を減らす方法、バックアップやログ転送の見落とし、請求書で転送料を特定する手順を解説。想定外の請求を防げます。

  5. プログラミング

    秘密情報をGitに入れない仕組み|.gitignore・git-secrets・履歴から漏れた鍵の削除

    APIキーや.envをGitにコミットしてしまう典型経路と、.gitignore・.env.exampleの運用、pre-commitでのgitleaks検知、GitHub secret scanningの活用、漏れた鍵の無効化と履歴書き換え(git filter-repo)の手順を解説。仕組みで再発を防げます。

  6. プログラミング

    開発・ステージング・本番環境の分離設計|環境差分をなくす構成とアクセス制御

    開発・ステージング・本番それぞれの目的と、構成をコードで揃える方法、環境別の設定注入、本番データを使わないテストデータ戦略、ステージングの保護(Basic認証・IP制限・noindex)、コストを抑える運用までを解説。環境差分による本番障害を防げます。

  7. プログラミング

    ngrok・Cloudflare Tunnelでローカルを公開|Webhook開発とデモ環境の作り方

    NAT内のローカル環境にStripeやLINEのWebhookを届けるトンネリングの仕組みを解説。ngrok・Cloudflare Tunnel・localtunnelの比較、固定ドメインと認証、リクエスト検査、公開時のセキュリティ、自宅サーバー公開への応用までわかります。

  8. プログラミング

    ローカル開発環境のHTTPS化|mkcert・hostsファイル・自己署名証明書の正しい使い方

    ローカル開発をHTTPS前提にすべき理由(Secure Cookie・Service Worker・OAuth)と、mkcertでローカルCAを作りhostsで独自ドメインを割り当ててVite・Next.js・Dockerで使う手順を解説。証明書警告を無視する癖の危険も理解できます。

  9. プログラミング

    localhost・0.0.0.0・127.0.0.1の違い|ポートとUnixソケットを理解して「つながらない」を解決

    localhost・127.0.0.1・0.0.0.0の意味の違い、Dockerで外から接続できない原因、host.docker.internal、ポート競合の調べ方、Unixソケットの利点と権限、1024未満ポートの制約を解説。「つながらない」を仕組みから解決できます。

Harmonic Society

「読んで終わり」にせず、自社の業務で試してみませんか?

AI・ローカルLLM・クラウドの導入を、要件整理からPoC・社内展開まで代表エンジニアが伴走します。オンライン対応・全国OK・売り込みなし。

無料・30分・オンラインOK|1営業日以内に返信します