コンテンツにスキップ

Playbook@Ansible

はじめに

本サイトにつきまして、以下をご認識のほど宜しくお願いいたします。


01. playbookファイル

playbookファイルとは

サーバーのセットアップ処理を設定する。

処理をrolesディレクトリに切り分けても良い。

切り分ける場合、rolesディレクトリを作業ディレクトリとし、相対パスでファイルを指定することになる。

*実装例*

appサーバー、dbサーバー、webサーバーをセットアップする。

各コンポーネントはrolesディレクトリに切り分けている。

# roleファイル
# appサーバー
- hosts: app
  become: yes
  force_handlers: "true"
  # rolesディレクトリ以下に処理を切り分ける。上から順にrolesを実行する。
  roles:
    - shared
    - app

# dbサーバー
- hosts: db
  become: yes
  force_handlers: "true"
  roles:
    - shared
    - db

# webサーバー
- hosts: web
  become: yes
  force_handlers: "true"
  roles:
    - shared
    - web
repository/
├── playbook.yml
├── roles/
│   ├── shared/
│   │   └── tasks/
│   │       └── main.yml
│   │
│   ├── app/
│   │   └── tasks/
│   │       └── main.yml
│   │
│   ├── db/
│   │   └── tasks/
│   │       └── main.yml
│   │
│   └── web/
│       └── tasks/
│           └── main.yml


01-02. playbookファイルの切り分け

rolesディレクトリ

▼ rolesディレクトリとは

特定の機能に関するタスクが設定されたファイルを配置する。

playbook.ymlファイルを切り分けるために使用する。

▼ handlersディレクトリ

taskファイルの後続処理が設定されたhandlerファイルを配置する。

taskファイルのnotifyオプションで指定できる。

# handlerファイル
- name: Restart php-fpm
  service:
    name: php-fpm
    state: restarted
# taskファイル
- name: Upload www.conf
  ansible.builtin.template:
    src: php-fpm/www.conf.j2
    dest: /etc/php-fpm.d/www.conf
  notify:
    # handlerの名前を指定する。
    - restart_php-fpm

▼ taskディレクトリ

playbookファイルから切り分けたセットアップ処理が設定されたtaskファイルを配置する。

*実装例*

PHP製のアプリケーションが稼働するappサーバーをセットアップする。

# taskファイル
- name: Install software-properties-common
  ansible.builtin.apt:
    name: software-properties-common
    state: present

- name: Install packages
  ansible.builtin.apt:
  pkg:
    - php
    - php-fpm
    - php-pdo
  state: present
  notify:
    - restart_php-fpm

- name: Upload php.ini
  ansible.builtin.template:
    src: php.ini.j2
    dest: /etc/php.ini
  notify:
    - restart_php-fpm

- name: Upload www.conf
  ansible.builtin.template:
    src: php-fpm/www.conf.j2
    dest: /etc/php-fpm.d/www.conf
  notify:
    - restart_php-fpm

- name: Setup composer
  ansible.builtin.shell: |

    # Composerのセットアップ処理

    ...

▼ templateディレクトリ

アップロードファイルの鋳型となるj2ファイルを配置する。

鋳型に変数を出力できる。

*実装例*

php.iniファイルの鋳型として、php.ini.j2ファイルを配置する。

; Start a new pool named 'www'.
; the variable $pool can we used in any directive and will be replaced by the
; pool name ('www' here)
[www]

...


group_varsディレクトリ

▼ group_varsディレクトリとは

複数の管理対象ノードで使用する変数に関するファイルやディレクトリを配置する。

inventoriesディレクトリと同じ階層に配置し、加えてinventoryファイルで設定したグループ名やホスト名と同じ名前にする必要がある。

自動的に読み込まれ、playbookファイルやinventoryファイルで出力できる。

▼ group_varファイル

複数の管理対象ノードで使用する変数を設定する。

# group_varファイル
env: prd
domain: example.com
ip_addresses:
  - 192.168.0.1
  - 192.168.0.2
  - 192.168.0.3
