Amazon CloudWatch Logsを実行するDockerイメージを作ってみた

docker

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

ども、大瀧です。
先日リリースされたCloudWatch Logsですが、早速弊社ブログでも取り上げています。

手軽に使えるログストアとして、AWSユーザーであれば(あるいはそれ以外のユーザーでも)検討する機会が多くなりそうです。それは、もしかしたら近いうちにデファクトのアプリ実行環境になるかもしれないDocker環境にも言えることだと思います。そこで、CloudWatch LogsにログをプッシュするDockerイメージを作成し、Docker環境でCloudWatch Logsを利用する手順をご紹介します。

動作確認環境

  • AMI : Amazon Linux 2014.03.2 HVM
  • Docker : バージョン1.0.0

コンテナ構成の概要

Dockerでログを集約する方法はいくつかありますが、今回は最も単純な、ボリュームを共有する方法を利用します。Dockerのログ集約については、以下のブログ記事が詳しいです。

概念図で示すと、以下の感じになります。

docker-awslog01

今回は収集対象のログをnginxのアクセスログとし、awslogエージェントを実行するコンテナがアクセスログをCloudWatch APIにPushします。DockerコンテナからCloudWatch APIにアクセスできるのか、IAMロールが動くのか気になるところですが、Dockerコンテナの既定のネットワーク構成であればどちらも問題ありません。

awslogコンテナのベースDockerイメージは、Docker Hubで公開しました。docker pullで使って下さい。

ベースDockerイメージと書いたのは、このイメージから直接コンテナーを立ち上げても監視するログファイルの定義が空のため、コンテナは何もしないためです。このイメージに設定ファイルを追加した派生イメージdocker buildで作成し、使っていただくものになっています。docker buildを実行するマシンは、Dockerを実行する任意のマシンで構いません(今回は手元のMBAでBoot2Dockerを実行しました)。

では、手順を追って紹介していきます。

1. CloudWatch Logsの設定ファイルの作成

CloudWatch Logsの動作には、以下2つのファイルが必要です。`docker build`を実行するマシンでそれぞれ作成します。

aws.conf

[plugins]
cwlogs = cwlogs

[profile default]
aws_access_key_id = AKIAXXXXXXXXXXXX
aws_secret_access_key = XXXXXXXXXXXXXXXXXXXXXXXXXX

CloudWatch APIにアクセスするための設定を記載します。[profile default]以降のアクセスキー、シークレットキーはIAMロールをEC2インスタンスに付与している場合は省略できます。

awslogs.conf

[general]
state_file = /var/awslogs/state/agent-state

[/var/log/nginx/access.log]
datetime_format = %b %d %H:%M:%S
file = /nginx-logs/access.log
push_delay = 5000
log_stream_name = {instance_id}
initial_position = start_of_file
log_group_name = /var/log/nginx/access.log
[/var/log/nginx/error.log]
datetime_format = %b %d %H:%M:%S
file = /nginx-logs/error.log
push_delay = 5000
log_stream_name = {instance_id}
initial_position = start_of_file
log_group_name = /var/log/nginx/error.log

4行目以降は監視したいファイルごとに作成します。いくつかパラメータがありますが、他のファイルを監視する場合も基本的にはファイル名のみいじる形で問題ないでしょう。

2. Dockerイメージのビルド

上記2ファイルを同じディレクトリで以下のDockerfileを作成し、Dockerイメージをビルドします。

Dockerfile

FROM takipone/docker-awslogs

1行しかないことに驚くかもしれませんが、これでOKです。先ほど作成したaws*.confファイルは、ベースのDockerイメージtakipone/docker-awslogsDockerfileの中ONBUILDが定義されているので、以下のビルドログにもあるように今回のビルド時にDockerイメージに追加されます。では、docker buildコマンドでビルドします。-tオプションに指定するイメージ名(今回はtakipone/awslogs-nginx)は、好きなもので構いません。

$ docker build -t takipone/awslogs-nginx .
Sending build context to Docker daemon 14.34 kB
Sending build context to Docker daemon
Step 0 : FROM takipone/docker-awslogs
# Executing 2 build triggers
Step onbuild-0 : ADD aws.conf       /var/awslogs/etc/aws.conf
 ---> 0db93cfae97f
Step onbuild-1 : ADD awslogs.conf /var/awslogs/etc/awslogs.conf
 ---> 4c3493eb04f6
 ---> 4c3493eb04f6
Removing intermediate container 43e3a83a7f4f
Removing intermediate container fe0a43f5d7bc
Successfully built 4c3493eb04f6
$

できました!

監視するログの設定(nginxの例)

順番が前後しますが、今回の監視対象ログとなるnginxのコンテナで出力するアクセスログ(access.log)およびエラーログ(error.log)を準備します。awslogコンテナとnginxコンテナのファイルはデフォルトでは別々のchroot環境になるので、docker runコマンドの-vオプションで外部にマウントするところに注意します。今回は/nginx-logs/ディレクトリにログを出力、外部にマウントします。

$ docker pull dockerfile/nginx
Pulling repository dockerfile/nginx
2a106d243809: Download complete
  : 
$ sudo mkdir /nginx-logs
$ docker run -d -p 80:80 -v /nginx-logs:/var/log/nginx dockerfile/nginx
6c73622f487d2366d8fd151946c0eb7c59c2f62ad644854a61f156189665af37
$ curl localhost
<!DOCTYPE html>
<html>
  :
<h1>Welcome to nginx!</h1>
  :
</html>
$ ls /nginx-logs
access.log  error.log
$ cat /nginx-logs/access.log
172.17.42.1 - - [13/Jul/2014:09:02:22 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.36.0"
$

nginxコンテナの動作は問題無さそうですね。

awslogコンテナの実行と動作確認

それでは、awslogコンテナを実行します。先ほどのnginxコンテナの実行と同様、docker run実行時に-vオプションで/nginx-logs以下をマウントします。

$ docker run -d --name awslogs -v /nginx-logs:/nginx-logs takipone/awslogs-nginx
0f9f920290560875fdb3352947a0a9458de076be3c8cc8e60ce9a46e52bd0439
$ docker ps
CONTAINER ID        IMAGE                           COMMAND                CREATED             STATUS              PORTS                         NAMES
0f9f92029056        takipone/awslogs-nginx:latest   /bin/sh -c '/bin/sh    2 seconds ago       Up 1 seconds                                      awslogs
6c73622f487d        dockerfile/nginx:latest         nginx                  13 hours ago        Up 13 hours         443/tcp, 0.0.0.0:80->80/tcp   grave_mayer
$

コンテナが動きました。では、CloudWatch Logsの画面を確認してみます。

docker-awslog02

コンテナを実行するEC2インスタンスのインスタンスIDでアクセスログが確認できます!

まとめ

DockerコンテナでCloudWatch LogsにログをPushする手順をご紹介しました。コンテナ間のログのやり取りはまだまだ改善や工夫ができるところだと思うので、引き続きいろいろ試行錯誤してみたいと思います。

Dockerコンテナを使うことで、awslogエージェントのインストール無しで手軽にセットアップ出来る感じがDockerらしくていいなぁ、と感じていただけるとDocker推しとしては嬉しい限りです。