日常の作業を Ansible で行う

この記事は [Wanoグループ Advent Calendar 2016](http://qiita.com/advent-calendar/2016/wano-group) の22日目の記事です。


構成管理ツールとして使われる [Ansible](https://www.ansible.com/) ですが、日常のちょっとした作業に活用しても便利です。
特定のパッケージをインストールする、ログを確認するなどの作業は、1回行うだけなら大したことありませんが、対象サーバの数が多くなると1台1台にログインして作業することの繰り返しになり大変です。
こういう作業を行うための環境をあらかじめ構築しておき、作業時には実行用の Ansible Playbook を1回書くだけですべてのサーバに適用できるようにしておくと作業の手間を軽減できます。


## サンプルで使用する構成

### 管理対象サーバ

##### OS
Ubuntu 14.04

##### Production x 2
- sample_prod_01
- sample_prod_02
- パスワード: prodpasswd

##### Staging x 2
- sample_stage_01
- sample_stage_02
- パスワード: stagepasswd

##### development x 2
- sample_dev_01
- sample_dev_02
- パスワード: devpasswd

##### ユーザ 
admin 

- sudo 権限あり
- パスワードは上記の通り
- 管理マシン側から公開鍵認証にてSSHログイン可能


## 構築手順

今回は作業用ディレクトリを ansible-work という名前にします。(名前はなんでもいいです)

```
$ mkdir ansible-work
$ cd ansible-work
```

#### デフォルト設定の追加

```ansible.cfg
[defaults]
hostfile=hosts
```


#### 管理対象サーバの設定

管理対象サーバを hosts ファイルに設定します。(/etc/hosts とは別物です。現在の作業ディレクトリである ansible-work 直下にこのファイルを作ってください。)

```ansible-work/hosts
[production]
sample_prod_01
sample_prod_02

[stage]
sample_stage_01
sample_stage_02

[development]
sample_dev_01
sample_dev_02
```

[production][stage][development]がグループ名で、各サーバをここでグループ分けしています。

#### sudo 時のパスワード入力を不要にする

今回の例では、環境ごとにパスワードが異なります。
ansible-playbook を -K オプション付きで実行して sudo パスワードを入力する方法では、1回に1つのパスワードしか指定できず、環境ごとに ansible-playbook を実行する必要があり面倒です。
以下のように環境ごとにあらかじめパスワードを指定しておくと、パスワードの入力が不要になります。

```
$ mkdir group_vars
```

```yaml:group_vars/production.yml
---
ansible_ssh_user: admin 
ansible_sudo_pass: prodpasswd
```

```yaml:group_vars/stage.yml
---
ansible_ssh_user: admin 
ansible_sudo_pass: stagepasswd
```

```yaml:group_vars/development.yml
---
ansible_ssh_user: admin 
ansible_sudo_pass: devpasswd
```

```yaml:group_vars/all.yml
--- 
remote_user: admin
```

ファイル名はグループ名に合わせてください。all.yml には全サーバ共通の設定を記述します(これはあとでPlaybook内で使います)。

#### パスワードファイルの暗号化

で、個人で使用する分にはこれでも良いのですが、実行環境を複数メンバーで共有する場合、パスワードを平文で書いておくのは望ましくありません。(あるいは個人で使うだけであっても、パスワードを平文で書いたファイルを持ってるのはなんか不安ではある)

そこで ansible-vault を使用して、パスワードが記述してあるファイルを共通鍵方式で暗号化します。

まず共通鍵をバージョン管理管轄外の場所に保存します。

```
$ echo samplepasswd > ~/.ansible_vault_pass
```
 
※ samplepasswd がパスワードになります。適宜変更してください。またファイル名も上記の通りでなくて大丈夫です。

暗号化します。

```
$ ansible-vault encrypt group_vars/production.yml --vault-password-file ~/.ansible_vault_pass
$ ansible-vault encrypt group_vars/stage.yml --vault-password-file ~/.ansible_vault_pass
$ ansible-vault encrypt group_vars/development.yml --vault-password-file ~/.ansible_vault_pass
```



## 実例

### 実行例 1: パッケージをインストールする
 
例として libxml2-dev パッケージをインストールします。以下のようなファイルを作成します。

```
$ mkdir tasks
```

```tasks/install_libxml2-dev.yml
---
- name: Install libxml2-dev
  hosts: all
  remote_user: "{{ remote_user }}"
  become: yes
  tasks:
    - apt: 
        name: libxml2-dev
        state: present
        update_cache: yes 
```

実行します。

```
$ ansible-playbook tasks/install_libxml2-dev.yml --vault-password-file ~/.ansible_vault_pass

PLAY [Install libxml2-dev] *****************************************************

TASK [setup] *******************************************************************
ok: [sample_dev_02]
ok: [sample_prod_01]
ok: [sample_prod_02]
ok: [sample_dev_01]
ok: [sample_stage_01]
ok: [sample_stage_02]

TASK [apt] *********************************************************************
changed: [sample_dev_01]
changed: [sample_dev_02]
changed: [sample_prod_02]
changed: [sample_stage_01]
changed: [sample_prod_01]
changed: [sample_stage_02]

PLAY RECAP *********************************************************************
sample_dev_01              : ok=2    changed=1    unreachable=0    failed=0   
sample_dev_02              : ok=2    changed=1    unreachable=0    failed=0   
sample_prod_01             : ok=2    changed=1    unreachable=0    failed=0   
sample_prod_02             : ok=2    changed=1    unreachable=0    failed=0   
sample_stage_01            : ok=2    changed=1    unreachable=0    failed=0   
sample_stage_02            : ok=2    changed=1    unreachable=0    failed=0   
```

これで管理対象のサーバすべてに libxml2-dev パッケージがインストールされました。
すべてのサーバにではなく、一旦開発環境(development)にだけインストールしたい場合は以下のように --limit オプションを追加します。

```
$ ansible-playbook --limit development tasks/libxml2-dev.yml --vault-password-file ~/.ansible_vault_pass
```

以下のコマンドでお手軽に実行することもできます。上の方法のほうが履歴が残る、結果が見やすいという意味で個人的には望ましいと思いますが。

```
ansible all -s -m apt -a 'name=libxml2-dev state=present update_cache=yes' --vault-password-file ~/.ansible_vault_pass
```



### 実行例 2: パッケージのバージョンを確認する

openssl など、セキュリティパッチが度々公開されるパッケージについては、現在インストールされているバージョンが最新かどうか確認したいケースが度々あります。そこでバージョンをファイルに書き出しローカルに転送する Playbook を作成します。

```yaml:tasks/openssl_version.yml
- name: Check version of openssl
  hosts: all
  remote_user: "{{ remote_user }}"
  become: no 
  vars:
      outfile: /tmp/{{ inventory_hostname }}.txt
  tasks:
      - shell: echo {{ inventory_hostname }}
                && sh -c 'dpkg -l | grep openssl | grep -v gnutls'
                && echo >> {{ outfile }}
      - fetch:
            src: "{{ outfile }}"
            dest: /tmp/openssl_version
            flat: yes
            fail_on_missing: yes
```

あらかじめ管理マシン上に /tmp/openssl_version というディレクトリを作成しておき、その後実行します。

```
$ mkdir /tmp/openssl_version
$ ansible-playbook tasks/openssl_version.yml --vault-password-file ~/.ansible_vault_pass
```

```
PLAY [Check version of openssl] ************************************************

TASK [setup] *******************************************************************
(...略...)

TASK [command] *****************************************************************
(...略...)

TASK [fetch] *******************************************************************
(...略...)

PLAY RECAP *********************************************************************
sample_dev_01              : ok=3    changed=2    unreachable=0    failed=0   
sample_dev_02              : ok=3    changed=2    unreachable=0    failed=0   
sample_prod_01             : ok=3    changed=2    unreachable=0    failed=0   
sample_prod_02             : ok=3    changed=2    unreachable=0    failed=0   
sample_stage_01            : ok=3    changed=2    unreachable=0    failed=0   
sample_stage_02            : ok=3    changed=2    unreachable=0    failed=0   
```

その後、

```
cat /tmp/openssl_version/*
```

を実行すれば、各サーバの openssl のバージョンを一覧することができます。

```
sample_dev_01
ii  openssl                         1.0.1f-1ubuntu2.21               amd64        Secure Sockets Layer toolkit - cryptographic utility

sample_dev_02
ii  openssl                         1.0.1f-1ubuntu2.21               amd64        Secure Sockets Layer toolkit - cryptographic utility

(...略...)

sample_stage_02
ii  openssl                         1.0.1f-1ubuntu2.21               amd64        Secure Sockets Layer toolkit - cryptographic utility
```

## 追記

Ansible Documentation の Vault のページに

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


>New in Ansible 1.5, “Vault” is a feature of ansible that allows keeping sensitive data such as passwords or keys in encrypted files, rather than as plaintext in your playbooks or roles. These vault files can then be distributed or placed in source control.


「暗号化したファイルが配布可能になる」と書いてありますが、暗号化されているとはいえ復号可能ではあるので、バージョン管理からは外しておいたほうが安全でしょう。