AWS
Elasticsearch
Docker
docker-compose
docker-machine

ELK(ElasticSearch, Logstash, Kibana)+fluentdの環境をDocker Composeで構築しつつ、試しにCloudWatchの統計データを収集してみた

More than 3 years have passed since last update.

前々から気になっていたELK(ElasticSearch, Logstash, Kibana)の環境をDocker Composeを使ってどこにでも簡単に構築できるようにしてみました。

また、Logstashやfluentdのプラグインを使ったデータ収集と可視化も試してみようと思い、試しにAWSのCloudWatchの統計データを収集してみました。


環境

今回試した環境と、ツール類のバージョンは下記のとおりです。

環境
バージョンなど

OS
EI Capitan(10.11.1)

ElasticSearch
2.0.0

Logstash
2.0.0

Kibana
4.2.0

td-agent
0.12.12

Docker Engine
1.8.3

Docker Machine
0.4.1

Docker Compose
1.4.2

表のDockerについて。。。


  • Engineはいわゆる普通のDocker。Dockerの実行環境です。

  • MachineはローカルやAWSなどの別環境にDockerのホストマシンを構築するツール。

    通常、MacやWindowsでDockerを使う場合は、このMachineを用いて、ローカルのVirtualBoxにDockerホストのVMを作って、それに対して、dockerコマンドを実行していきます。

  • Composeは複数のコンテナのパラメータをYAMLファイルに記述しておいて、ワンボタンで環境構築するものです。


はじめにdockerの環境を整えておく

Dockerで構築しておくと何度も同じインストール作業をしなくてよくなります。

MacだとDocker Toolboxをインストールすれば、Docker Engine, Machine, Composeの準備がすべて整います。

https://docs.docker.com/mac/step_one/

homebrew caskが使える場合は、下記でもインストールできます。

(私はこちらでやりました)

$ brew cask install dockertoolbox

インストールが終わったら、Dockerのホストが動作するVMをVirtualBoxに作成しておきます。

今回devという名前で作成しました。

$ docker-machine create -d virtualbox dev

Windows10でもDocker Toolboxをインストールして試してみましたが、Macと同じようにできました。

(ターミナルにはcygwinを使用しました)


それぞれのコンテナを作る


それぞれのDockerfile

今回作ったものは、下記になります。GitHubのリポジトリとして登録しています。

ELKに合わせてfluentdも試してみようと思い追加しています。

それぞれのビルド後のイメージサイズも書いてみました。

今回は勉強のためにubuntuのイメージをベースに構築してみましたが、イメージのサイズが大きくなってしまいました。。。:sweat:

ちなみに、下記まっさらな公式イメージ。Kibanaとか全然違いますね。


DockerHubのAutomated Buildに登録しておく

Docker Composeを実行した際にDockerHubから自動的にイメージを取ってくるようにするため、GitHubのリポジトリをDockerHubに登録しておきます。


これをやっておくと、GitHubの特定のリポジトリの特定のブランチにPushしたタイミングで自動的にDockerHubでイメージがビルドされ保存されるようになります。

方法は、とても簡単で、


  1. まず、DockerHubにログインします。

  2. 下記のように"Create"ボタンの右の▼を押して、
    dockerhub1.png

  3. "Create Automated Build"を選択します。
    dockerhub2.png

  4. すでにGitHubアカウントでログインしていたり、ひも付けをおこなっていると、下記のようにリポジトリ一覧が表示されます。

    Automated Buildしたいリポジトリを選択します。
    dockerhub3.png

  5. 必要内容を記述して、"Create"ボタンを押します。
    dockerhub4.png

これだけで完了です。


Docker Composeで構築する

次にDocker Composeで構築するためのYAMLファイルを作成します。

今回のコンテナの関係は下記の図のようになっています。

Pasted_Image_11_7_15__9_54_PM.png

赤い矢印についてはコンテナからコンテナへの通信なので、相手のIPアドレスがわからないと通信できません。

