VPS 上のdockerのログをAmazon CloudWatchに出力する
Dockerで実運用していて悩ましいのが「ログの管理」です。従来のサーバ管理のようにログをファイルに出力させる管理方法でもよいのですが、今回はAmazon CloudWatch(以降CloudWatchと記します)にDockerのログを出力するように設定する方法をご紹介します。
CloudWatchは、Amazon Web Services(AWS)から提供されているモニタリングサービスで、ログを収集するだけでなくCPUやネットワークトラフィックなどのリソースをリアルタイムで監視する機能を持っています。
今回はリソースのモニタリングではなく、Webサーバ・データベースサーバのログ収集を目的とします。
CloudWatchへのログ出力はAWSのリソースからしかできないわけではなく、今回の例のように他のVPSやオンプレミスサーバからもログを出力することができます。
構成
次のようなシステム構成でDockerを稼働させる前提です。
- VPS:KAGOYA CLOUD VPS
- ホストOS:Fedora CoreOS
- Dockerの制御:Docker Compose を使用
- Dockerコンテナ:php-apache, mysql
VPSでFedora CoreOS、Dockerを動かす手順は次の記事を参考にしてください。
事前準備
CloudWatchアクセス用ユーザの作成
CloudWatchを利用するためには、リソース(今回の例ではVPS上のDocker)からCloudWatchにアクセスするためのユーザ(CloudWatchアクセス用ユーザ)を準備する必要があります。
CloudWatchアクセス用ユーザは次の手順で作成します。
Amazon Web Services(AWS)のアカウントは事前に作成しておいてください。
Amazon IAMにログインし、[ユーザーを追加]ボタンをクリックします。
「ユーザー名」を指定(ここでは「cloudwatch_user」とした)し、「AWS 認証情報タイプを選択」は「アクセスキー - プログラムによるアクセス」を選択し[次のステップ: アクセス権限]ボタンをクリックします。
ユーザを追加画面にて「既存のポリシーを直接アタッチ」を選択します。
ポリシーのフィルタに「CloudWatchAgent」を入力して検索し、「CloudWatchAgentServerPolicy」を選択して[次のステップ: タグ]ボタンをクリックします。
タグの追加(オプション)では何も指定せず[次のステップ: 確認]ボタンをクリックします。
「成功」の表示を確認したら、[.csvのダウンロード]ボタンをクリックします。このCSVファイルに「アクセスキー」と「シークレットアクセスキー」が記載されているので大切に保管します。
CSVのダウンロードが終了したら[閉じる]ボタンをクリックします。
CSVファイルは「new_user_credentials.csv」などの名前でダウンロードされます。
ユーザーの一覧に今作成したユーザーが追加されます。
CloudWatchにロググループを作成
CloudWatchダッシュボードに入り、「ロググループ」に移動し、[ロググループを作成]ボタンをクリックします。
ロググループ名(ここでは「KAGOYA_web」とした)と保存期間(ここでは「1週間」を指定)を設定し、[作成]ボタンをクリックします。
作成したロググループが追加されていることを確認します。
CloudWatch Agentのインストール
DockerにはコンテナのログをAWS CloudWatchに送信してくれるロギングドライバーが備わっている様子。
なので、あとはCloudWatchにログを送信する設定をdocker-composeに入れ、認証の設定を行えばCloudWatchでログ収集ができるようになります。
Docker-Composeへの設定
今回はDocker-Composeを使って動かすので、次の例のようにCloudWatchの設定をdocker-compose.ymlに追加します。
例ではMySQLサーバとApache+phpサーバを動かすようにしています。
docker-compose.ymlの設定:「logging」の部分を追加します。
version: "3"
services:
mysql:
build: ./mysql
container_name: "testdb"
hostname: "testdb"
:省略
logging:
driver: awslogs
options:
awslogs-region: "us-west-2"
awslogs-group: "KAGOYA_web"
awslogs-create-group: "true"
tag: "{{.ImageName}}.{{.Name}}.{{.FullID}}"
php-apache:
build: ./php
container_name: "testweb"
hostname: "testweb"
:省略
ports:
- "443:443"
- "80:80"
depends_on:
- mysql
logging:
driver: awslogs
options:
awslogs-region: "us-west-2"
awslogs-group: "KAGOYA_web"
awslogs-create-group: "true"
tag: "{{.ImageName}}.{{.Name}}.{{.FullID}}"
volumes:
db_data:
以下の設定をコンテナ毎に設定します。
- driver:「awslogs」を指定します
- awslogs-region:CloudWatchに作成したリージョンを指定します
- awslogs-group:CloudWatchに作成したロググループを指定します
- awslogs-create-group:「"true"」を指定します
- tag:ログの書式を指定します。例では「{{.ImageName}}.{{.Name}}.{{.FullID}}」を指定しています
※本記事を書いているCMSの都合で最初の波括弧を全角で記載していますが、実際には半角で記載してください。
ACCESS_KEYの設定
このままではCloudWatchを使おうとすると下記のようなエラーが出てしまいます。
ERROR: for testweb Cannot start service php-apache: failed to initialize logging driver: failed to create Cloudwatch log stream: NoCredentialProviders: no valid providers in chain. Deprecated.
For verbose messaging see aws.Config.CredentialsChainVerboseErrors
ERROR: for php-apache Cannot start service php-apache: failed to initialize logging driver: failed to create Cloudwatch log stream: NoCredentialProviders: no valid providers in chain. Deprecated.
For verbose messaging see aws.Config.CredentialsChainVerboseErrors
CloudWatchにアクセスするためのアクセス権限が設定されていないために発生するエラーです。
これを解消するために、ホストOS側(Dockerコンテナではないので注意)の「/etc/sysconfig/docker」に下記設定を追加します。
※DockerのホストOSがRed Hat系ディストリビューションの場合です。Debian/Ubuntu系ディストリビューションの場合は設定するファイルが違うかもしれません。
$ sudo vi /etc/sysconfig/docker
# /etc/sysconfig/docker
vvv ここから追加 vvv
AWS_REGION=us-west-2
AWS_ACCESS_KEY_ID=ABCDEFG〜
AWS_SECRET_ACCESS_KEY=HIJKLMN〜
^^^ ここまで追加 ^^^
# Modify these options if you want to change the way the docker daemon runs
OPTIONS="--selinux-enabled \
:
CloudWatchを設定したAWSのリージョンを「AWS_REGION」に設定します(例では「us-west-2」)。
事前準備でダウンロードしたCSVファイルを開き、中に書かれている「Access Key ID」を「AWS_ACCESS_KEY_ID」へ、「Secret access key」を「AWS_SECRET_ACCESS_KEY」へ設定します。
Dockerデーモンの設定ファイルを再読み込みします。
$ sudo systemctl daemon-reload
CloudWatchダッシュボードを開き、[ログ]-[ロググループ]からdocker-compose.ymlで指定したロググループ(上記の例では「KAGOYA_web」)を参照してログが記録されていることを確認します。