ports:
  - 22/tcp
  - 80/tcp
  - 443/tcp

ポート番号のリストをplaybookファイルで出力する

---
- name: Add port
  firewalld:
    port: "{{ item }}"
    permanent: yes
    state: enabled
    zone: public
  with_items:
    - "{{ ports }}"

- name: Restart firewalld
  systemd:
    name: firewalld
    state: reloaded


host_varsディレクトリ

▼ host_varsディレクトリとは

特定の管理対象ノードで使用する変数に関するファイルを配置する。

▼ host_varファイル

特定の管理対象ノードで使用する変数を設定する。


inventoriesディレクトリ

▼ inventoriesディレクトリとは

管理対象ノードの情報を設定する。

Ansibleの実行時に、-iオプションでディレクトリを指定する。

$ ansible-playbook <playbookファイル> -i <inventoriesディレクトリ>

▼ inventoryファイル

管理対象ノードを設定する。

複数の拡張子 (ini形式、yml形式、json形式) で定義でき、ansible-inventoryコマンドでini形式から他の形式に変換できる。

ただし、ini形式の場合は拡張子をつけない方が良い。実行環境 (本番/ステージング) 別にファイルを切り分けると良い。

また、サーバーを冗長化している場合は、これも別々に定義しておく。

プロビジョニングの実行対象はロードバランサーから一時的に切り離すようにすることにより、プロビジョニングに伴ってインシデントが起こっても、ユーザーへの影響を防げる。

*実装例*

もしyml形式の場合は以下の通りとなる。

# inventoryファイル
# テスト環境
- all:
    hosts:
      app:
        # 管理対象ノードのIPアドレス
        ansible_host: 127.0.0.1
        # 管理対象ノードにログインするためのユーザー名
        ansible_user: vagrant
        # 管理対象ノードにログインするためのパスワード
        ansible_password: vagrant
      web:
        ansible_host: 127.0.0.1
        ansible_user: vagrant
        ansible_password: vagrant
      db:
        ansible_host: 127.0.0.1
        ansible_user: vagrant
        ansible_password: vagrant
# inventoryファイル
# 本番環境
- all:
    children:
      # 冗長化サーバーa
      server_a:
        hosts:
          # appサーバー
          app:
            # 管理対象ノードのIPアドレス
            ansible_host: 192.168.100.101
            # 管理対象ノードにログインするためのユーザー名
            ansible_user: ubuntu
            # 管理対象ノードにログインするためのパスワード
            ansible_password: ubuntu
            # 管理対象ノードへのSSH公開鍵認証に使用する秘密鍵
            ansible_ssh_private_key_file: /etc/ansible/ssh_keys/prd-foo.pem
          # webサーバー
          web:
            ansible_host: 192.168.100.10
            ansible_user: ubuntu
            ansible_password: ubuntu
            ansible_ssh_private_key_file: /etc/ansible/ssh_keys/prd-foo.pem
      # 冗長化サーバーc
      server_c:
        hosts:
          # appサーバー
          app:
            ansible_host: 192.168.100.102
            ansible_user: ubuntu
            ansible_password: ubuntu
            ansible_ssh_private_key_file: /etc/ansible/ssh_keys/prd-foo.pem
          # webサーバー
          web:
            ansible_host: 192.168.100.11
            ansible_user: ubuntu
            ansible_password: ubuntu
            ansible_ssh_private_key_file: /etc/ansible/ssh_keys/prd-foo.pem

*実装例*

もしini形式の場合は以下の通りとなる。

# inventoryファイル
# テスト環境

# -------------------
# 冗長化サーバーa
# -------------------

# appサーバー
[server_a.hosts.app]
# 管理対象ノードのIPアドレス
ansible_host=192.168.100.101
# 管理対象ノードにログインするためのユーザー名
ansible_user=ubuntu
# 管理対象ノードにログインするためのパスワード
ansible_password=ubuntu
# 管理対象ノードへのSSH公開鍵認証に使用する秘密鍵
ansible_ssh_private_key_file=/etc/ansible/ssh_keys/prd-foo.pem

