Amazon ECSのTaskのログをawslogsを使ってCloudWatch Logsに送る

先日 DockerにおけるロギングのSidecarアプローチ | shinodogg.com というエントリで、LogglyでDockerのログを一元管理する方法をご紹介しましたが、今日はCloudWatch LogsでDocker(Amazon ECSのタスク)のログを一元管理する方法を考えていきたいと思います。

awslogsログドライバーをGetting Startedしてみる

Using the awslogs Log Driverに沿って進めていくため、WordPressやMySQLのDocker imageを使ってEC2上にECSでタスク(EC2上に稼働するコンテナ)定義しながら構築を進めていく形になります。

awslogsをEC2インスタンスにインストール

Using CloudWatch Logs with Container Instancesに沿ってCloudWatch Logsのエージェントであるawslogsをコンテナを稼働させるEC2インスタンスにインストールしていきます。

$ which awslogs
/usr/bin/which: no awslogs in (/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/ec2-user/.local/bin:/home/ec2-user/bin)

$ sudo yum install -y awslogs
読み込んだプラグイン:priorities, update-motd, upgrade-helper
amzn-main/latest                                                                                         | 2.1 kB     00:00     
amzn-updates/latest                                                                                      | 2.3 kB     00:00     
依存性の解決をしています
〜略〜
  python27-ply.noarch 0:3.4-3.12.amzn1                    python27-pyasn1.noarch 0:0.1.7-2.9.amzn1                             
  python27-rsa.noarch 0:3.4.1-1.8.amzn1                  

完了しました!

awslogsの設定ファイルは /etc/awslogs/awslogs.conf に配置してあって、中身を開くとサービスの起動の仕方とかが書いてあります。

# ------------------------------------------
# CLOUDWATCH LOGS AGENT CONFIGURATION FILE
# ------------------------------------------
#
# --- DESCRIPTION ---
# This file is used by the CloudWatch Logs Agent to specify what log data to send to the service and how.
# You can modify this file at any time to add, remove or change configuration.
#
# NOTE: A running agent must be stopped and restarted for configuration changes to take effect.
#
# --- CLOUDWATCH LOGS DOCUMENTATION ---
# https://aws.amazon.com/documentation/cloudwatch/
#
# --- CLOUDWATCH LOGS CONSOLE ---
# https://console.aws.amazon.com/cloudwatch/home?region=us-east-1#logs:
#
# --- AGENT COMMANDS ---
# To check or change the running status of the CloudWatch Logs Agent, use the following:
#
# To check running status: service awslogs status
# To stop the agent: service awslogs stop
# To start the agent: service awslogs start
# To start the agent on server startup: chkconfig awslogs on
#
# --- AGENT LOG OUTPUT ---
# You can find logs for the agent in /var/log/awslogs.log

今回はサンプルに沿って↓のように書き換えます。

[general]
state_file = /var/lib/awslogs/agent-state        
 
[/var/log/dmesg]
file = /var/log/dmesg
log_group_name = /var/log/dmesg
log_stream_name = test/725126da-6e5b-453a-96b0-bc6fe0b6c34c

[/var/log/messages]
file = /var/log/messages
log_group_name = /var/log/messages
log_stream_name = test/725126da-6e5b-453a-96b0-bc6fe0b6c34c
datetime_format = %b %d %H:%M:%S

[/var/log/docker]
file = /var/log/docker
log_group_name = /var/log/docker
log_stream_name = test/725126da-6e5b-453a-96b0-bc6fe0b6c34c
datetime_format = %Y-%m-%dT%H:%M:%S.%f

[/var/log/ecs/ecs-init.log]
file = /var/log/ecs/ecs-init.log.*
log_group_name = /var/log/ecs/ecs-init.log
log_stream_name = test/725126da-6e5b-453a-96b0-bc6fe0b6c34c
datetime_format = %Y-%m-%dT%H:%M:%SZ

[/var/log/ecs/ecs-agent.log]
file = /var/log/ecs/ecs-agent.log.*
log_group_name = /var/log/ecs/ecs-agent.log
log_stream_name = test/725126da-6e5b-453a-96b0-bc6fe0b6c34c
datetime_format = %Y-%m-%dT%H:%M:%SZ

