Gunosy Tech Blog

Gunosy Tech Blogは株式会社Gunosyのエンジニアが知見を共有する技術ブログです。

Datadog Agentがkubeletと疎通できなくてもAWS IMDSv2からhostnameを取得させる

こんにちは。プロダクト開発部 Ads チームの johnmanjiro です。普段は広告配信の API や管理画面を開発しています。

先日、EKS 上で動いている Datadog Agent のバージョンを更新した際、Pod の起動時に複数回 Restart するという事象が発生しました。この記事では、その際に発生した問題とその解決策について紹介します。

また、今回の調査には Datadog のサポートにもご協力いただきました。ありがとうございます。

Datadog Agent のバージョンアップ

前提として、Ads チームが管理しているプロダクトはすべて EKS 上で動作し、Datadog Agent を使用してモニタリングを行っています。Datadog Agent は EKS の各 Node 上で DaemonSet として動作します。

また、Datadog Agent を含む Kubernetes 向けのツールは helmfile で管理しており、バージョンアップに関しても helmfile で行なっています。

今回は、Datadog Agent の helm chart のバージョンを 2.37.9 から 3.2.2 に更新しました。appVersion としては 7.38.2 から 7.40.1 に更新していることになります。

起動時に Restart する問題の発生

バージョンアップ後、一時は正常に動作しているように見えましたが、しばらくすると一部の Pod の起動時に複数回の Restart が発生してしまいました。一度正常に起動した後は問題なく稼働していましたが、新しく起動する Pod のうち一部が不定期に Restart してしまうという状況が続きました。

Restart した Pod で前回の agent コンテナのログを見てみると、以下のようなエラーが出ていました。

Error while getting hostname, exiting: unable to reliably determine the host name. You can define one in the agent config file or in your hosts file Error: Error while getting hostname, exiting: unable to reliably determine the host name. You can define one in the agent config file or in your hosts file

このエラーから、agent コンテナの起動時に hostname が取得できずに起動に失敗しているということがわかりました。 調べたところ、Datadog Agent は 7.40.0 から kubelet から hostname を取得しようとし、取得できない場合には起動に失敗するようになっていました*1

関連する issue を調べ、以下のように DD_HOSTNAME 環境変数に nodeName を指定するなどを試しましたが、今度は別の Warning が出力されたため、根本の解決には至らず切り戻しました。

env:
  - name: DD_HOSTNAME
    valueFrom:
      fieldRef:
        fieldPath: spec.nodeName

後ほどサポートに確認したのですが、EC2 環境においては ip-10-126-85-146 のような IP アドレスベースの名前になってしまい、この形式の名前は複数のインスタンス間で重複する可能性があるため、hostname として使用することは推奨されないとのことでした。

原因の調査

仮説

エラーと Restart 時の状況を調べていくと、どうやらスケーリングによって Node が新しくスケジューリングされた際に、新しい Node に配置される Datadog Agent で発生しているということがわかりました。 このことから、Node がスケジュールされたばかりで kubelet がまだ起動中の状態のときに hostname を取得しに行こうとしているのではないかという仮説が立ちました。

しかし、kubelet への疎通ができない場合にはすぐエラーで落ちてしまうことや、agent コンテナの kubelet へのアクセス自体を遅らせることができないことから、自力での調査を断念して Datadog のサポートチケットを切りました。

DEBUG ログの確認

サポートに問い合わせたところ、hostname を解決する際のログは基本的に DEBUG レベルで出力されるため、DEBUG レベルでコンテナの起動からエラーにより終了するまでのログを取得することを勧めていただきました。

実際に DEBUG レベルのログを取得したところ、仮説通り kubelet との疎通に失敗していることを確認できました。

Failed to reach Kubelet at: xx.xx.xx.xx:10255 - error: Get "http://xx.xx.xx.xx:10255/spec": dial tcp xx.xx.xx.xx:10255: connect: connection refused

解決策

この問題は、agent コンテナの環境変数に DD_EC2_PRIORITIZE_INSTANCE_ID_AS_HOSTNAME=true を設定することで解決しました。

通常であれば agent コンテナは kubelet と疎通を確認し、成功した場合には hostname の取得は成功した扱いになります。その後、さらに AWS IMDSv2 からインスタンス ID を取得し、取得できればインスタンス ID を hostname として利用します*2。 しかし、今回は kubelet との疎通に失敗していたため、hostname の取得は失敗と扱われ、AWS IMDSv2 からのインスタンス ID の取得も行われていませんでした。

そこで、 DD_EC2_PRIORITIZE_INSTANCE_ID_AS_HOSTNAME=true を設定することで、kubelet と疎通ができなかった場合にも AWS IMDSv2 からインスタンス ID を取得するようになるとのことでした*3

これを設定した結果、今まで発生していた Restart が発生しなくなり、安定して稼働するようになりました。

まとめ

今回は EKS で稼働している Datadog Agent のバージョンを上げた際に Pod の起動時に複数回 Restart が発生するようになった問題と、その解決策についてご紹介しました。

原因はスケジュールされたばかりの Node で kubelet がまだ起動しきっていない状態で agent コンテナがアクセスしにいっていることでした。 対応として、DD_EC2_PRIORITIZE_INSTANCE_ID_AS_HOSTNAME=true を設定することで、kubelet と疎通できなかった場合にも AWS IMDSv2 から hostname を取得させることができるようになりました。

自分1人で調べていてもこの解決策にはたどりつけなかったと思うので、サポートに問い合わせることの重要性をあらためて感じました。対応していただいたサポートの方には感謝の気持ちでいっぱいです。

この記事が同じ問題に遭遇している方の助けになれば幸いです。