新規投稿のお知らせを受信されたい方は、サブスクリプションをご登録ください:

年間600時間を削減した1行のKubernetes修正

2026-03-26

4分で読了
この投稿はEnglishおよび한국어でも表示されます。

このコンテンツは自動機械翻訳サービスによる翻訳版であり、皆さまの便宜のために提供しています。原本の英語版と異なる誤り、省略、解釈の微妙な違いが含まれる場合があります。ご不明な点がある場合は、英語版原本をご確認ください。

Terraformの変更を計画し適用するために使用するツールであるAtlantisを、再起動するたびに回復を待つのに30分もかかり、Atlantisが管理するリポジトリについては、プランも適用もインフラの変更もありません。認証情報のローテーションとオンボーディングのために月に約100回の再起動が必要となり、その結果、毎月50時間以上のエンジニアリング作業が中断され、そのたびにオンコールエンジニアが呼び出されていました。

これは最終的には、Atlantisが使用する永続的な量が何百万ものファイルに増えたため、人知れずボトルネックになったKubernetesの安全なデフォルトが原因でした。それを追跡し、1行の変更で修正した方法がこちらです。

不思議に遅い再起動

当社は、計画と適用を処理するAtlantisを使用して、GitLabのマージリクエスト(MR)で数十のTerraformプロジェクトを管理しています。1人のMRだけが一度にプロジェクトを変更できるように、ロックを強制します。

Kubernetes上でシングルトンのStatefulSetとして実行され、Kubernetes PersistentVolume(PV)に依存してディスク上のリポジトリの状態を追跡します。Terraformプロジェクトのオンボードまたはオフボードが必要になったり、Terraformで使用される認証情報が更新されたりする場合、その変更を取り込むためにAtlantisを再起動する必要があります。このプロセスには30分かかることがあります。

再起動の遅さは、最近、Atlantisが使用する永続ストレージのイノードが不足した時点で顕著になり、ボリュームを調整するために再起動を余儀なくされました。Inodeはディスク上の各ファイルおよびディレクトリエントリによって消費され、ファイルシステムに使用できる数はファイルシステムの作成時に渡されるパラメータによって決定されます。Kubernetesプラットフォームによって提供されるCeph永続ストレージの実装は、mkfsにフラグを渡す方法を公開していないため、デフォルト値に従うしかありません。ファイルシステムの拡張が利用可能なイノードを増やす唯一の方法であり、PVを再起動するには、Podの再起動が必要です。

先ほど、アラート期間の延長についてお話しましたが、それは問題を隠蔽するだけで、実際の問題への対応が遅れてしまいます。そこで、なぜ時間がかかるのか、正確に調査することにしました。

不適切な動作

使用するシークレットの変更を適用するためにAtlantisのローリングリスタートを依頼された際、我々はkubectl rollout restart statefulset atlantisを実行しました。これにより、既存のAtlantisポッドは正常に終了し、新しいポッドが起動します。新しいポッドはすぐに表示されますが、実際に見てみると:

$ kubectl get pod atlantis-0
atlantis-0                                                        0/1     
Init:0/1     0             30m

...それでは、何が実現するのでしょうか?当然、最初にチェックするのは、そのポッドのイベントです。これは開始コンテナが実行されるのを待っているので、ポッドイベントがその理由を明らかにするのでしょうか?

$ kubectl events --for=pod/atlantis-0
LAST SEEN   TYPE      REASON                   OBJECT                   MESSAGE
30m         Normal    Killing                  Pod/atlantis-0   Stopping container atlantis-server
30m        Normal    Scheduled                Pod/atlantis-0   Successfully assigned atlantis/atlantis-0 to 36com1167.cfops.net
22s         Normal    Pulling                  Pod/atlantis-0   Pulling image "oci.example.com/git-sync/master:v4.1.0"
22s         Normal    Pulled                   Pod/atlantis-0   Successfully pulled image "oci.example.com/git-sync/master:v4.1.0" in 632ms (632ms including waiting). Image size: 58518579 bytes.