[/var/log/ecs/audit.log]
file = /var/log/ecs/audit.log.*
log_group_name = /var/log/ecs/audit.log
log_stream_name = test/725126da-6e5b-453a-96b0-bc6fe0b6c34c
datetime_format = %Y-%m-%dT%H:%M:%SZ

デフォルトではCloudWatch Logsはus-east-1にデータを送信するようになっているので、/etc/awslogs/awscli.conf のリージョンを変更します。

[plugins]
cwlogs = cwlogs
[default]
region = ap-northeast-1

それでは awslogs を起動します。ついでに自動起動するように仕込んでおきます。

$ sudo service awslogs start
Starting awslogs:                                          [  OK  ]
$ sudo chkconfig awslogs on

でもって、CloudWatch Logsではそれっぽく見えてます。
Screen Shot 2017-02-08 at 15.04.37

でもって、毎回こういうことやるの面倒なので、cloud-initとかでよしなに〜っていうのは今回は割愛させていただいて…。あと、IAMロールでlogs:CreateLogStreamとかlogs:PutLogEventsの権限が必要よん、、とか。

ECSのTaskからCloudWatch Logsにデータを送信

ロググループの作成

例えばWordPressなヤツであれば、WordPressコンテナ用のロググループと、MySQLコンテナ用のロググループを作ります。

$ aws logs create-log-group --log-group-name awslogs-wordpress --region ap-northeast-1
$ aws logs create-log-group --log-group-name awslogs-mysql --region ap-northeast-1

ECS Taskの定義&実行

サンプルをまんまで↓ECSのコンソールのタスク定義から突っ込んで登録した後、

{
    "containerDefinitions": [
        {
            "name": "wordpress",
            "links": [
                "mysql"
            ],
            "image": "wordpress",
            "essential": true,
            "portMappings": [
                {
                    "containerPort": 80,
                    "hostPort": 80
                }
            ],
            "logConfiguration": {
                "logDriver": "awslogs",
                "options": {
                    "awslogs-group": "awslogs-wordpress",
                    "awslogs-region": "ap-northeast-1",
                    "awslogs-stream-prefix": "awslogs-example"
                }
            },
            "memory": 500,
            "cpu": 10
        },
        {
            "environment": [
                {
                    "name": "MYSQL_ROOT_PASSWORD",
                    "value": "password"
                }
            ],
            "name": "mysql",
            "image": "mysql",
            "cpu": 10,
            "memory": 500,
            "essential": true,
            "logConfiguration": {
                "logDriver": "awslogs",
                "options": {
                    "awslogs-group": "awslogs-mysql",
                    "awslogs-region": "ap-northeast-1",
                    "awslogs-stream-prefix": "awslogs-example"
                }
            }
        }
    ],
    "family": "awslogs-example"
}

コンテナインスタンスでタスクを実行します。
Screen Shot 2017-02-08 at 15.48.19

CloudWatch Logsでログの確認

WordPressにアクセスしてみます。
wp

CloudWatch Logs上で狙ったようにWordPressのログが出ていて、
Screen Shot 2017-02-08 at 15.59.05

MySQLの方もそれっぽいログが出ていました。
Screen Shot 2017-02-08 at 16.06.26

追加でログを取りたくなったら、、

例えばアクセスログだけでなく、PHPのデバッグログを見たい!という場合があるかもしれません。その場合、1つのコンテナ上で複数ファイルを上記の仕掛けでやりくりすることは出来ないので、EC2インスタンスのボリュームをマウントしてそこに書き込みを行い、それをCloudWatch Logsに流すコンテナを立ち上げることにします。

ECSのタスク定義に以下のように追加します。WordPressのDockerコンテナの /var/www/html を、コンテナインスタンス(EC2)の wpdata というディレクトリにマウントして、そこに書き込むことができる、という設定です。

"mountPoints": [
  {
    "sourceVolume": "wpdata",
    "containerPath": "/var/www/html",
    "readOnly": false
  }
]

コンテナインスタンス上の wpdata は今回は適当にホームディレクトリな設定にしました…
Screen Shot 2017-02-08 at 17.22.25

ということで、/var/www/html にある wp-config.php で デバッグログ設定を以下のように有効にします。

define('WP_DEBUG', true);
define('WP_DEBUG_DISPLAY', false);
define('WP_DEBUG_LOG', true);