# webサーバー
[server_a.hosts.web]
ansible_host=192.168.100.10
ansible_user=ubuntu
ansible_password=ubuntu
ansible_ssh_private_key_file=/etc/ansible/ssh_keys/prd-foo.pem

# -------------------
# 冗長化サーバーc
# -------------------

# appサーバー
[server_c.hosts.app]
ansible_host=192.168.100.102
ansible_user=ubuntu
ansible_password=ubuntu
ansible_ssh_private_key_file=/etc/ansible/ssh_keys/prd-foo.pem

# webサーバー
[server_c.hosts.web]
ansible_host=192.168.100.11
ansible_user=ubuntu
ansible_password=ubuntu
ansible_ssh_private_key_file=/etc/ansible/ssh_keys/prd-foo.pem
# inventoryファイル
# 本番環境

# -------------------
# 冗長化サーバーa
# -------------------

# appサーバー
[server_a.hosts.app]
ansible_host=192.168.100.101
ansible_user=ubuntu
ansible_password=ubuntu
ansible_ssh_private_key_file=/etc/ansible/ssh_keys/prd-foo.pem

# webサーバー
[server_a.hosts.web]
ansible_host=192.168.100.10
ansible_user=ubuntu
ansible_password=ubuntu
ansible_ssh_private_key_file=/etc/ansible/ssh_keys/prd-foo.pem

# -------------------
# 冗長化サーバーc
# -------------------

# appサーバー
[server_c.hosts.app]
ansible_host=192.168.100.102
ansible_user=ubuntu
ansible_password=ubuntu
ansible_ssh_private_key_file=/etc/ansible/ssh_keys/prd-foo.pem

# webサーバー
[server_c.hosts.web]
ansible_host=192.168.100.11
ansible_user=ubuntu
ansible_password=ubuntu
ansible_ssh_private_key_file=/etc/ansible/ssh_keys/prd-foo.pem


02. /roles/handlersセクション

handlersセクションとは

taskセクションの後に実行するセットアップ処理を設定する。


02-02. /roles/targetsセクション

targetsセクションとは

プレイの実行先のノードを設定する。

必須である。


name

▼ nameとは

プレイの名前を設定する。

- name: Setup nginx


hosts

▼ hostsとは

プレイの実行先のノードを設定する。

- hosts: all


become

▼ becomeとは

プレイをroot権限で実行するか否かを設定する。

root以外であれば、become_userキーを設定する。

- become: yes
  become_user: foo-user


gather_facts

▼ gather_factsとは

ファクト変数を収集するか否かを設定する。

- gather_facts: no

02-03. /roles/tasksセクション

tasksセクションとは

管理対象ノードで実行するセットアップ処理を手続き的に設定する。

必須である。


ansible.builtin.apt

▼ ansible.builtin.aptとは

管理対象ノードで、パッケージをaptリポジトリからインストールする。

任意のバージョンのパッケージをインストールする場合は、nameキーにそれを指定し、stateキーの値はpresentとする。

*実装例*

# nginxをインストールします。
- name: Install Nginx
  ansible.builtin.apt:
    name: nginx=1.0.0
    state: present


ansible.builtin.dnf

▼ ansible.builtin.dnfとは

管理対象ノードで、パッケージをdnfリポジトリからインストールする。

*実装例*

# cloudwatchエージェントをインストールする。
- name: install amazon-cloudwatch-agent
  ansible.builtin.dnf:
    name: amazon-cloudwatch-agent
    state: present

# カスタムメトリクスを収集するために、collectdをインストールする。
- name: install collectd
  ansible.builtin.dnf:
    name: collectd
    state: present

# 設定ファイルを配置する。
- name: copy amazon-cloudwatch-agent.json
  ansible.builtin.copy:
    src: amazon-cloudwatch-agent.json
    dest: /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json
    owner: root
    group: root
    mode: 0644

