6
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

LeveragesAdvent Calendar 2017

Day 11

Ansible 俺流 Best Practices

Last updated at Posted at 2017-12-12

はじめに

この記事は、Leveragesアドベントカレンダー11日目の記事になります。

10日目に続いてAnsible関連の記事をあげていきます。
今回は導入の過程でたどり着いたベストプラクティスを紹介します
公式ベストプラクティスでは少し都合が悪かったので公式を参考に少しカスタマイズしたものになります。
(自分流なので完全なベストプラクティスでない場合もあります。)

ベストプラクティスにたどり着く過程で下記の記事を参考にさせて頂きました。
Ansible ( 俺の中で ) 最強の Best Practices
Ansible オレオレベストプラクティス

公式では足りなかった理由

  • 共有で使いたいRoleがいくつか存在した
  • とはいえ社内秘情報もあるのでAnsible Galaxyに載せるのはちょっと…
  • プロジェクトが大量に存在するためそれぞれにproduction,stagingなどの設定が存在する
  • とはいえ全プロジェクトでproduction,stagingなどの環境で同じ設定のものも存在する

出来上がったベストプラクティス

playbook/
   ├── ansible.cfg                       # ansibleの設定ファイル
   ├── group_vars/
   │   ├── development
   │   │   └── all.yml                   # 全プロジェクトdevelopment環境用変数
   │   ├── production
   │   │   └── all.yml                   # 全プロジェクトproduction環境用変数
   │   ├── staging
   │   │   └── all.yml                   # 全プロジェクトstaging環境用変数
   │   └── all.yml                       # 全プロジェクト全環境用変数
   ├── host_vars/
   │   ├── host1.yml                     # host1用環境変数
   │   │         ︙
   │   └── host2.yml                     # host2用環境変数
   ├── inventories/
   │   ├── service-A
   │   │   ├── group_vars
   │   │   │   ├── development
   │   │   │   │   └── all.yml           # service-Aのdevelopment環境用変数
   │   │   │   ├── production
   │   │   │   │   └── all.yml           # service-Aのproduction環境用変数
   │   │   │   ├── staging
   │   │   │   │   └── all.yml           # service-Aのstaging環境用変数
   │   │   │   └── all.yml               # service-Aの全環境用変数
   │   │   ├── development.yml           # service-Aのdevelopment環境用インベントリファイル
   │   │   ├── production.yml            # service-Aのproduction環境用インベントリファイル
   │   │   └── staging.yml               # service-Aのstaging環境用インベントリファイル
   │   ├── service-B
   │   │   ├── group_vars
   │   │   │   ├── development
   │   │   │   │   └── all.yml           # service-Bのdevelopment環境用変数
   │   │   │   ├── production
   │   │   │   │   └── all.yml           # service-Bのproduction環境用変数
   │   │   │   ├── staging
   │   │   │   │   └── all.yml           # service-Bのstaging環境用変数
   │   │   │   └── all.yml               # service-Bの全環境用変数
   │   │   ├── production.yml            # service-Bのproduction環境用インベントリファイル
   │   │   ├── local.yml                 # service-Bのlocal環境用インベントリファイル
   │   │   ├── development.yml           # service-Bのdevelopment環境用インベントリファイル
   │   │   └── staging.yml               # service-Bのstaging環境用インベントリファイル
   │   ︙
   │   └── ...
   ├── roles
   │   ├── common
   │   │   ├── defaults
   │   │   │   └── main.yml              # commonロール内で使うデフォルト変数
   │   │   ├── files                     # commonロール内で使用するリソースファイル
   │   │   ├── handlers                  # commonロール内のタスクに依存するハンドラ
   │   │   ├── meta                      # commonロールに関連する依存関係
   │   │   ├── tasks
   │   │   │   └── main.yml              # commonロールで実行するタスク基軸
   │   │   ├── templates                 # commonロール内で呼び出されるテンプレート
   │   │   └── vars                      # commonロール内に関連する変数
   │   ├── nginx
   │   │   ├── defaults
   │   │   │   └── main.yml              # nginxロール内で使うデフォルト変数
   │   │   ├── files                     # nginxロール内で使用するリソースファイル
   │   │   ├── handlers
   │   │   │   └── main.yml              # nginxロール内のタスクに依存するハンドラ
   │   │   ├── meta                      # nginxロールに関連する依存関係
   │   │   ├── tasks
   │   │   │   ├── configure.yml         # nginxロールで実行する設定関連タスク
   │   │   │   ├── install.yml           # nginxロールで実行するインストール関連タスク
   │   │   │   └── main.yml              # nginxロールで実行するタスク基軸
   │   │   ├── templates                 # nginxロール内で呼び出されるテンプレート
   │   │   │   ├── location_root.conf.j2
   │   │   │   ├── nginx.conf.j2
   │   │   │   └── servers.conf.j2
   │   │   └── vars                      # nginxロール内に関連する変数
   │   ︙
   │   └── ...
   └── site.yml                          # 実行するPlaybook

