Docker-composeでECS上にコンテナを起動してログ収集・分析基盤(ELK)を構築する
はじめに
公開しているWebアプリケーションのアクセスログを収集したく、ログの収集・分析基盤としてELK環境を構築しました。自前でサーバを立てるのも面倒だったので、AWSとDockerのお勉強がてら、Docker-composeファイルを用意して、ECS上でコンテナを起動し、システムを構築しました。なお、構築時のエラー・トラブルについては別記事でまとめたいと思います。
この記事の対象者
- Elasticsearch, Logstash, Kibana環境をDockerで構築するのが初めて
- ECSを使ったことがなく、docker-compose.ymlからECS上でコンテナを建てたい人
この記事を見てできること
- ECS上でdocker-composeを使って、コンテナを起動できる
- EC2上にELK環境を構築できる(厳密には、ElasticsearchとLogstashのコンテナをEC2上で動かせる)
- アプリケーションからPOSTされたJSONデータをKibanaで可視化できる
システム情報
- Elasticsearch 7.0.0
- Logstash 7.0.0
- Kibana 7.0.0
- docker-compose v2
- EC2 t2.small メモリ2GB (無料枠対象外なのでご注意を)
システム構成
色々試行錯誤した結果、以下のようなシステム構成となりました。
Kibanaをlocalhost上で建てているのは、EC2インスタンスのスペックが低すぎて(2GB)、EC2上でKibanaが起動しなかったためです。自分だけKibanaを見れればよかったので、Kibanaを確認したい時だけ、localhost上にKibanaをデプロイしています。
docker-compose.ymlを使って、ECS上でコンテナを起動
以下の記事が参考になりました。
公式
ローカルで使用したdocker-compose.ymlを使ってECS上でコンテナを起動する
ECS CLIでAmazon ECSを操作してみた
AWS CLIを使用するための初期設定
ECS-CLIをインストール
brew install amazon-ecs-cli
バージョン確認
aws --version
aws-cli/1.16.156 Python/3.7.0 Darwin/18.2.0 botocore/1.12.146
ECS-CLIで使用するAWSの情報を設定
aws configure
AWS Access Key ID [None]: hogehoge
AWS Secret Access Key [None]: hogehoge
Default region name [None]: [リージョン名]
Default output format [None]: json
ここのIDとAccess Keyに何を設定すればいいかが分からない方は、おそらくIAMユーザを作成する必要があります。一旦、以下の公式ページに一通り目を通しましょう。
IAMユーザ作成→IAMユーザーのアクセスキーIDおよびシークレットアクセスキーの取得という手順をふむ必要があります。
※既に作成済みならば読み飛ばしてください。
docker-compose.yml(Logstash, Elasticsearch用)を準備
version: "2"
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:7.0.0
mem_limit: 1g
ports:
- "9200:9200"
- "9300:9300"
environment:
- discovery.type=single-node
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ulimits:
memlock:
soft: -1
hard: -1
nofile:
soft: 65536
hard: 65536
networks:
- elastic-stack
logstash:
image: gogogonkun/logstash_pub
mem_limit: 768m
ports:
- "5044:5044"
environment:
- "LS_JAVA_OPTS=-Xms512m -Xmx512m"
networks:
- elastic-stack
networks:
elastic-stack:
-
Dockerイメージについて
logstashのDockerイメージは、事前に設定ファイルに変更を加えたり、confファイルを仕掛けたかったため、公式のDockerイメージを一部変更したものを使用しています。経緯や詳細はこちらの記事で紹介します。 -
メモリサイズについて
t2.smallインスタンスのメモリが2GBしかないため、mem_limitをそれぞれ1g, 768mと設定して、自重しています。ちなみに2GBを超えてしまうと、コンテナが起動してくれません。 経緯や詳細は上記と同様にこちらの記事で紹介します。
とりあえずローカルで起動
docker-compose up -d
動作確認
$: curl localhost:9200
{
"name" : "77e042e7f49d",
"cluster_name" : "docker-cluster",
"cluster_uuid" : "Ocgt84ZaReWsBhgjzMQUSA",
"version" : {
"number" : "7.0.0",
"build_flavor" : "default",
"build_type" : "docker",
"build_hash" : "b7e28a7",
"build_date" : "2019-04-05T22:55:32.697037Z",
"build_snapshot" : false,
"lucene_version" : "8.0.0",
"minimum_wire_compatibility_version" : "6.7.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}
止める
docker-compose stop
ECSクラスタを起動(t2.smallインスタンスは有料です)
ecs-cli up --keypair KEY_NAME --capability-iam --size 1 --instance-type t2.small
docker-compose.ymlからECS上でコンテナを起動
ecs-cli compose -f docker-compose.yml up
確認
$: ecs-cli ps
Name State Ports TaskDefinition Health
6d644480-39a0-4367-b3ed-ac82b0d630d9/logstash RUNNING xx.xxx.xxx.xxx:5044->5044/tcp ELK:80 UNKNOWN
6d644480-39a0-4367-b3ed-ac82b0d630d9/elasticsearch RUNNING xx.xxx.xxx.xxx:9300->9300/tcp, xx.xxx.xxx.xxx:9200->9200/tcp ELK:80 UNKNOWN
ここまでで、ECS上にコンテナを起動することが出来ました。
少し寄り道... 固定のIPアドレスの取得
アプリケーションからLogstashへログをPOSTする際の送り先、KibanaでElasticsearchからログを取得する際の取得先のIPアドレスが、EC2インスタンスが再起動する度に変わってしまうと、その度にコンテナの設定変更が必要となります。
でもそんなのは面倒なので、EC2インスタンスのIPアドレスを固定します。Elastic IPsでは固定のIPアドレスを取得して、EC2インスタンスに紐づけることができます。
以下の記事を参考に、EC2インスタンスにIPアドレスを紐づけます。
公式
AWS EC2インスタンスにElastic IP(固定グローバルIPアドレス)を割り当てる
docker-compose.yml(Kibana用)を使って、localhost上でコンテナを起動
docker-compose.yml(Kibana用)を準備
version: "2"
services:
kibana:
image: gogogonkun/kibana
mem_limit: 3g
ports:
- "5601:5601"
environment:
- ELASTICSEARCH_URL=http://XX.XXX.XXX.XXX:9200
- ELASTICSEARCH_USER=NAME=kibana
- ELASTICSEARCH_PASSWORD=${ELASTIC_PASSWORD}
-
Dockerイメージについて
EC2インスタンス上に建てたコンテナと同様に、Dockerイメージを一部書き換えております。 -
環境変数について
- ELASTICSEARCH_URL
先ほどElastic IPsで取得したIPアドレスを設定します。 - ELASTICSEARCH_USER=NAME=kibana
Kibanaからインデックスを登録する際に、上手く書き込めなかったため、試行錯誤した結果です。
事象については、以下のリンクをご覧ください。
Kibana Error Connecting to ES on Docker - Cannot Revive Connection
Cannot specify a default index pattern
- ELASTICSEARCH_URL
docker-compose.ymlからlocalhost上でコンテナを起動
$: docker-compose up -d
確認
$: docker-compose ps
Name Command State Ports
-------------------------------------------------------------------------------
kibana_kibana_1 /usr/local/bin/kibana-docker Up 0.0.0.0:5601->5601/tcp
これで、EC2インスタンス上にElasticsearch、Logstashを、Localhost上にKibanaをそれぞれ建てることが出来ました。これで環境構築が完成したかのように思えますが、EC2インスタンスのセキュリティグループを設定していないため、アプリケーションやローカルの端末からEC2で建てているコンテナに接続することが出来ません。
EC2インスタンスのSecurity Groups設定
特定のIPアドレスから、EC2で建てたコンテナの指定したポートに対する接続を許可します。
下の図のようなイメージです。
この記事を参考にします。
【AWS】セキュリティグループを設定してみた(そして関連する用語を調べてみた)
以下のような設定になるかと思います。
3番は動作確認のために、自分のIPアドレスから全てのポートにアクセスできるようにしています。
Protocol | Port Range | Source | |
---|---|---|---|
1 | TCP | 5044 | App IP |
2 | TCP | 9200 | My IP |
3 | TCP | 0 - 65535 | My IP |
上手くいかなかったら、とりあえず動作確認のために、全てのIPアドレスから全てのポートに対する接続を許可してみてから、接続を許可する範囲を狭めていくといいと思います。
※セキュリティホールになるので、最終的にはガバガバ設定にしないでください・・・
動作確認
- Elasticsearch
[EC2コンテナのIPアドレス]:9200 に接続します。
JSONが返却されれば問題ないかと思います。
{
"name" : "77e042e7f49d",
"cluster_name" : "docker-cluster",
"cluster_uuid" : "Ocgt84ZaReWsBhgjzMQUSA",
"version" : {
"number" : "7.0.0",
"build_flavor" : "default",
"build_type" : "docker",
"build_hash" : "b7e28a7",
"build_date" : "2019-04-05T22:55:32.697037Z",
"build_snapshot" : false,
"lucene_version" : "8.0.0",
"minimum_wire_compatibility_version" : "6.7.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}
- Kibana
localhost:5601 に接続します。
画面が表示されるかと思います。
- Logstash
[EC2コンテナのIPアドレス]:5044 に接続します。
ok
※Logstash用のconfファイルが置かれていなければ、何も返却されません。
ちなみに今回は、Logstashがインストールされているコンテナの/usr/share/logstash/pipeline 配下に、以下のようなconfファイルを仕込んでいます。POSTされたJSONデータをそのままElasticsearchにぶち込むconfファイルです。
input {
http {
port => 5044
response_headers => {
"Access-Control-Allow-Origin" => "*"
"Content-Type" => "text/plain"
"Access-Control-Allow-Headers" => "Origin, X-Requested-With, Content-Type, Accept"
}
}
}
output {
elasticsearch {
hosts => "http://[EC2インスタンスのIPアドレス]:9200"
index => "movhis-%{+YYYY.MM}"
}
}
Logstashのコンテナを建てる度に、confファイルをちまちま設定するのが面倒な人は、以下の手順で、自分用のDockerイメージを使用しましょう。
- 公式のDockerイメージを書き換える
- Dockerイメージのコミット
- DockerHubへプッシュ
- docker-compose.ymlでプッシュしたDockerイメージを指定する
※DockerHubへのプッシュまでについてはこちらの記事を確認ください。
logstashにhttpリクエストを投げて、Kibanaから確認してみる
※上記confファイルが設定されている前提の話です。
先ほどの動作確認と同様に、ブラウザ上で[EC2コンテナのIPアドレス]:5044 に接続
次にKibanaからデータが登録されているか確認
データが登録されていることが確認出来ました。
おわりに
ECSを利用してDocker-composeファイルからELKの環境を構築してきました。また、Logstashを通してElasticsearchに登録されたログデータを、Kibanaから確認することも出来ました。
今回はPOSTされたJSONデータをそのまま可視化するだけでしたが、システムのメトリクス・業務のログ等、いろんなログデータを登録して可視化することができます。自分が使いやすいように好きにカスタマイズして遊んでください。
後半は説明が適当になってしまったので、後で見直して、整理したいと思います。特に、ログを可視化できるようになるまで、割とハマったポイントがあったので、別途まとめて紹介したいと思います。
説明が長くなってしまいましたが、改善点やご意見お待ちしております。
ここまで見ていただき、ありがとうございました。