【連載 第5回】ロール (Roles) の設計:Playbookを部品化して再利用する〜スパゲッティコードからの脱却〜

1つのファイルに全てを書くのは、もう卒業。「整理整頓」が自動化を加速させる。

こんにちは!「LINUX工房」管理人の「リナックス先生」です。
前回(第4回)は、Jinja2テンプレートを使って設定ファイルを動的に生成するテクニックを学びました。
これで、環境ごとに異なる設定ファイルをスマートに管理できるようになりましたね。

しかし、できることが増えるにつれて、あなたの site.yml(Playbook)はどんどん長くなっていませんか?

  • 「Apacheのインストールと設定」
  • 「MySQLの構築とユーザー作成」
  • 「OSの共通設定(ユーザー作成、NTP、SSH設定)」

これら全てを1つのファイルに書くと、あっという間に数百行を超えてしまいます。
どこに何が書いてあるか分からず、修正するのも一苦労。これをプログラミングの世界では「スパゲッティコード」と呼びます。

コウ君

先生、図星です…。
最初は数十行だったPlaybookが、今ではスクロールバーが豆粒みたいになるくらい長くなってます。
「Webサーバー用」と「DBサーバー用」でファイルを分けてるんですが、共通の設定(ユーザー作成とか)を両方にコピペしてて、修正漏れが起きそうで怖いです。

リナックス先生

それは限界のサインね、コウ君。
Ansibleには、Playbookを機能ごとの「部品」に分割して管理する「ロール (Roles)」という仕組みがあるの。
これを使えば、「Webサーバーの設定部品」や「共通設定部品」を作って、レゴブロックみたいに組み合わせるだけでサーバーが構築できるようになるわ。
大規模なインフラ構築には必須の知識よ!

本記事では、Ansibleのディレクトリ構成のデファクトスタンダードである「Roles」の概念と、実務で使いやすい設計・実装方法を徹底解説します。

🚀 【続・Ansible講座】本連載のカリキュラム


1. ロール (Roles) とは何か?

ロールとは、これまで1つのPlaybookファイルに書いていた「タスク」「変数」「ハンドラー」「ファイル」「テンプレート」などを、決まったルールに従ってディレクトリに分割・配置する仕組みのことです。

なぜロールが必要なのか?

例えば、「Webサーバー」を構築するには以下の要素が必要です。

  1. Apacheをインストールする (tasks)
  2. httpd.conf を配置する (templates)
  3. 設定変更時に再起動する (handlers)
  4. ポート番号などの定義 (vars)

これらをひとまとめにしてapache ロール」というパッケージ(部品)にします。
そうすれば、「WebサーバーA」を作る時も「WebサーバーB」を作る時も、単に「apache ロールを使う」と宣言するだけで済みます。

Rolesのメリット:

  • 可読性向上: ファイルが機能ごとに分かれるため、見通しが良くなる。
  • 再利用性: 汎用的なロール(例:Nginx, MySQL, Common)を作れば、他のプロジェクトでも使い回せる。
  • チーム開発: 「私はDB担当、あなたはWeb担当」といった分業がしやすくなる。

2. Rolesの標準ディレクトリ構成

Ansibleのロールには、「このディレクトリにはこのファイルを置く」という厳格なルールがあります。
逆に言えば、このルールに従うだけで、誰が見ても分かりやすい構成になります。

基本構造

プロジェクトルートの下に roles/ ディレクトリを作り、その中にロールごとのフォルダを作ります。

site.yml          # 全体を統括するPlaybook
roles/
  common/         # 共通設定用ロール
    tasks/
      main.yml    # タスク定義
    handlers/
      main.yml    # ハンドラー定義
    vars/
      main.yml    # 変数定義
  apache/         # Apache用ロール
    tasks/
      main.yml
    templates/
      httpd.conf.j2 # テンプレートファイル
    defaults/
      main.yml    # デフォルト変数

各ディレクトリ内の main.yml が、そのロールのエントリーポイント(入口)として自動的に読み込まれます。

ディレクトリ名 役割
tasks 実行する処理(タスク)を記述します。一番重要です。
handlers notify で呼び出されるハンドラーを記述します。
templates Jinja2テンプレートファイル(.j2)を置きます。
files copy モジュールで配布する静的なファイルを置きます。
vars そのロールで使用する変数を定義します(優先度高)。
defaults 変数のデフォルト値を定義します(優先度低)。上書き可能です。
meta ロールの依存関係(このロールの前に実行すべきロール)などを定義します。

3. 実践:既存のPlaybookをRoleに移行する

論より証拠。実際にロールを作ってみましょう。
これまで書いてきたApache構築のPlaybookを、httpd ロールとして切り出します。

3-1. 雛形の作成 (ansible-galaxy init)

手動でディレクトリを作っても良いですが、Ansibleには雛形作成コマンドが用意されています。

mkdir roles
cd roles
ansible-galaxy init httpd

これで roles/httpd/ 配下に、先ほど説明したディレクトリ群が一瞬で生成されます。
(使わないディレクトリは削除しても構いません)

3-2. タスクの移行 (tasks/main.yml)

元のPlaybookの tasks: セクションの中身を、roles/httpd/tasks/main.yml に移動します。
※重要: tasks: というキーワードは不要です。リストのハイフン - から書き始めます。

roles/httpd/tasks/main.yml