構成と設定例

Playbook

構成

playbook/
   ├── ansible.cfg                       # ansibleの設定ファイル
   ︙
   └── site.yml 
  • ansible.cfg
    このプレイブック用のansibleの設定ファイルです。
  • site.yml
    対象ホストグループとロールの関連設定ファイル

設定例

ansibleのオプションを設定します。
オプションの項目と詳細はConfiguration file — Ansible Documentationを参考にします。

ansible.cfg
[defaults]
forks          = 10
transport      = ssh
retry_files_enabled = False

対象ホストグループとそのグループに対して実行するロールを指定します。

site.yml
---
- hosts: all
  become: yes
  roles:
    - common

- hosts: web
  become: yes
  roles:
    - php
    - nginx

実行するロール内で必要となる他のロールのhandlerは下記のように呼び出します。

site.yml
- hosts: db
  become: yes
  roles:
    - postgresql
  handlers:
    - include: roles/php/handlers/main.yml
    - include: roles/nginx/handlers/main.yml

group_vars

構成

各環境のディレクトリを作成し、その配下に環境変数格納用のymlを配置します。
ここに格納する環境変数はサービスに関係なく、例えば本番環境であれば全サービスの本番環境で必要な変数になります。

   ├── group_vars/
   │   ├── production
   │   │   └── all.yml                   # 全プロジェクトdevelopment環境用変数

設定例

ansibleを実行する際のsshのポートとユーザー名を指定します。

group_vars/production/all.yml
ansible_ssh_port: 22
ansible_ssh_user: root

Inventory

構成

inventories以下にサービス毎にディレクトリを作成します。

├── inventories/
   │   ├── service-A
   ︙  ︙
   │   ├── service-B

サービスのディレクトリ以下は環境毎にymlを作成し環境変数格納用のgroup_varsディレクトリを配置します。
group_varsディレクトリ下には各環境ごとのディレクトリを作成し、環境変数を格納するymlを作成します。
ここで格納する環境変数はサービスと環境ごとに変わる変数になります。

   │   ├── service-A
   │   │   ├── group_vars
   │   │   │   ├── development
   │   │   │   │   └── all.yml           # service-Aのdevelopment環境用変数
   │   │   │   ├── production
   │   │   │   │   └── all.yml           # service-Aのproduction環境用変数
   │   │   │   ├── staging
   │   │   │   │   └── all.yml           # service-Aのstaging環境用変数
   │   │   │   └── all.yml               # service-Aの全環境用変数
   │   │   ├── development.yml           # service-Aのdevelopment環境用インベントリファイル
   │   │   ├── production.yml            # service-Aのproduction環境用インベントリファイル
   │   │   └── staging.yml               # service-Aのstaging環境用インベントリファイル

設定

production.ymlの設定例

production.yml
[web]
10.0.1.1

[production:children]
web

development.ymlの設定例

development.yml
[web]
10.0.2.1

[db]
10.0.2.1

[production:children]
web
db

group_varsディレクトリ下のall.ymlの設定例
ここではnginxの設定の際に使用するサービスのルートディレクトリなどを設定しています。