そのため、下記のようにlinkオプションで指定してやる必要があります。

  links:

- elasticsearch:docker-elasticsearch

これを書いておけば、docker-elasticsearchというホスト名で、elasticsearchのコンテナのIPアドレスが引けるようになります。

(コンテナ内の/etc/hostsにelasticsearchのコンテナのIPアドレスが書かれていました。)

上をふまえて、最終的にDocker Composeに渡すYAMLファイル(docker-compose.yml)は下記のようにしました。


docker-compose.yml

# elasticsearch

elasticsearch:
image: khiraiwa/docker-elasticsearch:1.0.0
volumes:
- /data_elasticsearch:/data_elasticsearch
ports:
- "9200:9200"
- "9300:9300"

# kibana
kibana:
image: khiraiwa/docker-kibana:1.0.0
volumes:
- /data_kibana:/data_kibana
ports:
- "5601:5601"
links:
- elasticsearch:docker-elasticsearch

# logstash
logstash:
image: khiraiwa/docker-logstash:1.0.0
volumes:
- /data_logstash:/data_logstash
links:
- elasticsearch:docker-elasticsearch
environment:
- AWS_ACCESS_KEY_ID=dummy
- AWS_SECRET_ACCESS_KEY=dummy

# tdagent
tdagent:
image: khiraiwa/docker-tdagent:1.0.0
volumes:
- /data_tdagent:/etc/td-agent
links:
- elasticsearch:docker-elasticsearch
environment:
- AWS_ACCESS_KEY_ID=dummy
- AWS_SECRET_ACCESS_KEY=dummy


