AWSでログ監視をなるべくansibleから設定する
ゴール
アプリケーションのログをCloudWatchで監視し、アラームがあげられるようなec2サーバ環境のansibleによる自動構築
注意
いくつかわかったことと、わからないことがあり、わからないことが解決したら書き換えていきます。
必ずしも全てあっているわけではありません。
ansibleによるec2インスタンスの構築・立ち上げ
ansibleとは サーバ等を自動構築するための構成管理ツール
Ansilbe All Modulesを見ると、多くのaws設定モジュールがansibleには存在します。
コンソール、aws cliでできることが完全に網羅されていませんがこれらのモジュールを使うとansibleの中で構成変更とその結果を出力することができます。
aws cliで構築するやり方をAWS CLIで構築するCloudWatch Agentより参考としました。
ec2インスタンスの構築公開は後回しにします。
ansibleによるec2サーバの設定
ここではawsに構築されたec2インスタンスにパッケージ等インストールしてCloudWatchでサーバの監視ができる状態をansibleで作ります。
ec2は構築のたびにIPとか変わります。そのためansibleの静的設定ファイルにホストの指定ができません。そのためawsからそれを取得するEC2 External Inventoryというツールがあります。ここなどを参考にこれを導入しました。
まずは必要なパッケージのインストール
次のようなansibleの構成にて単純なパッケージの導入と起動とかを設定していきます。
.
├── hosts
│ ├── prod
│ └── stg
│ ├── ec2.ini
│ └── ec2.py
├── roles
│ └── packages
│ ├── tasks
│ │ └── main.yml
│ └── vars
│ └── main.yml
└── site.yml
導入したいパッケージ
次の2つが必要なパッケージだがAmazon Linux 2のAMIを選択してインスタンスを作っておいたらすでにインストール済みでした。
amazon-cloudwatch-agent
amazon-ssm-agent
インスタンスにログインし次を実行。
[ec2-user@ip-10-1-21-4 bin]$ sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -m ec2 -a status
{
"status": "stopped",
"starttime": "",
"version": "1.208036.0"
}
[ec2-user@ip-10-1-21-4 bin]$
加えてこちらのパッケージを導入。
collectd
collectdの設定方法を参考とさせていただきました。
collectdで集めた情報をCloudWatchから参照することができる。
aws cloudwatch ...
というcliもあるがcollectd等と連携することが推奨されているようだ。
次のようにcollectdの設定を変更して再起動する。
- name: collectd configuration
lineinfile: >-
dest='/etc/collectd.conf'
state=present
backrefs=yes
regexp='{{ item.regexp }}'
line='{{ item.line}}'
with_items:
- regexp: '^#?\s*LoadPlugin disk'
line: 'LoadPlugin disk'
- regexp: '^#?\s*LoadPlugin email'
line: 'LoadPlugin email'
register: conf
- debug: var=conf
- name: dependency service restart
service:
name: collectd
state: restarted
CloudWatchに情報を送るIAMユーザを作成
次のポリシーをアタッチしたIAMユーザを作成
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "cloudwatch:PutMetricData",
"Resource": "*"
}
]
}
AWS Sytems Manager Sericesからコマンド実行のトラブルシューティング(原因不明)が発生。
CloudWatch エージェント設定ファイルを手動で作成または編集するを見て頑張って設定ファイルを作ってみる。
一度「Amazon Web Services パターン別構築・運用ガイド」を読んで実行していたのでP.414で生成されたファイルを元に変更している。
metrics
diskの計測方法(measurement)を変えている
"metrics": {
"append_dimensions": {
"AutoScalingGroupName": "${aws:AutoScalingGroupName}",
"ImageId": "${aws:ImageId}",
"InstanceId": "${aws:InstanceId}",
"InstanceType": "${aws:InstanceType}"
},
"metrics_collected": {
"collectd": {
"metrics_aggregation_interval": 60
},
"cpu": {
"measurement": [
"cpu_usage_idle",
"cpu_usage_iowait",
"cpu_usage_user",
"cpu_usage_system"
],
"metrics_collection_interval": 60,
"resources": [
"*"
],
"totalcpu": false
},
"disk": {
"measurement": [
"total",
"used",
"free",
"used_percent",
"inodes_free"
],
"metrics_collection_interval": 60,
"resources": [
"*"
]
},
"diskio": {
"measurement": [
"io_time",
"write_bytes",
"read_bytes",
"writes",
"reads"
],
"metrics_collection_interval": 60,
"resources": [
"*"
]
},
"mem": {
"measurement": [
"mem_used_percent"
],
"metrics_collection_interval": 60
},
"netstat": {
"measurement": [
"tcp_established",
"tcp_time_wait"
],
"metrics_collection_interval": 60
},
"statsd": {
"metrics_aggregation_interval": 60,
"metrics_collection_interval": 10,
"service_address": ":8125"
},
"swap": {
"measurement": [
"swap_used_percent"
],
"metrics_collection_interval": 60
}
}
logs
ログはデフォルトでmessagesの監視がついていたがそれをコピーしてアプリケーションのログを監視できるようにした。
"logs": {
"logs_collected": {
"files": {
"collect_list": [
{
"file_path": "/var/log/messages",
"log_group_name": "messages",
"log_stream_name": "{instance_id}"
},
{
"file_path": "/var/log/application.log",
"log_group_name": "application",
"log_stream_name": "{instance_id}"
}
]
}
}
},
agent
ウィザードを使って生成した元にはagentがなかったが、ログを見てみようと思いdebugを入れた。
"agent": {
"debug": true
},
$ aws ssm describe-instance-information --instance-information-filter-list key=PingStatus,valueSet=Online [17:48:26]
{
"InstanceInformationList": [
{
"IsLatestVersion": false,
"ComputerName": "ip-x-x-x-x.us-west-2.compute.internal",
"PingStatus": "Online",
"InstanceId": "i-xxxx7cb53516b635e",
"IPAddress": "xx.xx.xx.xx",
"ResourceType": "EC2Instance",
"AgentVersion": "2.3.372.0",
"PlatformVersion": "2",
"PlatformName": "Amazon Linux",
"PlatformType": "Linux",
"LastPingDateTime": 1554108523.909
}
]
}
設定ファイルを配布する
AWS CLIで構築するCloudWatch Agent
の CloudWatch Agentの設定ファイルをパラメータストアにアップロード を参考に
AWS SYSTEM MANAGERのパラメータストア にアップロードすることにした。
ansibleにもaws_ssm_parameter_storeというパラメータストアの管理モジュールがありましたので、それを使います。
値は設定ファイルから設定しています。
- aws.cloudwatchagent.name AmazonCloudWatch-linux
- aws.cloudwatchagent.file 上記設定ファイルを別ファイルとしてパスを記載
- name: copy conf file SSM parameter store
aws_ssm_parameter_store:
region: "{{ aws.common.region }}"
name: "{{ aws.cloudwatchagent.name }}"
description: "{{ aws.cloudwatchagent.description }}"
string_type: String
value: "{{ lookup('file',aws.cloudwatchagent.file) }}"
register: aws_ssm_parameter_store
- debug: var=aws_ssm_parameter_store
設定を反映する。
AWS CLIで構築するCloudWatch Agent
の CloudWatch Agent設定 を参考にansibleを定義します。
モジュールは存在しなかったのでaws cliを実行することにしました。
ec2インスタンスはすでに構築されている前提で、まずはec2のインスタンスIDを取得します。
私の環境ではsystemというタグでいくつかグループを分けていたためフィルタに設定しています。各自の環境に読み替えてください。
- name: get ec2 instanceids
ec2_instance_facts:
region: "{{ aws.common.region }}"
filters:
"tag:system": "{{ aws.common.target }}"
register: ec2_instance_facts
- debug: var=ec2_instance_facts
次に取得したインスタンスIDに対してコマンドを実行します。
- name: aws CloudWatch config
command: >
aws ssm send-command
--document-name "AmazonCloudWatch-ManageAgent"
--targets "Key=instanceids,Values='{{ item.instance_id }}'"
--parameters "action=configure, mode=ec2, optionalConfigurationSource=ssm, optionalConfigurationLocation=AmazonCloudWatch-linux, optionalRestart=yes"
--profile {{ aws.common.profile }}
--timeout-seconds 600 --max-concurrency "50" --max-errors "0" --region "{{ aws.common.region }}"
with_items: "{{ ec2_instance_facts.instances }}"
うまく実行できたら AWS コンソールからログインし、CloudWatchのメトリクスを確認します。
CWAgentにCloudWatchAgentの設定を行なったec2インスタンスが追加されていれば成功です。
.
├── hosts
│ ├── prod
│ └── stg
│ ├── ec2.ini
│ └── ec2.py
├── roles
│ ├── cloudwatch
│ │ ├── tasks
│ │ │ ├── main.yml
│ │ └── vars
│ │ ├── main.yml
│ ├── iam_role
│ │ └── tasks
│ │ └── main.yml
│ └── packages
│ ├── tasks
│ │ └── main.yml
│ └── vars
│ └── main.yml
└── site.yml