inventories/service-A/group_vars/production/all.yml
projects:
  - location_root: /www/
    host_name: service-a.example.com
    location_names:
      - root

roles

構成

rolesディレクトリ以下に一般的に全サーバーで必要なcommonディレクトリとWebサーバーに必要なNginx関連の設定を行うnginxディレクトリを作成します。

   ├── roles
   │   ├── common
   │   │   ├── defaults
   │   │   │   └── main.yml              # commonロール内で使うデフォルト変数
   │   │   ├── files                     # commonロール内で使用するリソースファイル
   │   │   ├── handlers                  # commonロール内のタスクに依存するハンドラ
   │   │   ├── meta                      # commonロールに関連する依存関係
   │   │   ├── tasks
   │   │   │   └── main.yml              # commonロールで実行するタスク基軸
   │   │   ├── templates                 # commonロール内で呼び出されるテンプレート
   │   │   └── vars                      # commonロール内に関連する変数
   │   ├── nginx
   │   │   ├── defaults
   │   │   │   └── main.yml              # nginxロール内で使うデフォルト変数
   │   │   ├── files                     # nginxロール内で使用するリソースファイル
   │   │   ├── handlers
   │   │   │   └── main.yml              # nginxロール内のタスクに依存するハンドラ
   │   │   ├── meta                      # nginxロールに関連する依存関係
   │   │   ├── tasks
   │   │   │   ├── configure.yml         # nginxロールで実行する設定関連タスク
   │   │   │   ├── install.yml           # nginxロールで実行するインストール関連タスク
   │   │   │   └── main.yml              # nginxロールで実行するタスク基軸
   │   │   ├── templates                 # nginxロール内で呼び出されるテンプレート
   │   │   │   ├── location_root.conf.j2
   │   │   │   ├── nginx.conf.j2
   │   │   │   └── servers.conf.j2
   │   │   └── vars                      # nginxロール内に関連する変数
  • defaults
    ロール内で使うデフォルト変数設定ファイルを格納するディレクトリ
  • files
    ロール内で使用するリソースファイを格納するディレクトリ
    リスースファイルとはcopyモジュールなどで使われるファイル群
  • handlers
    ロール内のタスクに依存するハンドラ(ex. nginxの設定変更後のリスタートタスク)
  • meta
    ロールに関連する依存関係の設定ファイルを格納するディレクトリ
  • tasks
    ロールで実行するタスクを格納するディレクトリ
  • templates
    ロール内で呼び出されるテンプレート(ex. nginxの設定ファイル)
  • vars
    ロール内で使用する変数を格納するディレクトリ

設定例

commonロールではyumでのパッケージインストールなどを行います。

roles/common/tasks/main.yml
---
- name: Update yum
  yum:
    name: '*'
    state: latest
  tags: yum

- name: Install yum package
  yum:
    name: "{{ item.name }}"
    state: "{{ item.state }}"
  with_items: "{{ yum_install }}"
  tags: yum

- name: Setting timezone
  file:
    src: "{{ zoneinfo_path }}"
    dest: "/etc/localtime"
    state: link
    force: yes
  tags: timezone

ここのタスクで呼び出されているyum_installなどの変数はdefaultsディレクトリ下にて定義します。

roles/common/defaults/main.yml
yum_install:
  - {
      name: "epel-release",
      state: "latest"
    }
  - {
      name: "python-pip",
      state: "latest"
    }
  - {
      name: "zip",
      state: "latest"
    }
  - {
      name: "unzip",
      state: "latest"
    }

zoneinfo_path: "/usr/share/zoneinfo/Asia/Tokyo"

nginxロールではnginxのインストールとconfファイルの設定などを行います。
インストール関連のタスクをまとめたinstall.ymlと設定関連のタスクをまとめたconfigure.ymlにわけます。
main.ymlではinstall.ymlconfigure.ymlの読み込むのみにします。
これにより設定のみループ処理したりなどがしやすくなります。

roles/nginx/tasks/main.yml
---
- include: install.yml
- include: configure.yml
  with_items: "{{ projects }}"
  loop_control:
    loop_var: project
  when: projects is defined