(GitHubにあげておきました。

https://github.com/khiraiwa/compose-elk/blob/5694e5c09b9e679b674d4a916582802f24d6e855/docker-compose.yml)


CloudWatchの統計データを取得してみる

動作確認のため、LogstashやfluentdのコンテナでCloudWatchの統計データをInputして、ElasiticSearchのコンテナにOutputするようにしてみました。


Logstash

検索すると、下記のInputプラグインが見つかりました。

logstash-input-cloudwatch

今回はこれを使ってみることに。

しかし、問題があり、logstash-input-cloudwatch.gemspecに書かれているlogstashの対応バージョンは1.4.0以上2.0.0未満でした。

そこで、とりあえず、これを2.0.0に対応させてビルドしてみることに。

下の方の一行を下記のように修正しました。


logstash-input-cloudwatch.gemspec

  s.add_runtime_dependency "logstash-core", '>= 1.4.0', '<= 2.0.0'


そして下記のコマンドでビルド。


$ [logstashへのパス]/vendor/jruby/bin/gem build logstash-filter-awesome.gemspec

すると、logstash-input-cloudwatch-0.2.2.gemが出来上がったので、下記でインストール。


$ [logstashへのパス]/bin/plugin install /your/local/plugin/logstash-filter-awesome.gem

今回のDockerイメージでは、Dockerfileにてビルド済みファイルをADDしてインストールするようにしています。

Outputのプラグインの追加インストールは必要なく、デフォルトでElasticSearchにOutputできます。

logstash.confは下記のようにしてみました。


logstash.conf


input {
cloudwatch {
tag_name => "Name"
tag_values => "*"
region => 'us-west-2'
interval => 900
period => 60
namespace => 'AWS/EC2'
metrics => [ 'CPUCreditUsage','CPUCreditBalance','CPUUtilization','DiskReadOps','DiskWriteOps','DiskReadBytes','DiskWriteBytes','NetworkIn','NetworkOut','StatusCheckFailed','StatusCheckFailed_Instance','StatusCheckFailed_System' ]
statistics => [ 'SampleCount', 'Average', 'Minimum', 'Maximum', 'Sum' ]
}
}

output {
elasticsearch { hosts => 'docker-elasticsearch:9200' }
stdout { codec => rubydebug }
}


inputのcloudwathではnamespaceがAWS/EC2の統計データを取得するようにしています。

outputではelasticsearchへの出力と標準出力を行っています。

elasticsearchのhostsにはdocker-elasticsearchという値を設定しているので、/etc/hostsにより名前解決されます。

実行してみたところ正しく動作し、ElasticSearchには下記のような形でInputされていました。(CPUUtilizationのもの)

{

"_index": "logstash-2015.11.04",
"_type": "logs",
"_id": "AVDSjQcXo0IJOX5JTEN8",
"_score": null,
"_source": {
"timestamp": "2015-11-04 12:43:00 +0000",
"sample_count": 5,
"unit": "Percent",
"minimum": 0,
"maximum": 0.17,
"sum": 0.17,
"average": 0.034,
"@version": "1",
"@timestamp": "2015-11-04T12:43:00.000Z",
"metric": "CPUUtilization",
"instance": "i-fdb70939",
"Name": "Test"
},
"fields": {
"@timestamp": [
1446640980000
]
},
"sort": [
"43"
]
}

このプラグイン、試してみたところ、tag_valuesのところにワイルドカードを指定可能なようで、なかなか便利でした。

※本来、Logstashの2.0.0には対応していなかったはずなのでちょっと心配ですが。。。


fluentd

こちらも探してみるとInputのプラグインとして下記が見つかりました。

fluent-plugin-cloudwatch

また、ElasticSearchへのOutputにも別途プラグインの追加が必要です。

fluent-plugin-elasticsearch

これらはDockerfile中でインストールするようにしています。

tdagent.confは下記のようにしました。


tdagent.conf


<source>
type cloudwatch
tag cloudwatch.ec2

aws_key_id YOUR_AWS_KEY_ID
aws_sec_key YOUR_AWS_SECRET_KEY

cw_endpoint monitoring.us-west-2.amazonaws.com

namespace AWS/EC2
metric_name CPUCreditUsage,CPUCreditBalance,CPUUtilization,DiskReadOps,DiskWriteOps,DiskReadBytes,DiskWriteBytes,NetworkIn,NetworkOut,StatusCheckFailed,StatusCheckFailed_Instance,StatusCheckFailed_System,
dimensions_name InstanceId
dimensions_value i-XXXXXXXX
statistics Average
period 300
interval 300
</source>

<source>
type cloudwatch
tag cloudwatch.billing

aws_key_id YOUR_AWS_KEY_ID
aws_sec_key YOUR_AWS_SECRET_KEY

cw_endpoint monitoring.us-east-1.amazonaws.com

namespace AWS/Billing
metric_name EstimatedCharges
dimensions_name Currency
dimensions_value USD
statistics Average
interval 7200
period 21600
</source>

<match cloudwatch.**>
type elasticsearch
host docker-elasticsearch
port 9200
index_name fluentd
type_name fluentd
logstash_format true
logstash_prefix tdagent
request_timeout 5s # defaults to 5s
reload_connections true # defaults to true

# Buffered output options
buffer_type memory
flush_interval 60
retry_limit 17
retry_wait 1.0
num_threads 1
</match>


まず、一つ目のsourceではlogstashの時と同じくAWS/EC2のものを、二つ目のsourceではAWS/Billingを取るようにしています。

AWS/Billingは現時点の請求額です。

AWS/Billingのnamespaceの統計データを取るには、あらかじめ下記の設定が必要です。

https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/DeveloperGuide/monitor_estimated_charges_with_cloudwatch.html

Outputについて、Logstashのときと同様にelasticsearchのhostにはdocker-elasticsearchを設定しているので、/etc/hostsにより名前解決されます。

実行してみたところ正しく動作し、ElasticSearchには下記のようにインプットされていました。

{

"_index": "tdagent-2015.11.04",
"_type": "fluentd",
"_id": "AVDSmNVAo0IJOX5JTEYl",
"_score": null,
"_source": {
"CPUUtilization": 0.032,
"@timestamp": "2015-11-04T12:53:00+00:00"
},
"fields": {
"@timestamp": [
1446641580000
]
},
"sort": [
1446641580000
]
}

ちなみに、Logstashで使えたようなワイルドカードは使えないようだったので、とりあえずtdagent.confのdimensions_valueをi-XXXXXXXXとしています。

(実行時に修正して、td-agentのコンテナを再起動する必要あり。。。)


実際に構築してみる

一連の手順を詳しく書くと長いように感じますが、実際に入力するdocker-composeのコマンドはとてもシンプルです。


dockerの準備


  1. docker machineの起動

    $ docker-machine start dev

  2. docker machineの環境変数をホストマシンに登録

    $ eval "$(docker-machine env dev)"

  3. docker machineにポートフォワーディング

    コンテナがたちあがるのは、devというVM上なので、

    devというVMのKibanaの5601/tcpポートをVMのホストのMacから繋げられるようにしておきます。

    別のターミナルを開いて、下記を入力。

    $ ssh docker@$(docker-machine ip dev) -L 5601:localhost:5601

    このとき聞かれるパスワードはデフォルトだとtcuserです。

  4. docker composeのリポジトリをclone

    $ git clone -b 1.0.0 git@github.com:khiraiwa/compose-elk.git

    $ cd compose-elk

    docker-compose.ymlのAWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYを正しいものに書き換えます。(二か所)

  5. docker composeで起動

    $ docker-compose up -d

    すると、DockerHubからのイメージのPullが始まり、それが完了するとコンテナが立ち上がります。


tg-agentのconfを書き換えて再起動

自動でtd-agent.confのインスタンスIDを書き換えるようにしていないので、手作業が発生してしまいました :sweat:


  1. 先ほどポートフォワーディングしたターミナルはdevのVMにログインしたままになっているので、これで/data_tdagent/td-agent.confを開きます。(viなどで)

  2. dimensions_valueがi-XXXXXXXXになっている箇所が一つあるので、これを正しいインスタンスIDに書き換えて、保存します。(下記、例)


    dimensions_value i-fdb70939


  3. コンテナを再起動します。Docker Composeを実行したマシンで、下記を実行して、fluentdのコンテナを再起動します。


    $ docker-compose restart tdagent



Kibanaで見てみる


  1. Webブラウザから下記のURLにアクセスします。

    http://localhost:5601/

    すると、Kibanaが開きます。

    しかし、初回だと、まだindexパターンの設定を行っていないので、データをみることはできません。

  2. indexパターンの設定を行う

    まず、"Settings"のメニューを選択します。
    kibana1.png
    続いて、indexのパターンを作成します。

    今回Logstashはlogstash-*、fluentdはtdagent-*のindexのフォーマットでデータをInputするように設定しているため、それを入力して作成します。
    "Create"ボタンが緑色にならず、押せなかった場合はまだデータがInputされていません。
    kibana2.png

  3. データを確認する

    "Discover"を選択し、先ほど作成したindexパターンを選択します。

    すると、図のようにデータのInputのグラフと、実際のパラメータが表示されるので確認できます。
    kibana3.png

  4. グラフ化

    Visualizeでグラフの作成が可能です。そして、それをDashboardで自由に表示できます。
    (ここについては割愛します)


dockerの終了


  1. docker composeで終了

    $ docker-compose stop

  2. docker machineの終了

    $ docker-machine stop dev

  3. dockerホストのVMも削除する場合は

    $ docker-machine rm dev


最後に

これで、どこでもワンボタンで構築できるELK(+fluentd)の環境を作ることができました。

(ちなみに、まだProxy環境下ではテストしていないので動かないかもです。)

ちなみに、今回はCloudWatchの統計データ取得を試しにやりましたが、AWSのACCESS_KEYを登録するだけでいい、SaaSのサービスの方が相当楽ですね:sweat:

またGrafanaだと、CloudWatchが正式にサポートされているそうです。

GrafanaでCloudWatch見る(接続設定編)

まあ、そもそも最大表示間隔が2週間でよければ、2015年10月に発表されたCloudWatch Dashboardsで十分なのですが。