ansibleでCloudWatch Logsを導入する

ログをいい感じに管理したいよねーってことでawsのCloudWatch Logsを導入することになったのでまとめました。

ansibleなんぞやって人は、以前に調べたのでこちらをどうぞ
[ansibleで疎通確認とplaybookの実行](https://qiita.com/bunty/items/76d5db9a3058e28957db)

# やろうとしていること
CloudWatch Logsの[クイックスタート](http://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/QuickStartEC2Instance.html)に記載されている内容をansibleを使って実行できるようにします。

ansibleを使わないでやるとこんな感じですかね。

```
1. awslogs パッケージをインストール
[ec2-user ~]$ sudo yum install -y awslogs

2. 追跡するログを設定

3. awslogs サービスを開始
[ec2-user ~]$ sudo service awslogs start

4. システム起動時に毎回 awslogs サービスを起動する設定
[ec2-user ~]$ sudo chkconfig awslogs on
```

# ansibleで書いていく

## 全体的な構成
site.ymlが実行するファイルで、rolesにcloudwatch-logs用ディレクトリを作成して、site.ymlから呼び出します。

```
.
└── ansible
    ├── roles
    │   └── cloudwatch-logs
    │       ├── tasks
    │       │   └── main.yml
    │       └── templates
    │           ├── awscli.conf.j2
    │           └── awslogs.conf.j2
    │   
    └── site.yml

```
## 各ファイル

### site.yml
site.ymlが実際に実行をするファイルです。

こちらではcloudwatch-logsをincludeして利用しています。
なんとなく書いていたのですが、becomeはroot権限で実行する場合にyesにします。

```/ansible/site.yml
---
- hosts: all
  vars:
  remote_user: ec2-user
  become: yes

  roles:
    - { role: cloudwatch-logs }
  
```

### main.yml
こちらがcloudwatch-logsのタスクを定義しているメインのファイルです。
冒頭のやろうとしていることに書いたansibleを使わないでやる場合のコマンドの代わりに
こちらを実行するイメージを持ってもらえれば良いと思います。

どのログファイルを管理するかなどの設定は、別ファイルを作成してそれを読み込みます。

`start agent`の部分で起動させ、`enabled=yes`を指定することで、再起動させた時に自動で起動させるようにします。


```/ansible/roles/cloudwatch-logs/tasks/main.yml
---
- name: install awslogs
  yum: name=awslogs state=latest disable_gpg_check=yes

- name: copy conf files
  template: src={{ item }}.j2 owner=root dest=/etc/awslogs/{{ item }}
  with_items:
        - awscli.conf
        - awslogs.conf

- name: start agent
  service: name=awslogs state=started enabled=yes state=started
```

### awscli.conf.j2
regionは使っているところに合わせてもらえれば良いかと。

```/ansible/roles/cloudwatch-logs/templates/awscli.conf.j2
[plugins]
cwlogs = cwlogs

[default]
region = ap-northeast-1
```

### awslogs.conf.j2
このファイルでどのファイルをCloudWatch Logs側に送るのか、ログの名前はどうするのかということを指定します。
今回は`/var/log/httpd`ディレクトリにあるアクセスログとエラーログを全てCloudWatch Logsに送ります。
それぞれ`access_log`と`error_log`というロググループを作成して、その中にhostnameごとに管理していきます。


```/ansible/roles/cloudwatch-logs/templates/awslogs.conf.j2
[general]
state_file = /var/lib/awslogs/agent-state

[/var/log/httpd/access_log]
datetime_format = %b %d %H:%M:%S
buffer_duration = 5000
log_stream_name = {hostname}.access_log
initial_position = start_of_file
file = /var/log/httpd/access_log.*
log_group_name = access_log

[/var/log/httpd/error_log]
datetime_format = %b %d %H:%M:%S
buffer_duration = 5000
log_stream_name = {hostname}.httpd_error_log
initial_position = start_of_file
file = /var/log/httpd/error_log.*
log_group_name = error_log
```


## dry-run
準備ができたのでdry-runで確認します。
1つfailedがありますが、こちらはawslogsをstartさせようとしたけどinstallされてないからできないということですね。
(dry-runなので実際にはinstallが行われていません。)

```
 $ ansible-playbook site.yml -i hosts -C

PLAY [all] *********************************************************************

TASK [setup] *******************************************************************
ok: [127.0.0.1]

TASK [cloudwatch-logs : install awslogs] ***************************************
changed: [127.0.0.1]

TASK [cloudwatch-logs : copy conf files] ***************************************
changed: [127.0.0.1] => (item=awscli.conf)
changed: [127.0.0.1] => (item=awslogs.conf)

TASK [cloudwatch-logs : start agent] *******************************************
fatal: [127.0.0.1]: FAILED! => {"changed": false, "failed": true, "msg": "no service or tool found for: awslogs"}
  to retry, use: --limit @/Users/username/workspace/aws/aws/ansible/site.retry

PLAY RECAP *********************************************************************
127.0.0.1              : ok=3    changed=3    unreachable=0    failed=1


```

## ansibleの実行
丁寧にやるならinstall前後の処理で分けて実行すれば、dry-runでOKのtaskだけをサーバに反映できると思います。
が、失敗しても問題はない環境なのでそのまま実行します。できた。

```
$ ansible-playbook site.yml -i hosts         

PLAY [all] *********************************************************************

TASK [setup] *******************************************************************
ok: [127.0.0.1]

TASK [cloudwatch-logs : install awslogs] ***************************************
changed: [127.0.0.1]

TASK [cloudwatch-logs : copy conf files] ***************************************
changed: [127.0.0.1] => (item=awscli.conf)
changed: [127.0.0.1] => (item=awslogs.conf)

TASK [cloudwatch-logs : start agent] *******************************************
changed: [127.0.0.1]

TASK [Set hostname.] ***********************************************************
ok: [127.0.0.1]

PLAY RECAP *********************************************************************
127.0.0.1              : ok=5    changed=4    unreachable=0    failed=0

```

# 気をつけること
・ログデータをどのように管理するのかを考えて構成を考える
・実際にコンソール画面を見てみる
・権限周りで詰まったら[クイックスタート](http://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/QuickStartEC2Instance.html) + [IAM Policy Simulator](https://policysim.aws.amazon.com/)で確認

# 参考
http://dev.classmethod.jp/cloud/ansible-cloudwatch-logs-play-framework/
http://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/QuickStartEC2Instance.htm