EKS1.24にバージョンアップした時に発生した各種問題について

アソビューでSREを担当している鈴木です。アソビューでは、先日、当社のサービスに利用しているEKSを最新版の1.24までバージョンアップしました。今回は、ここでいくつか問題が発生したので、発生した問題とどう対応したかという話を書きたいと思います。

はじめに

EKS1.24では、Dockershimの依存の排除という内部的には大きな変更が入りました。アプリケーションのレイヤにおいては、ほぼ影響はなかったのですが、インフラの立場においては、想像していたよりも大きな変更でこれに起因する対応が色々と発生してました。当社で発生した問題は、大きくは下記の三つでした。AWSのドキュメントの記載を元にして事前に検出できた問題が1つ、できなかった問題が3つありました。

  • ドキュメントの記載を元にして事前に検出できた問題
    • Dockershimに依存しているアプリケーションの検出
  • ドキュメントの記載を元にして事前に検出できなかった問題
    • DatadogでJMX系のmetricsが取得できなくなった
    • cluster autoscalerが起動に失敗した
    • fluentdでログが送付されなくなった

このあたりを順を追って説明していきたいと思います。

バージョンアップの流れ

まず、AWSのマニュアルをベースにバージョンアップを計画していきました。こちらの手順に従って影響範囲などの調査をしていきました。

docs.aws.amazon.com

各バージョンについての注意事項は、下記のページが参考になりました。

docs.aws.amazon.com

この中でもDockershimの依存が排除されるのが特に重要な変更でした。「Docker ソケット (DDS) の検出器」を使って検出した結果、Datadog Agentが検出されました。なのでまずは、こちらを置き換えることから始めました。

github.com

Datadog Agentの最新化

まず、最初にDockershim依存のないDatadog Agentへの置き換えから始めました。置き換えた結果、ほぼ問題なく動作していたのですが、細かくみていくと、一部のメトリックスが正しく取得できなくなっていることが判明しました。JavaアプリケーションのHeapやGCの情報を取得できるJMX metricsの情報が取得できなくなっていました。そこで、二つのアプローチを試すことにしました。

問題の対応方法1(JMX を使用したオートディスカバリー)

最初に、「JMX を使用したオートディスカバリー」という方法を試しました。 こちらでもメトリックスは、取得できたのですが、外部から取得するという方法のためかruntime-idという情報を一緒に取得することができませんでした。APMから関連情報として閲覧できない状態になってしまうので(下図参照)、この方法は諦めて別の方法で試すことにしました。

問題の対応方法1(Unix ドメインソケット上の DogStatsD)

次に試したのは、「Unix ドメインソケット上の DogStatsD」を利用する方法です。リンク先のページに案内があるように、アプリケーション側のコンテナの設定を下記のようにします。

volumeMounts:
    - name: dsdsocket
      mountPath: /var/run/datadog
      readOnly: true
    ## ...
volumes:
    - hostPath:
          path: /var/run/datadog/
      name: dsdsocket

こちらを追記することで、Dockershimに依存があった時を同じ情報を取得することができるようになったので、こちらの設定でこの問題を解決しました。

評価環境の更新

この段階で、バージョンアップに必要な準備ができたと判断して、実際に評価環境のEKSをバージョンアップしてみました。評価環境のEKSを1.24にバージョンアップ後に2つの問題が発覚しました。こちらは、AWSのドキュメントだけでは気づけなかった問題となります。

cluster-autoscalerが起動しなくなる問題の発生

バージョンアップした後、cluster-autoscalerが動作しなくなってしまいました。Podのログを見ると、IAMの権限が足りないというログが出てました。調べてみると、1.23と比較すると必要な権限の変更がされていました。下記に1.24以降の推奨のIAM設定が記載されているので、その通りに設定することにより、この問題が解消しました。こちらもこれから更新する方は、事前に確認しておくとよさそうです。

github.com

fluentdでログが送信されなくなる問題の発生

もう一つの問題は、fluentdでアプリケーションのログが、送信されなくなってしまったという問題です。調査した結果、このバージョンの間で、下記のログの出力形式がJson形式から変更になっていました。

 /var/log/containers

具体的には、下記のように変更になっていました。

1.23

{
 "log":"2021/12/17 08:03:23 [INFO] 2023-02-02 16:48:11.576  INFO [coupon-service,,] 15 --- [       Thread-4] s.amazon.kinesis.coordinator.Scheduler   : Sleeping ...",
 "stream":"stdout", 
 "time":"2023-02-02T07:48:11.576765119Z" 
}

1.24

2023-02-02T07:48:11.576765119Z stdout F 2023-02-02 16:48:11.576  INFO [coupon-service,,] 15 --- [       Thread-4] s.amazon.kinesis.coordinator.Scheduler   : Sleeping ...

