2019年7月17日水曜日

docker の fluentd ドライバで stdout と stderr を別々に扱う方法

概要

docker の fluentd ドライバで stdout と stderr を別々のタグで扱う方法を紹介します
実際に stdout と stderr に出力するアプリを作成し試しています

環境

  • macOS 10.14.5
  • docker 18.09.2
  • fluentd 1.3.2
    • rewrite-tag-filter 2.2.0

stdout と stderr にそれぞれ出力するアプリの作成

Sinatra で作成します
ここはそれぞれに出力できるのであれば何でも OK です

  • bundle init
  • vim Gemfile
gem "sinatra"
  • bundle install --path vendor
  • vim app.rb
require 'sinatra/base'
require 'logger'

class MyApp < Sinatra::Base
  configure do
    unless ENV['LOCAL'] == "true"
      $stdout = IO.new(IO.sysopen("/proc/1/fd/1", "w"), "w")
      $stdout.sync = true
      STDOUT = $stdout
    end
    set :ologger, Logger.new(STDOUT)
    set :elogger, Logger.new(STDERR)
  end

  get '/stdout' do
    settings.ologger.info("stdout")
    'stdout'
  end

  get '/stderr' do
    settings.elogger.info("stderr")
    'stderr'
  end
end
  • vim config.ru
require './app.rb'
run MyApp

こんな感じです
Ruby アプリの場合 stdout は少し工夫が必要なのでそれを入れています
動作確認としては stdout と stderr だけに表示するように実行してみましょう

  • LOCAL=true bundle exec rackup config.ru 2> /dev/null
  • LOCAL=true bundle exec rackup config.ru > /dev/null

上が stdout のみで下が stderr のみ表示する実行方法です

Dockerfile

次に作成したアプリを docker 上で動作するようにします

  • vim Dockerfile
FROM ruby

ADD . /home
WORKDIR /home
RUN gem install bundler
RUN bundle install --path vendor
EXPOSE 9292

CMD ["bundle", "exec", "rackup", "config.ru", "-o", "0.0.0.0"]
  • docker build -t myapp .

これでイメージを作成します

fluentd コンテナの作成

まずは fluentd コンテナから立ち上げます
今回の目的は作成した Sinatra アプリの stdout と stderr を fluentd で別々に扱うことです
なので fluent.conf をそのように記載する必要があります
ポイントは rewrite_tag_filter を使って stdout と stdout に対して別々のタグを付与する必要がある点です

  • mkdir fluentd
  • cd fluentd
  • vim fluent.conf
<source>
  @type forward
</source>

<match docker.myapp>
  @type rewrite_tag_filter 
  <rule>
    key source
    pattern /^stdout$/
    tag out.${tag}
  </rule>
  <rule>
    key source
    pattern /^stderr$/
    tag err.${tag}
  </rule>
</match>

<match out.docker.myapp>
  @type stdout
</match>

<filter err.docker.myapp>
  @type record_transformer
  <record>
    hostname "#{Socket.gethostname}"
  </record>
</filter>

<match err.docker.myapp>
  @type stdout
</match>

record-transformer はテスト用に使っています
stderr にだけフィールドを追加して出力しています
デフォルトの fluetd イメージには rewrite-tag-filter プラグインが含まれてないのでプラグインをインストールしたイメージを作成します

  • vim Dockerfile
FROM fluent/fluentd

RUN apk add --update --virtual .build-deps \
        sudo build-base ruby-dev \
 && sudo gem install \
        fluent-plugin-rewrite-tag-filter \
 && sudo gem sources --clear-all \
 && apk del .build-deps \
 && rm -rf /var/cache/apk/* \
           /home/fluent/.gem/ruby/2.4.0/cache/*.gem
  • docker build -t myfluentd .

これで fluentd コンテナを起動しましょう

  • docker run -d -p 24224:24224 -p 24224:24224/udp -v $(pwd)/fluent.conf:/fluentd/etc/fluent.conf -e FLUENTD_CONF=fluent.conf --name=fluentd myfluentd
  • docker logs -f fluentd

アプリコンテナの起動

ではアプリコンテナを起動しましょう
コンテナを起動する際にロギングドライバに fluentd を指定しましょう
またタグは docker.myapp にします

  • docker run -d --log-driver=fluentd --log-opt fluentd-address=192.168.128.100:24224 --log-opt tag="docker.myapp" -p 9292:9292 myapp

動作確認

fluentd コンテナのログを見ておきましょう
そしてアプリの stdout, stderr にアクセスしましょう

  • curl localhost:9292/stdout
  • curl localhost:9292/stderr

すると以下のように source -> stderr なログにだけ hostname というフィールドが追加されていることがわかると思います

2019-07-17 00:10:43.000000000 +0000 out.docker.myapp: {"source":"stdout","log":"I, [2019-07-17T00:10:43.723529 #1] INFO – : stdout","container_id":"9000f9bafa59b2de3d857ebba520caa76143c1d54bb006d63d92e77318bfa448","container_name":"/gifted_thompson"} 2019-07-17 00:10:43.000000000 +0000 err.docker.myapp: {"source":"stderr","log":"172.17.0.1 - - [17/Jul/2019:00:10:43 +0000] \"GET /stdout HTTP/1.1\" 200 6 0.0262","container_id":"9000f9bafa59b2de3d857ebba520caa76143c1d54bb006d63d92e77318bfa448","container_name":"/gifted_thompson","hostname":"7d6a67bf27a1"} 2019-07-17 00:11:01.000000000 +0000 err.docker.myapp: {"container_id":"9000f9bafa59b2de3d857ebba520caa76143c1d54bb006d63d92e77318bfa448","container_name":"/gifted_thompson","source":"stderr","log":"I, [2019-07-17T00:11:01.546225 #1] INFO – : stderr","hostname":"7d6a67bf27a1"} 2019-07-17 00:11:01.000000000 +0000 err.docker.myapp: {"source":"stderr","log":"172.17.0.1 - - [17/Jul/2019:00:11:01 +0000] \"GET /stderr HTTP/1.1\" 200 6 0.0009","container_id":"9000f9bafa59b2de3d857ebba520caa76143c1d54bb006d63d92e77318bfa448","container_name":"/gifted_thompson","hostname":"7d6a67bf27a1"}

最後に

ポイントは rewrite-tag-filter を使って stdout と stderr を一旦受け取った上で再度タグ付けをする点でした
今回は 1 つのコンテナのログのみ対応しましたが他にも stdout と stderr を別々に扱いたい場合は docker.myapp のように別のタグの match を定義すれば OK です

参考サイト

0 件のコメント:

コメントを投稿