自転車操業になりつつある「初老丸の独り Advent calendar 2015」の十七日目の記事です。

追記(2016/01/20)

ECS 上の Docker コンテナから CloudWatch Logs を利用する場合には以下の点に注意が必要です。

  • Task Definition での定義はサポートしていない
  • docker run 時のオプションで指定することで利用は可能

コメントにて id:NewGyu さんよりご指摘頂きました。id:NewGyu さん、コメント有難うございました。

現時点ではTask Definitionにawslogsを指定すると「awslogsなぞ知らん」と言われてしまい使えないようです。

ただ、ECSAgentにそれっぽいプルリクが来ているので近日使えるようになりそうな気配です。
https://github.com/aws/amazon-ecs-agent/pull/251

上記の通り、ECS Agent に Logging Driver として CloudWatch Logs を利用出来るようにするプルリクがあるようです(Stream 名(デフォルトは Container ID))について検討が必要な点があるようです)ので、近いうちに Task Definition で指定が可能になると思います。

tl;dr

Amazon ECS で個人的な疑問を紐解いていきたい。

今日の疑問

疑問

  • Docker の Logging Driver で CloudWatch Logs が使えるとのことですが、ECS でも使えますでしょか

答え

  • 少々お待ち下さい、ECS から直接利用するにはもう少し時間がかかりそうです(2016/01/20)
  • 安心してください、もちろん使えますよ

以下のようにドキュメントにも記載されいる。

docs.docker.com

ポイントとしては Credentials だと思う。(後ほど)

ちなみに Logging Driver とは

個人的な認識だがコンテナのログを以下のようなミドルウェアに出力することができるようになるオプション。

  • json-file
  • syslog
  • journald
  • gelf
  • fluentd
  • awslogs(CloudWatch Logs)

journaldgelf は生まれて初めて聞いた。

ドキュメントを読むと、Docker Engine を起動する際、Docker コンテナを起動する際にオプションとして Logging Driver を指定できるようだ。

以下、Docker Engine 起動時のオプション。(ドキュメントより抜粋)

$ docker daemon --log-driver=json-file --log-opt labels=foo --log-opt env=foo,fizz

以下、コンテナ起動時のオプション。(ドキュメントより抜粋)

$ docker run --log-driver=syslog --log-opt syslog-address=tcp://192.168.0.42:123

ECS で Logging Driver CloudWatch Logs 試す

教材

引き続き、教材は以下の教材を利用する。

github.com

まずは Credential

以下のような IAM Policy をコンテナインスタンスに適用する必要がある。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}

教材の terraform/iam.tf を以下のように修正する。

$ git diff iam.tf
diff --git a/terraform/iam.tf b/terraform/iam.tf
index 3734e62..8811f67 100644
--- a/terraform/iam.tf
+++ b/terraform/iam.tf
@@ -50,6 +50,14 @@ resource "aws_iam_role_policy" "ecs_iam_role" {
       ],
       "Effect": "Allow",
       "Resource": "*"
+    },
+    {
+      "Action": [
+        "logs:CreateLogStream",
+        "logs:PutLogEvents"
+      ],
+      "Effect": "Allow",
+      "Resource": "*"
     }
   ]
 }

次に CloudWatch Logs の Log Group を作っておく

これも教材に追加。

$ cat cwlog.tf
#
# Create CloudWatch Logs Log Group
#
resource "aws_cloudwatch_log_group" "oreno_cw_log" {
  name = "docker-logging"
}

terraform apply

あとは terraform apply するだけ。(教材では make tf-apply

$ make tf-apply

(snip)

Outputs:

  CloudWatch Logs Log Group Name = docker-logging
  EC2 IP address                 = xxx.xxx.xxx.xxx
  EC2 Instance ID                = i-xxxxxxxx
  ECS Cluster Name               = oreno-cluster

hello-world

コンテナインスタンスにログインして hello-world してみる。

$ docker run 
> --log-driver=awslogs 
> --log-opt awslogs-region=ap-northeast-1 
> --log-opt awslogs-group=docker-logging 
> hello-world

Hello from Docker.
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker Hub account:
 https://hub.docker.com

For more examples and ideas, visit:
 https://docs.docker.com/userguide/

以下のようにログが出力されている。

20151217093900

Log Stream 名を指定しなければ上記のようにコンテナ ID が Log Stream 名となる。

20151217094006

おお簡単。

CloudWatch Logs Logging Driver について

ドキュメントより抜粋。

  • Docker Engine のオプションとして
$ docker daemon --log-driver=awslogs
  • コンテナの起動時にオプションとして
$ docker run --log-driver=awslogs
  • awslogs-region オプション

リージョンを指定する。

$ docker run --log-driver=awslogs --log-opt awslogs-region=ap-northeast-1...
  • awslogs-group オプション

Log Group を指定する。

$ docker run --log-driver=awslogs --log-opt awslogs-region=ap-northeast-1 --log-opt awslogs-group=docker-logging ...

Log Group は事前に作成しておく必要があるので注意。

  • awslogs-stream オプション

Log Stream を指定する。これは必須ではない。

$ docker run --log-driver=awslogs --log-opt awslogs-region=ap-northeast-1 --log-opt awslogs-group=docker-logging --log-opt=awslogs-stream=foo ...

指定しない場合にはコンテナ ID が Log Stream 名を指定する。

Log Stream 名については以下のような注意書きがある。

Log streams within a given log group should only be used by one container at a time. Using the same log stream for multiple containers concurrently can cause reduced logging performance.

同一の Log Stream に複数のコンテナからのログを送るとログの収集パフォーマンスに影響を及ぼす…(という解釈)。

以上

疑問は…

解けました。

もう少し…

Log Driver については触れていきたいと思う。

元記事はこちら

(ショロカレ 17 日目)Amazon ECS の個人的な疑問を紐解いていくメモ(3)~ ECS で Docker の CloudWatch Logs Logging Driver を利用する