この記事は Supership 株式会社 Advent Calendar 2018の 23 日目の記事です。
今年 Supership に転職していて、業務でログ基盤のリプレースとアプリケーションのリプレースを行っておりFluentdに機能追加のPull Requestを送る機会があったので何ができるようになったのか、どんな問題があったのかをまとめるという趣旨の記事になります。
Fluentd の out_forward とは
Fluentd はデータ転送を行う Ruby で書かれたデータコレクタです。
Fluentd と Fluentd のノード間においてデータ転送を行う際に出力する側のプラグインの名称です。
Fluentd の本体に含まれていて、TCP/UDP のコネクション確立を含めたデータ転送処理を行います。
どのような問題があったか
Fluentd には v0.14.12 から out_forward でのデータ転送時に暗号化処理する機能があります。
それ以前のバージョンでは別途プラグインを導入する必要があり、 tagomoris/fluent-plugin-secure-forward が用いられていました。
私が担当しているログ転送基盤部分では AWS から GCP にグローバルネットワークを介して接続しているため、暗号化処理は必須要件になります。
このような構成の時に AWS 側と GCP 側で事前共有が必要な認証情報の不一致があった場合どのような状態になるでしょうか。
それを知るにはまず Fluentd の out_forward がどのタイミングでコネクションを張るかを知る必要があります。
out_forward では Fluentd プロセスが起動した時に conf によって指定されたノードとの接続を試みません。
デフォルト設定では名前解決を試みて名前解決が行えるかを試しますが***1**、接続は試みません。
そのため実際にログを受け取り、転送する段階になって転送先のノードとコネクションを張ります。
通常の平文でのログ転送においてはリトライが可能なためそこまで多くの問題は生じないでしょう。
もし、誤った認証情報をもった Fluentd がデプロイされたらデータ受け取り転送する段階になって conf の認証情報では繋がらないということが判明します。
一般的なコネクションの問題であれば時間経過によりリカバリーが見込めることもありますが、誤った認証情報というケースにおいては時間経過でリカバリーを待つより異常終了でエラーがあったことが明確になるほうが良いかと思います。
そしてその異常終了のタイミングは Fluentd がデータを受け取る前の段階であると望ましいでしょう。
この件を Fluentd のメーリングリストに相談し、起動時に疎通できなければそのまま Fluentd が異常終了するようにするという verify_connection_at_startup オプションを追加する Pull Request を送りました。
ちなみにこの Pull Request 適用前の Fluentd version 1.3.1 以前では認証情報(Shared key)の不一致の場合は warn レベルで Fluentd のログに出力されるだけで異常終了することはありませんでした。
なぜログを確認する運用にしなかったか
warn レベルでログにエラーがでるということは前述しましたが、運用体制としてログを確認するフローになぜしなかったのかを以下で説明します。
メトリクス監視ツールなどで Fluentd のログを監視して認証情報の不一致が発生していることを監視することも可能でした。
しかし、こちらも前述している通り最も良い解決方法としては起動時に異常終了することであると考えています。
私が担当しているログ転送基盤は属人的でブラックボックスが存在したシステムからの脱却を行っており、アプリケーションからログ転送基盤までを CI/CD による継続的デプロイメント環境へ移行しています。
その一環としてログ転送基盤も Docker コンテナへ移行し自動デプロイが行われる構成へと移行しています。
自動デプロイ環境への移行中の検証で認証情報の不一致があっても Fluentd 起動時に異常終了しないため、自動デプロイの切り戻しが容易ではないことが判明しました。
メトリクス監視ツールなどを使用して Fluentd のログを監視してもログの欠損がない安全な自動切り戻しが難しく起動時に異常終了させたいという思いがありました。
この事情を Fluentd のメーリングリストに相談したところ機能追加が必要だというレスポンスを得て、この機能追加の Pull Request を送ったところマージされて、Fluentd version 1.3.1 よりこの機能が利用できるようになりました。
*1 ignore_network_errors_at_startup 時は DNS の名前解決を行わない