AnsibleのプレイブックをRolesで構成する

/

導入

プロビジョニングツール
以前にVagrantでAnsibleを実行しましたがsite.ymlから単純にプレイブックをインクルードを行っただけだったので、今回実行したい処理をモジュール化してより独立性を高めるためにRolesの機能を使ったファイルを構成でプロビジョニングを行っていきます。

Ansibleで行うVagrantの開発環境構築/koltatt

実行環境

ホストOS ubuntu16.04LTS
ゲストOS centOS7.2
Vagrant 1.8.1
VirtualBox 5.0.24
Ansible 2.1.2.0

ファイル構成

前回は以下の様にsite.ymlから直接プレイブックをインクルードする形にしていましたが、

├─ vagrantfile
├─ hosts
├─ site.yml
└─ tasks
      └─ nginx.yml
- tasks:
    - include: tasks/nginx.yml

今回のRolesを使った構成はこのようになります。

├─ vagrantfile
├─ hosts
├─ site.yml
└─ roles
    └─ nginx
        ├─ handlers
        │   └─main.yml
        ├─ tasks
        │   └─main.yml
        └─ templates
             ├─ default.conf.j2
             └─ nginx.conf.j2
- hosts: webservers
  become: yes
  become_user: root
  roles:
    - nginx

Roles

RolesはプレイブックをタスクやテンプレートなどAnsibleの構造に従って配置するのではなく、サーバーに実行したい処理毎に管理します。Ansibleに実際に行わせたい役割を単位にモジュール化されるので、プレイブックのプロジェクト間の移動や他人との共有が行いやすくなります。
Rolesではvars,tasks,handlersなどのあらかじめ決められたファイル構造を自動的に読み込んでくれるため、規約に従ったファイルの配置を行えばRolesの指定を行うだけで目的のプロビジョニングを実行が可能です。

今回はVagrant上でNginxのインストールと設定ファイルの設置、サービスの実行までを行うRolesを作成します。

参照
http://docs.ansible.com/ansible/playbooks_roles.html#roles

tasks

roles/nginxを実行するためにまずsite.ymlのあるディレクトリでroles/nginx/tasks/main.ymlを作成します。
tasksに限らずRolesモジュールでは各Roles以下にあるディレクトリ内にmain.ymlを設置するればデフォルトのプレイブックとして自動的に実行されます。

- name: add epel
  yum: name=epel-release state=present

- name: install nginx
  yum: name=nginx state=latest

- name: Copy nginx configuration
  template: >
    src=nginx.conf.j2
    dest=/etc/nginx/nginx.conf
    owner=root
    group=root
    mode=0644
  notify: restart nginx

- name: Copy nginx default configuration
  template: >
    src=tmp.conf
    dest=/etc/nginx/conf.d/default.conf
    owner=root
    group=root
    mode=0644
  notify: restart nginx

- name: start nginx service
  service: name=nginx state=started enabled=yes

handlers

ハンドラーはtasks内のnodifyによって呼び出されるコールバック関数で、タスクによってなんらかの変更があった場合のみ実行されます。

- name: restart nginx
  command: systemctl restart nginx.service

今回のケースで言えば例えばtasksのプレイブック内の以下の箇所でnofityによって上記のハンドラーを呼び出しています。
プロビジョニングが最初に実行された時には設定ファイルが新たに作成されるためハンドラーが実行されていますが、2回目以降は設定ファイルに変更が加えられない限りハンドラーは実行されません。

- name: Copy nginx default configuration
  template: >
    src=default.conf.j2
    dest=/etc/nginx/conf.d/default.conf
    owner=root
    group=root
    mode=0644
  notify: restart nginx

プロビジョニングの実行。

# 1回目
...
TASK [nginx : Copy nginx default configuration] ********************************
# 変更されている
changed: [localhost]
...
#ハンドラーの実行
RUNNING HANDLER [nginx : restart nginx] ****************************************

changed: [localhost]
# 2回目以降
TASK [nginx : Copy nginx default configuration] ********************************
# 変更されていない
ok: [localhost]

参照
http://docs.ansible.com/ansible/playbooks_intro.html

templates

nginxの設定ファイルを設置にはテンプレートモジュールを使います。
テンプレートモジュールはあらかじめ用意しておいたテキストファイルをサーバー側の指定したディレクトリに設置してくれます。

server {
    listen       80;
    server_name  localhost;
    charset      utf-8;

    location / {
        root  /var/www;
        index index.html;
    }
}
user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
    use epoll;
}

http {
    server_tokens off;
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  ltsv  'domain:$host\t'
                      'host:$remote_addr\t'
                      'user:$remote_user\t'
                      'time:$time_local\t'
                      'method:$request_method\t'
                      'path:$request_uri\t'
                      'protocol:$server_protocol\t'
                      'status:$status\t'
                      'size:$body_bytes_sent\t'
                      'referer:$http_referer\t'
                      'agent:$http_user_agent\t'
                      'response_time:$request_time\t'
                      'cookie:$http_cookie\t'
                      'set_cookie:$sent_http_set_cookie\t'
                      'upstream_addr:$upstream_addr\t'
                      'upstream_cache_status:$upstream_cache_status\t'
                      'upstream_response_time:$upstream_response_time';

    access_log  /var/log/nginx/access.log  ltsv;

    sendfile        on;
    tcp_nopush     on;

    keepalive_timeout  30;
    keepalive_requests 50;

    gzip  on;

    include /etc/nginx/conf.d/*.conf;
}

テンプレートファイルの末尾にある.j2という拡張子はjinja2というAnsibleの利用しているPython用のテンプレートエンジンのものです。
.j2拡張子はテンプレート内で変数を使うのであれば必要になりますが、今回の用に変数を利用しないのであれば/nginx/templates/default.confという様にテキストファイルのままでも実行する事が出来ます。

参照
http://docs.ansible.com/ansible/template_module.html

実行

roles/nginx以下の各ディレクトリに必要なプレイブックとファイルを設定したあとは、site.ymlからnginxをRolesとして呼びだせば、プロビジョニングが実行されます。

- hosts: webservers
  become: yes
  become_user: root
  roles:
    - nginx
$ vagrant provision

あとがき

Rolesを使うとAnsibleの構成が実際のサーバー設定を考える時と似た形で抽象化されるので管理がしやすくなります。またパッケージ単位ではなくwebserverといった形でサーバーの役割毎にRolesを設定する事も可能なので、うまく使えば複数のサーバーの設定の管理も効率化する事が可能です。

参照

http://docs.ansible.com/ansible/playbooks_roles.html