# cloudwatchエージェントを起動する。
- name: fetch-config config.json
  ansible.builtin.shell: |
    /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl \
      -a fetch-config \
      -m ec2 \
      -c file:/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json \
      -s

# cloudwatchエージェントをsystemdで管理する。
- name: enable cloudwatch-agent
  ansible.builtin.systemd:
    name: amazon-cloudwatch-agent
    enabled: yes
    daemon_reload: yes


ansible.builtin.lineinfile

▼ ansible.builtin.lineinfileとは

管理対象ノードにあるファイルを行単位で編集する。

*実装例*

SELinuxを無効化する。

*実装例*

# SELinuxを無効化します。
- name: Disable SELinux
  ansible.builtin.lineinfile:
    path: /etc/selinux/config
    regexp: "^SELINUX="
    line: "SELINUX=disabled"

*実装例*

# unlimitの設定を追加します
- name: Add ulimit setting
  lineinfile:
    path: /etc/systemd/system.conf.d/50-limits.conf
    regexp: "^DefaultLimitNOFILE=.*$"
    line: "DefaultLimitNOFILE=65536:65536"

*実装例*

# rsyslog_conf_fileにstatを格納する
- name: Check if /etc/rsyslog.conf exists
  ansible.builtin.stat:
    path: /etc/rsyslog.conf
  register: rsyslog_conf_file

- name: Create rsyslog.conf
  ansible.builtin.lineinfile:
    line: "$FileCreateMode 0640"
    regexp: "^$FileCreateMode"
    path: /etc/rsyslog.conf
  # もしrsyslog_conf_file内にデータがあれば、実行する
  when: rsyslog_conf_file.stat.exists


ansible.builtin.copy

▼ ansible.builtin.copyとは

管理対象ノードのディレクトリにファイルをコピーする。

*実装例*

# 設定ファイルを配置します。
- name: Copy foo.json
  ansible.builtin.copy:
    src: foo.json
    dest: /etc/foo.json
    owner: root
    group: root
    mode: 0644


ansible.builtin.file

▼ ansible.builtin.fileとは

管理対象ノードでファイルを操作する。

*実装例*

管理対象ノードでchownコマンドを実行することにより、ファイルの所有権を設定する。

- name: Update foo-binary permission
  ansible.builtin.file:
    path: /usr/local/bin/foo-binary
    owner: root
    group: root


ansible.builtin.get_url

▼ ansible.builtin.get_urlとは

管理対象ノードでcurlコマンドを実行する。

- name: Download tool
  ansible.builtin.get_url:
    url: https://github.com/hiroki-hasegawa/foo-tool.tar.gz
    dest: .


ansible.builtin.service

▼ ansible.builtin.serviceとは

管理対象ノードでserviceコマンドの実行を設定する。

*実装例*

# serviceコマンドを使用して、nginxを起動します。
- name: Start nginx service
  ansible.builtin.service:
    name: Start nginx
    state: started
    enabled: "yes"


ansible.builtin.shell

▼ ansible.builtin.shellとは

管理対象ノードでシェルを実行する。複数行に渡る場合は、『|』を使用する。

*実装例*

- name: Echo foo
  ansible.builtin.shell: |
    echo foo

*実装例*

- name: fetch-config amazon-cloudwatch-agent.json
  ansible.builtin.shell: |
    /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl \
      -a fetch-config \
      -m ec2 \
      -c file:/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json \
      -s


ansible.builtin.systemd

▼ ansible.builtin.systemdとは

管理対象ノードでsystemctlコマンドの実行を設定する。

*実装例*

# systemdでnginxのプロセスを管理します。
- name: Start nginx systemd
  ansible.builtin.systemd:
    name: Start nginx
    state: started
    enabled: yes
    daemon_reload: yes

*実装例*

# systemdでcloudwatchエージェントのプロセスを管理します。
- name: Start cloudwatch-agent systemd
  ansible.builtin.systemd:
    name: amazon-cloudwatch-agent
    state: started
    enabled: yes
    daemon_reload: yes