このために、Fluentdのparseに失敗してログの送信がされなくなってしまっていました。 アソビューでは、EKSのバージョンアップをダウンタイムなしで実施したかったので、ログのParserの設定は、バージョンが上がったと同じタイミングで変更する必要があり、ちょっとだけ工夫が必要でした。

その方法を簡単に紹介します。下記のように、fluent.confを二つのバージョン分用意して、自分自身が、どちらのバージョンで動作しているかを判定して適切な設定ファイルを選択するというように実装しました。これにより、ダウンタイムなしでローリングアップデートしながらEKS1.24ヘとあげることができました。

1.23用の設定(ConfigMap)

  fluent.conf: |-
    <match fluent.**>
      @type null
    </match>
    <source>
      @type tail
      @id in_tail_container_logs
      path /var/log/containers/*.log
      pos_file /var/log/fluentd-containers.log.pos
      tag kubernetes.*
      read_from_head true
      <parse>
        @type json
        time_format %Y-%m-%dT%H:%M:%S.%NZ
      </parse>
    </source>
  ....(略)

1.24用の設定(ConfigMap) 今回、JavaのStacktraceなどのマルチラインをまとめたかったのでJava用のParser(in_tail_container_logs)とnginxのログなどそれ以外のParserに分けるために二つのParser(in_tail_container_logs_other)を作っています。

  fluent-1.24.conf: |-
    <label @FLUENT_LOG>
      <match fluent.**>
        @type null
      </match>
    </label>
    <source>
      @type tail
      @id in_tail_container_logs
      path /var/log/containers/*.log
      exclude_path ["/var/log/containers/otherxxxxxxxx*.log", "/var/log/containers/otheryyyyyy*.log", "/var/log/containers/ebs-csi-controller*.log", "/var/log/containers/datadog*.log", "/var/log/containers/fluentd-cloudwatch*.log"]
      pos_file /var/log/fluentd-containers.log.pos
      tag kubernetes.*
      read_from_head true
      <parse>
        @type regexp
        expression /^(?<time>[^ ]+) (?<stream>stdout|stderr) (?<logtag>[^ ]*) (?<log>.*)$/
        time_format %Y-%m-%dT%H:%M:%S.%L%z
      </parse>
    </source>
    <source>
      @type tail
      @id in_tail_container_logs_other
      path /var/log/containers/otherxxxxxxxx*.log, /var/log/containers/otheryyyyyy*.log
      pos_file /var/log/fluentd-containers-nginx.log.pos
      tag kubernetes.*
      read_from_head true
      <parse>
        @type cri
      </parse>
    </source>
    <filter kubernetes.**>
      @type kubernetes_metadata
    </filter>
    <filter kubernetes.**>
      @type concat
      key log
      multiline_start_regexp /^\d{4}[-/]\d{1,2}[-/]\d{1,2}/
      flush_interval 5
      timeout_label @OUTPUT
    </filter>
    <match kubernetes.**>
      @type relabel
      @label @OUTPUT
    </match>
 (略)

fluentd 側のPodの設定:

          lifecycle:
            postStart:
              exec:
                command:
                - bash
                - -c
                - |
                  if [ ! -e /.dockerenv ] && [ -e /fluentd/etc/base/fluent-1.24.conf ]; then
                    cp /fluentd/etc/base/fluent-1.24.conf /fluentd/etc/fluent.conf
                  else
                    cp /fluentd/etc/base/fluent.conf /fluentd/etc/fluent.conf
                  fi

なお、EKS 1.24かどうかというのは、「/.dockerenv」の存在有無で判定しています。

本番環境の更新

評価環境で色々問題が発覚しましたが、本番環境は、問題なくバージョンアップすることができました。弊社の場合には、EKSアップデート中に、何度かローリングアップデートの失敗→リトライを繰り返すことはありましたが、外向きには、これは障害にならないので、順調に更新されましたと言って良いと思います。現在、アソビューのEKSのノードの数は、100台近くあり、これを1台ずつ順番に更新していきました。時間は、5時間程度かけてゆっくりと更新され、無事本番環境のEKSのバージョンアップが完了しました。

まとめ

EKSのバージョンアップは、色々と安定しないことが多いですが、事前にきちんと準備を行えば、安全に環境を更新できるという点は、運用者にはやさしいなと感じます。このような業務をアソビューのSREでは、行っていますが、そんなアソビューに少しでも興味がある方はぜひこちらもご覧ください!一緒に挑戦していく仲間たちを募集しています。すべての人に、遊びの世界をつなげる次の10年を一緒に創っていきましょう。

www.asoview.com