そうすることで、 wp-content ディレクトリの中に以下のような debug.log というファイルが出来ます。(ログの出力先のパスを変えなさいよっていう話もあるのですが、、)
今回はこのファイルをtailしてCloudWatch Logsに転送してみたいと思います。

[08-Feb-2017 08:25:38 UTC] WordPress database error Table 'wordpress.wp_users' doesn't exist for query SELECT * FROM wp_users WHERE user_login = 'hoge' made by require_once('wp-load.php'), require_once('wp-config.php'), require_once('wp-settings.php'), WP->init, wp_get_current_user, _wp_get_current_user, apply_filters('determine_current_user'), WP_Hook->apply_filters, call_user_func_array, wp_validate_logged_in_cookie, wp_validate_auth_cookie, get_user_by, WP_User::get_data_by

DebugログをCloudWatch Logsに転送するコンテナを立てる

今回はログtailして出力するDocker imageとしてfluent/fluentd(https://hub.docker.com/r/fluent/fluentd/)を使ってみたいと思います。

タスク定義にfluentd用のコンテナの設定を以下のように追加します。
イメージは fluent/fluentd
Screen Shot 2017-02-10 at 18.46.55

fluentdの設定ファイルは、試しに立ち上げて docker exec -it {CONTAINER ID} /bin/sh で中入ってみたら↓こんな感じだったので、

$ ps -ef 
PID   USER     TIME   COMMAND
    1 fluent     0:00 {fluentd} /usr/bin/ruby /usr/bin/fluentd -c /fluentd/etc/fluent.conf -p /fluentd/plugins
    6 fluent     0:00 {fluentd} /usr/bin/ruby /usr/bin/fluentd -c /fluentd/etc/fluent.conf -p /fluentd/plugins
   18 fluent     0:00 /bin/sh
   25 fluent     0:00 ps -ef

コンテナインスタンス(ECSのタスクが稼働するEC2インスタンス)の適当なところに fluent.conf を置いて読み取り専用で /fluentd/etc にマウントして、
ついでに debug.log も読み込めるように、wpdata(上記のWordPressのコンテナが吐き出したdebug.logは /var/www/html/wp-content に出力される)も /home/fluent に読み取り専用でマウントしておきます。
Screen Shot 2017-02-10 at 18.47.16
超絶雑で大変申し訳ございませんがコンテナインスタンス(EC2)と各タスク(Dockerコンテナ)は↓こんな構成。笑
hoge
ログ出力に関しては、awslogs-php というグループを後で作ることにして、こちらも今までと同様にawslogsを使ってCloudWatch Logsに連携するように設定します。これによって標準出力に吐き出すだけでログが転送されます。

ということでfluent.confの中身は↓こんな感じ。debug.logtailして標準出力に吐き出すだけ。

<source>
  @type tail
  path /home/fluent/wp-content/debug.log
  format none
  tag php
  @id input
</source>
<match **>
  @type stdout
  @id output
</match>

※ CloudWatch Logsまでデータが行くと、その先にAmazon Elasticsearch Serviceに簡単に突っ込めたり、AWS Lambdaでホゲホゲしたりとか、色々便利なのですが、その辺の話はまた別途…

CloudWatch Logsにロググループを追加してDebugログを出力する

CloudWatch LogsのロググループはPHP用に以下のものを用意します。
$ aws logs create-log-group --log-group-name awslogs-php --region ap-northeast-1

例えばですが、、WordPressの 外観 メニューから選べる Twenty Seventeen: テーマヘッダー (header.php) の中に
↓こんなコードを一行追加してみます。

error_log("hoge log");

ECSタスクを実行後にCloudWatch Logsを見ると↓こんな風に仕込んだデバッグログが見えます。
Screen Shot 2017-02-10 at 19.29.10

最後に

今回『アプリケーションが稼働するコンテナ→データボリューム→ログをtailして吐き出すコンテナ→CloudWatch Logs』といったような流れをawslogsを使ってやってみました。この仕掛けを使いながら DockerにおけるロギングのSidecarアプローチ | shinodogg.com で紹介したようなsidecarやsidekicksと呼ばれるようなやり方を実現できると、コンテナ化しても安心してログ管理が出来るのではないかと思います。

西一番街ブラックバイト 池袋ウエストゲートパークXII
石田 衣良
文藝春秋
売り上げランキング: 43,902

シェアする

  • このエントリーをはてなブックマークに追加

フォローする