▼ state

ユニットの最終的な状態を設定する。

設定値 説明
reloaded 最終的な状態としてdeamon_reloadするように、ユニットを再読み込みする。
restarted 最終的な状態として再起動するように、ユニットを再起動する。
started 最終的な状態として停止しているように、ユニットを起動する。
stopped 最終的な状態として停止しているさうに、ユニットを停止する。


ansible.builtin.template

▼ ansible.builtin.templateとは

テンプレート (.j2ファイル) から作成したファイルを管理対象ノードのディレクトリに配置する。

*実装例*

- name: Upload foo.conf
  ansible.builtin.template:
    src: foo.conf.j2
    dest: /etc/foo/foo.conf


ansible.builtin.unarchive

▼ ansible.builtin.unarchiveとは

コントロールノードまたは管理対象ノードでtarコマンドを実行することにより、圧縮ファイルを解凍する。

*実装例*

- name: Unarchive file
  ansible.builtin.unarchive:
    src: /tmp/foo-tool.tar.gz
    dest: /usr/local/bin
    remote_src: yes # 管理対象ノード上の圧縮ファイルを指定する場合はyesとする。


ansible.builtin.user

▼ ansible.builtin.userとは

シェルのユーザーを操作する。

*実装例*

ユーザーを作成する。

無効なシェルを設定し、ログインできないようにしておく。

- name: add user
  ansible.builtin.user:
    name: foo
    shell: /bin/false


ansible.builtin.yum

▼ ansible.builtin.yumとは

管理対象ノードで、パッケージをyumリポジトリからインストールする。

任意のバージョンのパッケージをインストールする場合は、nameキーにそれを指定し、stateキーの値はpresentとする。

*実装例*

# nginxをインストールします。
- name: Install Nginx
  ansible.builtin.yum:
    # バージョンを指定する
    name: nginx=1.0.0
    state: present
# epelリポジトリをインストールします。
- name: Install epel-release
  ansible.builtin.yum:
    name: https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm
    state: present


ansible_env

▼ ansible_envとは

管理対象ノードに設定された環境変数を出力する。

gather_factsオプションを有効化する必要がある。

*実装例*

管理対象ノードの環境変数のFOOを出力する。

gather_factsオプションを有効化しておく。

- gather_facts: yes
- vars:
    FOO: ansible_env.FOO

environment

▼ environmentとは

task内で出力できる環境変数を設定する。

*実装例*

- name: Echo foo
  ansible.builtin.shell: |
    echo foo
    echo "${FOO}"
  environment:
    FOO: FOO


02-04. /roles/varsセクション

varsセクションとは

プレイで使用する設定値を変数として設定する。

設定した変数は、ansible.builtin.templateオプションを使用してj2ファイルに出力できる。

*実装例*

- name: Upload foo.conf
  ansible.builtin.template:
    src: foo.conf.j2
    dest: /etc/foo/foo.conf
  vars:
    foo: FOO
    bar: BAR
# foo.conf.j2ファイル
{{foo}}


02-05. プラグイン

lookup

▼ env

コントロールノードに設定された環境変数を出力する。

*実装例*

コントロールノードの環境変数のFOOを出力する。

- name: Upload foo.conf
  ansible.builtin.template:
    src: foo.conf.j2
    dest: /etc/foo/foo.conf
  vars:
    foo: 'lookup("env", "FOO")'


03. AWS

amazon.aws.ec2_ami

AWS EC2を作成する。

これはTerraformでも代替できる。

- name: Basic AMI Creation
  amazon.aws.ec2_ami:
    instance_id: i-xxxxxx
    wait: true
    name: newtest
    architecture: x86_64
    virtualization_type: hvm
    root_device_name: /dev/xvda
    device_mapping:
      - device_name: /dev/sda1
        size: XXX
        delete_on_termination: true
        volume_type: gp2
      - device_name: /dev/sdb
        size: YYY
        delete_on_termination: false
        volume_type: gp2
    tags:
      Name: newtest
      Service: TestService