前々から気になっていた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も試してみようと思い追加しています。
それぞれのビルド後のイメージサイズも書いてみました。
- ElasticSearch 314 MB
- Logstash 422 MB
- Kibana 321 MB
- fluentd 125 MB
今回は勉強のためにubuntuのイメージをベースに構築してみましたが、イメージのサイズが大きくなってしまいました。。。
ちなみに、下記まっさらな公式イメージ。Kibanaとか全然違いますね。
-
ElasticSearch公式
153MB -
Logstash公式
206MB -
Kibana公式
89MB -
fluentd公式
v0.12.16で178 MB
DockerHubのAutomated Buildに登録しておく
Docker Composeを実行した際にDockerHubから自動的にイメージを取ってくるようにするため、GitHubのリポジトリをDockerHubに登録しておきます。
これをやっておくと、GitHubの特定のリポジトリの特定のブランチにPushしたタイミングで自動的にDockerHubでイメージがビルドされ保存されるようになります。
方法は、とても簡単で、
- まず、DockerHubにログインします。
- 下記のように"Create"ボタンの右の▼を押して、
- "Create Automated Build"を選択します。
- すでにGitHubアカウントでログインしていたり、ひも付けをおこなっていると、下記のようにリポジトリ一覧が表示されます。
Automated Buildしたいリポジトリを選択します。
- 必要内容を記述して、"Create"ボタンを押します。
これだけで完了です。
Docker Composeで構築する
次にDocker Composeで構築するためのYAMLファイルを作成します。
今回のコンテナの関係は下記の図のようになっています。
赤い矢印についてはコンテナからコンテナへの通信なので、相手のIPアドレスがわからないと通信できません。
そのため、下記のようにlinkオプションで指定してやる必要があります。
links:
- elasticsearch:docker-elasticsearch
これを書いておけば、docker-elasticsearchというホスト名で、elasticsearchのコンテナのIPアドレスが引けるようになります。
(コンテナ内の/etc/hostsにelasticsearchのコンテナのIPアドレスが書かれていました。)
上をふまえて、最終的にDocker Composeに渡すYAMLファイル(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に対応させてビルドしてみることに。
下の方の一行を下記のように修正しました。
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は下記のようにしてみました。
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は下記のようにしました。
<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の準備
- docker machineの起動
$ docker-machine start dev
- docker machineの環境変数をホストマシンに登録
$ eval "$(docker-machine env dev)"
- docker machineにポートフォワーディング
コンテナがたちあがるのは、devというVM上なので、
devというVMのKibanaの5601/tcpポートをVMのホストのMacから繋げられるようにしておきます。
別のターミナルを開いて、下記を入力。
$ ssh docker@$(docker-machine ip dev) -L 5601:localhost:5601
このとき聞かれるパスワードはデフォルトだとtcuserです。 - 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_ID
とAWS_SECRET_ACCESS_KEY
を正しいものに書き換えます。(二か所) - docker composeで起動
$ docker-compose up -d
すると、DockerHubからのイメージのPullが始まり、それが完了するとコンテナが立ち上がります。
tg-agentのconfを書き換えて再起動
自動でtd-agent.confのインスタンスIDを書き換えるようにしていないので、手作業が発生してしまいました
- 先ほどポートフォワーディングしたターミナルはdevのVMにログインしたままになっているので、これで/data_tdagent/td-agent.confを開きます。(viなどで)
- dimensions_valueがi-XXXXXXXXになっている箇所が一つあるので、これを正しいインスタンスIDに書き換えて、保存します。(下記、例)
dimensions_value i-fdb70939
- コンテナを再起動します。Docker Composeを実行したマシンで、下記を実行して、fluentdのコンテナを再起動します。
$ docker-compose restart tdagent
Kibanaで見てみる
- Webブラウザから下記のURLにアクセスします。
http://localhost:5601/
すると、Kibanaが開きます。
しかし、初回だと、まだindexパターンの設定を行っていないので、データをみることはできません。 - indexパターンの設定を行う
まず、"Settings"のメニューを選択します。
続いて、indexのパターンを作成します。
今回Logstashはlogstash-*、fluentdはtdagent-*のindexのフォーマットでデータをInputするように設定しているため、それを入力して作成します。
"Create"ボタンが緑色にならず、押せなかった場合はまだデータがInputされていません。
- データを確認する
"Discover"を選択し、先ほど作成したindexパターンを選択します。
すると、図のようにデータのInputのグラフと、実際のパラメータが表示されるので確認できます。
- グラフ化
Visualizeでグラフの作成が可能です。そして、それをDashboardで自由に表示できます。
(ここについては割愛します)
dockerの終了
- docker composeで終了
$ docker-compose stop
- docker machineの終了
$ docker-machine stop dev
- dockerホストのVMも削除する場合は
$ docker-machine rm dev
最後に
これで、どこでもワンボタンで構築できるELK(+fluentd)の環境を作ることができました。
(ちなみに、まだProxy環境下ではテストしていないので動かないかもです。)
ちなみに、今回はCloudWatchの統計データ取得を試しにやりましたが、AWSのACCESS_KEYを登録するだけでいい、SaaSのサービスの方が相当楽ですね
またGrafanaだと、CloudWatchが正式にサポートされているそうです。
GrafanaでCloudWatch見る(接続設定編)
まあ、そもそも最大表示間隔が2週間でよければ、2015年10月に発表されたCloudWatch Dashboardsで十分なのですが。