Dockerとログ(クラスタ構成編)

またログの話

前回といってももう半年以上も前になりますが、今回はコンテナクラスタを構築する場合を考えてみます。 ホストを意識しているコンテナではなく、ホストを意識しないコンテナ。

目的をいうと、疎結合、シンプルに、楽にログの収集を実施したいのです。

問題の定義

なぜログについて悩むのか。問題を明確にします。

コンテナとホストを疎結合にしたい

クラスタを構成するうえで、「このホストはnginxとPHPで構成する・・」、みたいなことをしたくない。 インスタンスのリソースが空いているから自由に使え、また自由にスケールできるようにしたい。 ホストの存在を忘れたい。 ログデータをホストとVolumeマウントして何かやる方法がこの問題に違反する。ホストの立場からするとどのコンテナがDocker runされているのか知る必要があり、ログファイルがどこにあるかさえも知っておく必要があるかもしれない。

ログの管理はコンテナに任せたい

コンテナ(コンテナ上で動作しているアプリケーション)が吐いたログはコンテナで管理して欲しい。 結局、1つ目の疎結合の問題と似てしまうのだが、コンテナ外の助けを必要としてしまうと、ログ管理するコンポーネントは、コンテナの情報や仕様を知る必要がある。 これは悪ではないが自分のことは自分でやって欲しい。コンテナの仕様が変わったらログ管理も変更する必要があり、バージョンの違うコンテナが混在したらどうするか?・・ありえない、面倒臭い。

解決する方法案

あくまで参考に。より良い案もあると思う。 Fluentdによるログ解析基盤が既にあったりすればまた違う答えがある気がします。

Amazon Elasticsearch Serviceを使ったログ収集基盤の構成を考えてみた | Ryuzee.com
こちらを例に取ると、全体的にFluentdが標準化されており、素敵な構成だと思います。 解析基盤もそれなりに整っていそうな感触。

Docker Log Driver

コンテナのログはそのコンテナが管理するシンプルな方法として、Docker Log Driverが非常に適当に思える。nginxだと/dev/stdoutaccess.logをリンクさせることでFluentdなりawslogsなりに集約させることができる。ただし例外がありPHP-FPMコンテナの場合は・・使えない。monologが出力するログはサブプロセスで動いているので標準出力に吐かせてどうこうできる感じでは無いっぽい。 php - Docker: Logging From Both App and Server In One Container - Stack Overflow

CloudWatchLogs Agent

phpコンテナのログ出力がLogDriverだけではうまくいかない為、 Supervisorと併用しCloudWatchLogs Agentをコンテナ内で動かすことにしてみました。 コンテナのバージョンがアプリケーションのバージョンに依存してしまいますが、 現時点ではクラスタを組むにはこの方法しかないのではなかろうかというところ。 役目ごとにコンテナを分けたい気分もあります。ローカルで動作させた場合に無駄にAgentも動くので、些細なことですがやや気になるといったところ。

まとめ

単純ですがDocker Log Driverか、使えない場合はコンテナ内にログ集約する役目を持たせる方法がベターかと思います。簡単さでいうと、ホスト側にログの集約機能を持たせるほうが簡単だと思われます。 AWS Beanstalkの簡単さには甘えてしまいますが、Beanstalkはこの簡単な方法がベストマッチします。

ちなみに、CloudWatchLogsありき前提で記載しました。 Managedされているログの集約先なのでぴったり。Aggregatorを自分で構築運用しようとか私は好きではありません。 CloudwatchLogsからESに飛ばしたり、S3に保存したりできるのも素敵です。

Dockerとログ

ログをどう運用するか?

ログは大事だ。Dockerで構築した環境の場合、どのように保存して管理していくか考えてみたい。

方式をリストアップ

選択できるログの運用方法をリストアップしてそれぞれについての利点等を考えてみる。自分が全く知らない方法があるかもしれないがそれはご了承いただきたい。

1. まずアンチパターン

最近久しぶりに目にしたがこちらの記事にも記載があるのだが、ログをそのままコンテナ内に保存するのは当然良くない。

コンテナにデータを保存しない

よほどの自信がある時以外は、Dockerコンテナ内にデータを保存するのはやめましょう。動作中のコンテナを誤って止めてしまうと、そのデータは永遠に失われてしまいます。データを管理するのであれば、共有ディレクトリのあるホストに直接、保存した方が安全ですし簡単です。

ログに関しては、ホストの共有ディレクトリか[logstash](http://logstash.net/)やpapertrailのようなリモートのログ収集サービスを使うといいでしょう。

引用:Dockerにまつわる誤解とベストプラクティスについて

自分はコンテナをストップするとデータは全て消えるものだと勘違いしていたので、そもそもこの選択肢は無いと思っていたというのは余談として、ちゃんとコンテナやDockerホストが壊れてしまったときのことを考えておきましょう。

2. Volumeマウントする方式

この方式は、必要なコンテナ側のログ出力ディレクトリとDockerホスト側のディレクトリをVolumeマウントしておく方法です。 実現には比較的簡単な方法といえるでしょう。ただ、保存しておくログのディレクトリがいっぱいあったりすると面倒な為、Dockerベースとした構築を前提としている場合、アプリケーションを設計するときからこの辺りは少し考慮しておく必要がありそうです。

オンプレミスでサーバーを管理していた頃は、syslog周りもちゃんと把握しておくようなイメージがありましたが、クラウド+Dockerで考えたときにsyslogが全く無いのは困るかもしれませんが、あまり見る機会がなさそうな感じがします。ハードが壊れているとかであれば捨てればいいわけです。ただ、「スケーラブルな設計となっていれば」というのが前提ではありますが。

また大事なのはログをコンテナの外に出すことは簡単ですが、さきほど言ったようにスケーラブルな構成ですとそのホストもいつ死んでも大丈夫なようにもっと安全な場所へ退避しておくことが必要となるでしょう。

AWSならS3に退避したり、Fluentdでログをどこかへ集約したり、この辺りの選択肢は環境によっていろいろありそうです。

3. ログドライバを使う方式

まだちゃんと把握できていない領域。

Docker 公式 Configure logging driver

logオプションをjson-fileを指定すると、docker logs [ContainerID]でログを確認することができるのだが、fluentdオプションが使えるようになったのは確か1.8系から。(というか早すぎて追いつくのが大変)

ログをコンテナ内に保存せず、Fluentdに処理させるといった考え方としては簡単なのだが、どのログにどのタグをつけたりといったことが想像がつかない。 もうちょっとこの辺はまだ深掘りする必要がありそうだし、journaldというキーワードも気になるところ。

4. その他

ここに記載する内容は面白そうだったのでメモしておく程度。実際にやったことがないので利点やら短所などはよくわかりません。

まとめ

  • ちゃんとログ運用を考えないなら、最低限、ログの出力ディレクトリは1つにまとめておく
  • まとめておけばホスト側にマウントして外部へ吸い出す。自作するなら、Fluentdとか使いたくなる。

ログは保守程度であればいうほど見る機会は少ないですが、解析系に使うようになると非常に重要で後々面倒なことにならないように先を見据えた設計にしておきたいですね。