---
# tasks file for httpd
- name: Apacheをインストール
  ansible.builtin.dnf:
    name: httpd
    state: present

- name: 設定ファイルを配置
  ansible.builtin.template:
    src: httpd.conf.j2  # パス指定なしでOK
    dest: /etc/httpd/conf/httpd.conf
  notify: Restart Apache

- name: サービス起動
  ansible.builtin.service:
    name: httpd
    state: started
    enabled: true

3-3. ハンドラーの移行 (handlers/main.yml)

同様にハンドラーも移動します。

roles/httpd/handlers/main.yml

---
# handlers file for httpd
- name: Restart Apache
  ansible.builtin.service:
    name: httpd
    state: restarted

3-4. テンプレートの配置 (templates/)

httpd.conf.j2 ファイルを roles/httpd/templates/ ディレクトリの中に移動します。
ロール内では、template モジュールの src は自動的に templates/ ディレクトリを探しに行くため、パスの指定(roles/httpd/templates/...)は不要になります。


4. PlaybookからRoleを呼び出す

部品(ロール)ができたら、それを呼び出す「設計図(Playbook)」を書きます。
驚くほどシンプルになります。

site.yml

---
- name: Webサーバー構築
  hosts: webservers
  become: true

  roles:
    - common  # 共通設定ロール(例として記載)
    - httpd   # 先ほど作ったApacheロール

たったこれだけです!
「まず共通設定をやって、次にApacheを入れる」という意図が一目瞭然です。
実行コマンドはこれまでと同じです。

ansible-playbook -i inventory.ini site.yml

変数を渡しながらロールを呼ぶ

ロール内のデフォルト変数を上書きしたい場合は、以下のように記述します。

  roles:
    - role: httpd
      vars:
        http_port: 8080

5. 【プロのノウハウ】変数の置き場所「defaults」と「vars」

ロール内には変数を置く場所が2つあります(defaults/main.ymlvars/main.yml)。
この2つの違いを理解することが、汎用的なロールを作る鍵です。

defaults/main.yml (優先度:最低)

ここには「上書きされることを前提としたデフォルト値」を書きます。
例えば、Apacheのポート番号などです。

# roles/httpd/defaults/main.yml
http_port: 80

ここに書いておけば、ユーザーが何も指定しなければ80番で動き、group_vars やPlaybook側で指定すればそちらが優先されます。
基本的には変数はここに書くのがベストプラクティスです。

vars/main.yml (優先度:高)

ここには「ユーザーに変更させたくない、ロール内部の固定値」を書きます。
例えば、OSごとのパッケージ名の違いなど、システムの動作に関わる定数に近いものです。

# roles/httpd/vars/main.yml (CentOS用)
apache_service_name: httpd

ここに書くと優先順位が高いため、group_vars などで上書きしようとしても無視されることがあります。
「設定値」ではなく「内部ロジック用の変数」として使うのが正解です。


6. Ansible Galaxyで「車輪の再発明」を防ぐ

「Nginxをインストールするロール」や「MySQLを構築するロール」など、世界中の誰かが既に素晴らしいロールを作っています。
それらを共有・ダウンロードできる公式プラットフォームが「Ansible Galaxy」です。

公開ロールの検索と利用

例えば、世界で最も有名なAnsibleコントリビューターの一人、Jeff Geerling氏(geerlingguy)のApacheロールを使いたい場合。

# ロールの検索
ansible-galaxy search apache

# ロールのインストール
ansible-galaxy install geerlingguy.apache

Playbookでの指定:

  roles:
    - geerlingguy.apache

もちろん、セキュリティ要件などで外部コードが使えない場合もありますが、ディレクトリ構成やタスクの書き方の参考にするだけでも非常に勉強になります。
「一から自分で書く前に、Galaxyで似たロールがないか探してみる」のは、エンジニアの賢い時間の使い方です。


まとめ:部品化こそが自動化の到達点

お疲れ様でした!
第5回では、Playbookを整理整頓し、再利用可能な「ロール」に昇華させる方法を学びました。

今回の要点まとめ:

  • Roles を使って、巨大なPlaybookを機能ごとの部品に分割する。
  • ansible-galaxy init で標準ディレクトリ構成を作成する。
  • タスク、ハンドラー、テンプレートはそれぞれの専用ディレクトリに配置する。
  • defaults/main.yml にデフォルト変数を定義し、柔軟な上書きを可能にする。
  • vars/main.yml は内部定数として使う。
  • Ansible Galaxy を活用して、他人の知恵を借りる。
コウ君

ロールを使ったら、あんなにゴチャゴチャしていたPlaybookがたった数行になりました!
ディレクトリの中を見れば何をしてるかすぐに分かるし、これなら他のメンバーにも引き継ぎできそうです。
「common」ロールを作って全サーバーに適用するの、やってみます!

さて、インフラ構築には「パスワード」や「APIキー」などの機密情報が付きものです。
これらをPlaybookや変数ファイルに平文(そのまま)で書くのは、セキュリティ上非常に危険です。
次回は、こうした機密情報を安全に暗号化して管理する仕組み「Ansible Vault」について学びます。

次回、【第6回】Ansible Vault:パスワードなどの機密情報を暗号化する でお会いしましょう!

▼ ロール開発の練習環境を作るなら ▼

自分専用の実験場
「おすすめVPS」

VPSランキングを見る

Ansibleスキルを活かす
「ITエンジニア転職」

転職エージェントを見る

コメント