一見正常に見えますが、ポッドのスケジュール設定から実際にinitコンテナの画像を取得するまでの時間がどれだけかかるのでしょうか?残念ながら、Kubernetes自体から取得しなければならないデータは、これだけでした。しかし、実際にポッドを実行するのに時間がかかるのはなぜかを知る必要がありました。

深層学習

Kubernetesでは、各ノードで実行されるkubeletと呼ばれるコンポーネントが、ポッドの作成の調整、永続的なボリュームの実装など、その他多くのことを担当します。Kubernetesチームに在籍していた頃から、kubeletがsystemdサービスとして実行されるので、そのログがKibanaで利用できるはずだとわかっています。ポッドがスケジュールされているため、関心のあるホスト名がわかっており、kubeletからのログメッセージには関連するオブジェクトが含まれているため、atlantisをフィルタリングして、興味のあるログメッセージに絞り込むことができます。

ポッドがスケジュールされた直後にAtlantis PVが搭載されているのがわかりました。また、すべてのシークレットボリュームが問題なく増加することも確認されました。しかし、ログにはまだ大きな未説明のギャップがありました。Cloudflareの調査結果:

[operation_generator.go:664] "MountVolume.MountDevice succeeded for volume \"pvc-94b75052-8d70-4c67-993a-9238613f3b99\" (UniqueName: \"kubernetes.io/csi/rook-ceph-nvme.rbd.csi.ceph.com^0001-000e-rook-ceph-nvme-0000000000000002-a6163184-670f-422b-a135-a1246dba4695\") pod \"atlantis-0\" (UID: \"83089f13-2d9b-46ed-a4d3-cba885f9f48a\") device mount path \"/state/var/lib/kubelet/plugins/kubernetes.io/csi/rook-ceph-nvme.rbd.csi.ceph.com/d42dcb508f87fa241a49c4f589c03d80de2f720a87e36932aedc4c07840e2dfc/globalmount\"" pod="atlantis/atlantis-0"
[pod_workers.go:1298] "Error syncing pod, skipping" err="unmounted volumes=[atlantis-storage], unattached volumes=[], failed to process volumes=[]: context deadline exceeded" pod="atlantis/atlantis-0" podUID="83089f13-2d9b-46ed-a4d3-cba885f9f48a"
[util.go:30] "No sandbox for pod can be found. Need to start a new one" pod="atlantis/atlantis-0"

最後の2つのメッセージは、最終的にポッドが実際に正しく起動するのが確認されるまで、数回ループしました。

そのため、kubeletは、ポッドは移動準備はできていると考えていますが、まだスタートしていず、何かがタイムアウトしています。

欠けている部分

ポッドにある最下位レベルのログでは、何が起こっているのかを示すものではありませんでした。他に注目すべきものは?さて、ハングアップ前の最後のメッセージは、ノードに実装されたPVです。通常、PVに問題が増大している場合(例:他のノードに実装されているため)、それはイベントとして浮上します。しかし、ここではまだ何かが起こっており、掘り下げる必要があるのはPV自体だけです。そこで、Kibanaに接続すると、PV名がユニークなため、検索条件として十分

[volume_linux.go:49] Setting volume ownership for /state/var/lib/kubelet/pods/83089f13-2d9b-46ed-a4d3-cba885f9f48a/volumes/kubernetes.io~csi/pvc-94b75052-8d70-4c67-993a-9238613f3b99/mount and fsGroup set. If the volume has a lot of files then setting volume ownership could be slow, see https://github.com/kubernetes/kubernetes/issues/69699

当初、私はイノードが不足すると言ったのを覚えていますか?つまり、このPVには多くのファイルがあるのです。PVがマウントされている場合、kubeletchgrp -Rを実行して、このファイルシステム全体のすべてのファイルとフォルダのグループを再帰的に変更します。移行に時間がかかるのも不思議ではありません。これは高速ストレージですら大量のエントリーを作成することです!

ポッドのspec.securityContextfsGroup: 1が含まれており、GID 1の下で実行されているプロセスが、ボリューム上のファイルにアクセスできるようにしています。Atlantisは非ルートユーザーとして実行されるため、この設定がないとPVの読み取りや書き込み許可が得られません。Kubernetesはこれを実施する方法として、PV全体に対してマウントされるたびに再帰的に所有権を更新しています。