roles/nginx/tasks/install.yml
---
- name: Install nginx
  yum:
    name: nginx
    state: latest
  tags: nginx

- name: Copy nginx configuration
  template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf
  notify: restart nginx
  tags: nginx
roles/nginx/tasks/configure.yml
- name: Make location root directory
  file:
    path: "{{ project.location_root }}"
    state: directory
    owner: "{{ deploy_user }}"
    group: "{{ deploy_user }}"
    mode: 0775
  tags: nginx

- name: Copy server configuration
  template:
    src: server.conf.j2
    dest: /etc/nginx/sites-available/{{ project.host_name }}/server.conf
  notify: restart nginx
  tags: nginx

- name: Copy location configuration
  template:
    src: "location_{{ item }}.conf.j2"
    dest: "/etc/nginx/sites-available/{{ project.host_name }}/locations/{{ item }}.conf"
  notify: restart nginx
  with_items: "{{ project.location_names }}"
  tags: nginx

- name: Setting php-fpm configuration
  lineinfile:
    dest: /etc/php-fpm.d/www.conf
    state: present
    backrefs: yes
    regexp: "{{ item.regexp }}"
    line: "{{ item.line }}"
  with_items: "{{ php_fpm_setting }}"
  notify: restart php-fpm
  tags: nginx

- name: Nginx is running and enabled
  service:
    name: nginx
    state: started
    enabled: yes
  tags: nginx

- name: php-fpm is running and enabled
  service:
    name: php-fpm
    state: started
    enabled: yes
  tags: nginx

ここで使用している変数もcommonの時と同様defaultsディレクトリに設定します。

roles/nginx/defaults/main.yml
php_fpm_setting:
  - {
      regexp: "^user = apache",
      line: "user = nginx"
    }
  - {
      regexp: "^group = apache",
      line: "group = nginx"
    }
  - {
      regexp: "^listen = 127.0.0.1:9000",
      line: "listen = /var/run/php-fpm.sock"
    }
  - {
      regexp: "^;listen.owner = nobody",
      line: "listen.owner = nginx"
    }
  - {
      regexp: "^;listen.group = nobody",
      line: "listen.group = nginx"
    }
  - {
      regexp: "^;listen.mode = 0660",
      line: "listen.mode = 0660"
    }

またprojects変数などはinventories/service-A/group_vars/production/all.ymlで設定しています。
このようにサービスに依存する変数などはinventories以下に記載することで環境やサービス毎に変更することが可能です。

configure.ymlで呼び出されているserver.conf.j2などはテンプレートファイルとよばれ、定義している変数を使用して設定内容を動的に変更できます。
ここではnginxserver.conf用のテンプレートを紹介します。

roles/nginx/templates/server.conf.j2
server {
  listen       80;
  listen       [::]:80;
  server_name  {{ project.host_name }};

  {% if project.use_elb == true %}
  # アクセスが http なら https としてリダイレクト
  if ($http_x_forwarded_proto != https) {
    return 301 https://$host$request_uri;
  }

  set $my_http "http";
  set $my_ssl "off";
  set $my_port "80";
  if ($http_x_forwarded_proto = "https") {
    set $my_http "https";
    set $my_ssl "on";
    set $my_port "443";
  }
  {% endif %}

  charset UTF-8;

  error_page   500 502 503 504  /50x.html;

  access_log /var/log/nginx/{{ project.host_name }}/access.log main;
  error_log /var/log/nginx/{{ project.host_name }}/error.log;

  include /etc/nginx/sites-enabled/{{ project.host_name }}/locations/*.conf;
}

まとめ

今回はAnsibleの導入過程でたどり着いたベストプラクティスを紹介しました。
このベストプラクティス自体はAnsibleの公式のベストプラクティスからは少し外れたものになっていますが、
多数のプロジェクトを抱えることの多い場合はある程度使いやすいものになっているのではないかと思います。

参考URL

公式ベストプラクティス
Ansible ( 俺の中で ) 最強の Best Practices
Ansible オレオレベストプラクティス

6
6
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?