修正プログラム

これを修正するのは、途方もない作業でした。バージョン1.20以降、Kubernetesはpod.spec.securityContextの追加フィールドをサポートしています。fsGroupChangePolicyというものです。このフィールドのデフォルトはAlwaysで、これがまさにここでの動作となります。別のオプションとして、OnRootMismatchという、PVのルートディレクトリに正しい権限がない場合にのみ権限を変更する機能があります。PV上でファイルがどのように作成されるかを正確に把握していない場合は、fsGroupChangePolicy: OnRootMismatchを設定しないでください。PV内の何もグループを変更してはいけませんことを確認し、そのフィールドを次のように設定しました:

spec:
  template:
    spec:
      securityContext:
        fsGroupChangePolicy: OnRootMismatch

現在は、Atlantisの再起動に約30秒かかるようになり、開始時の30分から短縮しています。

Kubernetesのデフォルト設定は、小容量なら問題ありませんが、データが増えるにつれてボトルネックになる可能性があります。当社では、fsGroupChangePolicyに対するこの1行の変更によって、毎月50時間近くの滞っていたエンジニアリング時間を取り戻すことができました。当社のチームはこの時間をインフラストラクチャの変更が通過するのを待ち、オンコールエンジニアが誤報に対応していたのです。これは、デプロイよりも診断に時間がかかった修正から、年間約600時間が生産的な作業に戻ったことに相当します。

Kubernetesの安全なデフォルトは、小規模で単純なワークロード向けに設計されています。しかし、業務が成長するにつれ、これらは徐々にボトルネックとなる可能性があります。大量の永続的ボリュームのあるワークロードを実行している場合は、このような再帰的な権限変更が静かに再起動時間を食っているかどうかを確認する価値があります。securityContext設定、特にfsGroupfsGroupChangePolicyを監査します。OnRootMismatchはv1.20から利用可能です。

すべての修正が現実的または複雑なものではありません。そして、通常、「なぜシステムがこのように動作するのか?」を考えてみましょう。

インフラストラクチャの問題を大規模にデバッグすることに関心があるなら、当社は募集していますCloudflareコミュニティまたはDiscordに参加して、情報交換しましょう。

Cloudflareは企業ネットワーク全体を保護し、お客様がインターネット規模のアプリケーションを効率的に構築し、あらゆるWebサイトやインターネットアプリケーションを高速化し、DDoS攻撃を退けハッカーの侵入を防ぎゼロトラスト導入を推進できるようお手伝いしています。

ご使用のデバイスから1.1.1.1 にアクセスし、インターネットを高速化し安全性を高めるCloudflareの無料アプリをご利用ください。

より良いインターネットの構築支援という当社の使命について、詳しくはこちらをご覧ください。新たなキャリアの方向性を模索中の方は、当社の求人情報をご覧ください。
KubernetesTerraformプラットフォームエンジニアリングインフラストラクチャSRE

Xでフォロー

Cloudflare|@cloudflare

関連ブログ投稿

2026年3月23日 13:00

Launching Cloudflare’s Gen 13 servers: trading cache for cores for 2x edge compute performance

Cloudflare’s Gen 13 servers double our compute throughput by rethinking the balance between cache and cores. Moving to high-core-count AMD EPYC ™ Turin CPUs, we traded large L3 cache for raw compute density. By running our new Rust-based FL2 stack, we completely mitigated the latency penalty to unlock twice the performance....

2026年2月13日 14:00

Equinixによる古いコードの廃棄:CloudflareにおけるRustサービスのグレースフルリスタート

ecdysisは、ネットワークサービスのダウンタイムアップグレードを可能にするRustライブラリです。Cloudflareは、数百万の接続を5年間保護し、現在はオープンソースとなっています。...

2025年12月22日 14:00

Workersが社内メンテナンススケジュールパイプラインを強化する方法

グローバルネットワークでは、物理的なデータセンターのメンテナンスにリスクが伴います。さらに、複数のデータソースと指標パイプラインに加え、グラフインターフェイスでインフラストラクチャの状態を表示することで、スケーリングの課題を解決しながら、Workers上でサービスを停止させるような保守スケジューラーを構築しました。...