Skip to content

EKSノードのカーネルチューニング ​

対象バージョン: Amazon Linux 2023(カーネル6.1/6.12/6.18)、Kubernetes 1.33以降(Amazon EKS) 最終更新日: September 13, 2026

このドキュメントで扱うこと ​

  • EKSノードで何を変更し、何を既定のままにするか、その判断方法
  • EKSでカーネルパラメーターを適用する実際の経路と、それぞれの落とし穴
  • AL2023のカーネル移行(6.1から6.18)が運用上何を意味するか

まず、ほとんどの設定は変更しない ​

これがこのドキュメントでもっとも重要な助言です。

カーネルの既定値は、幅広いワークロードで妥当に動作するように選ばれています。またTCPバッファーの自動調整など、多くの機能は負荷に応じてカーネルが調整します。根拠のないチューニングには3つのコストがあります。

問題例
再現できない設定ノードごとに値が異なり、障害を再現できない
カーネルアップグレード時の破損6.1で使えた設定が6.18では名前や場所が変わる、または削除される
自動調整を妨げるソケットごとにSO_RCVBUF/SO_SNDBUFを明示すると、そのソケットの自動サイズ調整が無効になる。sysctlの範囲設定は別の制御

チューニングの前提条件は測定です。 次の順序で進めてください。

  1. 症状を特定する(遅延、破棄、スループットなど)
  2. まず破棄カウンターを確認する: conntrack -Sのinsert_failed、tc -s qdiscのdropped、ethtool -SのNIC破棄数
  3. そのカウンターが増加している箇所のパラメーターだけを変更する
  4. 同じ条件で変更前と変更後を測定する
  5. 変更内容と理由をコードとして記録する(以下の適用経路を参照)

測定方法については、Podネットワークベンチマークのフィクスチャを参照してください。

適用経路: EKSでカーネルパラメーターを変更する方法 ​

方法はいくつかあり、それぞれ適用範囲と落とし穴が異なります。 実務では違いを理解することが重要です。

経路適用範囲永続性注意点
ノードのブートストラップ(User Data/nodeadm)ノード全体ノード置換時に再適用AL2023ではnodeadm設定を使う。最も標準的
Bottlerocket設定(settings.kernel.sysctl)ノード全体ノード設定として管理Bottlerocketはイミュータブルなので、この方法だけを使う
PodのsecurityContext.sysctlsPodのnet名前空間だけPod仕様名前空間スコープのsysctlのみ。 多くのnet.*が該当する
特権init DaemonSetノード全体Pod再起動時に再適用よく使われるが、特権が必要(セキュリティレビューの対象)
kube-proxy-config ConfigMapconntrack関連kube-proxyが管理EKSではCLI引数より優先される
KarpenterのEC2NodeClassノードグループノードのプロビジョニング時User Dataを宣言的に管理する

見落としやすい2つの点 ​

1つ目は、名前空間スコープのsysctlと、そうでないsysctlの違いです。 多くのnet.*値はnet名前空間単位で設定できるため、PodのsecurityContext.sysctlsで変更できます。一方、vm.*、fs.*、net.netfilter.nf_conntrack_maxなど一部の値はノード全体に適用され、Pod仕様からは変更できません。

また、kubeletは既定では「unsafe」sysctlを拒否します。必要な場合は、ノード設定で--allowed-unsafe-sysctlsを明示的に許可します。

2つ目は、kube-proxyがconntrack設定を上書きすることです。 コンテナを支えるカーネル機能で触れましたが、実務でよく遭遇する落とし穴なので繰り返します。EKSでは既定でkube-proxy-config ConfigMapが用意され、コマンドライン引数より優先されます。ブートストラップでsysctlを引き上げても、kube-proxyが元に戻す場合があります。

要確認

Bottlerocketでは、settings.kernel.sysctlでconntrackの上限を引き上げても反映されないという報告があります(2024年9月に報告されたbottlerocket-os/bottlerocket#4221)。原因はkube-proxy設定ファイル(/var/lib/kube-proxy-config/config)がコマンドライン引数より優先されることです。

kube-proxyの設定ファイルを使う場合、上限管理をノードのsysctlへ意図的に委ねるには、設定内のconntrack.maxPerCore/conntrack.minフィールドを変更します。両方を0に設定しても、--configに無視されるCLIフラグへ依存してよい理由にはなりません。適用前にマネージドアドオンによる再調整とメモリの余裕を確認してください。

特定のBottlerocketリリースで解決済みかどうかは確認できませんでした。 どの経路を使っても、適用後にノード上の実際の値を確認してください。

bash
# Check the actually applied values on the node
cat /proc/sys/net/netfilter/nf_conntrack_max
cat /proc/sys/net/netfilter/nf_conntrack_count
conntrack -S | head

カーネルバージョン: AL2023の6.1から6.18への移行 ​

現在、把握しておくべき変更です。

日付内容
2023年3月カーネル6.1を搭載したAL2023をリリース
2025年4月カーネル6.12のサポートを追加
2026年8月17日al2023-ami-kernel-default AMIの既定カーネルを6.1から6.18に変更

ここから2つの点が導かれます。

既定カーネルのAMIファミリーは変更されましたが、ノードの置換時には起動テンプレートまたはプロビジョニングポリシーで選択したAMIが使われます。AMI IDを固定している場合、新しいノードを起動しただけではカーネルは変わりません。latest/defaultを再取得する設定では、新しいカーネルが選ばれる可能性があります。EKS最適化AMIには独自のリリース選択があります。

カーネルを固定する必要がある場合は、バージョンを指定したAMI(al2023-ami-kernel-6.1-*など)を明示的に使ってください。

カーネル変更時に確認すること:

項目理由
チューナブルの存在と場所バージョン間で名前が変わる、sysctlからdebugfsへ移動するなどの変更がある
カーネルモジュールに依存するコンポーネントeBPFプログラム、特定のCNI機能、GPUドライバー、カスタムモジュール
スケジューラーの動作6.6以降はEEVDF(後述)。遅延に敏感なワークロードで差が出る場合がある
パフォーマンスの退行カーネルバージョンごとにベンチマークを再測定する

推奨事項: カーネル移行はKubernetesのバージョンアップグレードと同じ重要度で扱います。同じカーネルを使ったステージングで検証し、性能ベースラインを再測定してから本番へ展開してください。

CPU: スケジューラーとスロットリング ​

EEVDF: 6.6での変更 ​

Linux 6.6では、CFSのタスク選択ロジックがEEVDF(Earliest Eligible Virtual Deadline First)に置き換わりました。

正確に理解すべきなのは、何が変わり、何が変わらなかったかです。

変更された点変更されていない点
次に実行するタスクの選び方(仮想デッドラインに基づく)vruntimeの仕組み、重みの計算
起床したタスクのプリエンプション判断: ヒューリスティック(sched_wakeup_granularity_ns)ではなくデッドラインを比較グループスケジューリング(cgroupのcpu.weight)、負荷分散

したがって、これはCFS全体の置き換えではなく、タスク選択ロジックの進化と捉えるのが正確です。変更はfair_sched_class内にあります。

運用上は、遅延に敏感なワークロードで起床時の遅延特性が変わる場合があります。通常は改善しますが、カーネル6.1から6.18へ移行してp99が変化した場合、これも原因候補の1つです。

チューナブルが実際にある場所 ​

カーネルソース(kernel/sched/debug.c)で確認した内容:

項目状況
sched_latency_ns削除済み。kernel/sched/fair.cに参照が残っていない
sched_wakeup_granularity_ns削除済み(同上)
/sys/kernel/debug/sched/base_slice_ns現在の相当値。内部変数はsysctl_sched_base_sliceで、debugfsではbase_slice_nsとして公開

そのため、CFS時代の遅延/プリエンプションに関するチューナブルはなくなり、単一の基本タイムスライス(base_slice_ns)に統合されています。名前にsched_の接頭辞はありません。パスは/sys/kernel/debug/sched/base_slice_nsです。

別の方法として、EEVDFではタスク自身がsched_setattr()システムコールでタイムスライスを要求できます。遅延に敏感なアプリケーションでは、グローバルなチューナブルを変更するより適しています。

スケジューラーのチューナブルは、現在も推奨される調整対象ではありません。 debugfsはカーネルのデバッグ用インターフェースであり、本番環境でマウントされているとは限りません。多くの場合、アプリケーションのスレッド数またはcgroup上限を調整する方が適切です。

CPU上限: スロットリングが実際の問題である場合 ​

コンテナを支えるカーネル機能で説明したとおり、CPU上限は帯域幅の制限であり、使用率が低くても遅延を生じさせます。

診断:

bash
# cgroup v2: from the container's cgroup path
cat cpu.stat
# nr_periods, nr_throttled, throttled_usec

nr_throttled / nr_periodsが無視できない割合なら、上限が原因です。

対応の優先順位(設計についてはリソース最適化を参照):

  1. アプリケーションが認識するCPU数を上限に合わせます。もっとも見落とされる原因です。コンテナ内のランタイムがノードの全コアを認識し、その数のスレッドを起動すると、クォータをすぐに使い切ります。JVMの-XX:ActiveProcessorCount、GoのGOMAXPROCS、Node.jsのUV_THREADPOOL_SIZEなどを上限に合わせてください。
  2. ノード安定性とのトレードオフを考慮して上限を引き上げます。
  3. 遅延に極端に敏感な場合は上限の削除を検討しますが、requestsとノード分離を使ってnoisy neighborのリスクを管理します。
  4. cpu.pressure PSIで実際の停止時間を確認します。

CPU Managerのstaticポリシー(コア専有)は、遅延に敏感なワークロードに使える別の仕組みです。ノード使用率が下がるため、採用理由が必要です。

メモリ: OOMと圧力 ​

変更するものと既定のままにするもの ​

パラメーター推奨事項
vm.swappinessKubernetesは従来swap無効を前提としてきました。swapサポートは成熟してきていますが、EKSで有効にする前にサポート状況を確認してください
vm.overcommit_memory既定値を維持します。変更するとコンテナのメモリ確保失敗の挙動が予測しにくくなります
vm.min_free_kbytesメモリ回収の余裕に関する値です。低すぎると急な割り当てでOOMになるおそれがあります。大容量ノードでバーストが激しい場合に限り検討してください
vm.max_map_countElasticsearch/OpenSearchなどで実際に必要となる調整です。既定値が低く、mmap上限に達します
kernel.pid_max高密度ノードでPIDが枯渇した場合に調整します

vm.max_map_countは、実際に必要となる例としてよく挙がります。OpenSearch系のソフトウェアは多くのファイルをmmapし、既定値では起動に失敗します。「正当化されたチューニング」のよい例です。症状が明確で、パラメーターが直接の原因であり、ベンダーが値を文書化しています。

カーネルパラメーターの前にkubelet予約を確認する ​

ノードの安定性には、カーネルのチューニングよりもkubeletのリソース予約の方が大きな影響があります。

設定目的
--system-reservedOSとシステムデーモンのために予約する
--kube-reservedkubeletとコンテナランタイムのために予約する
--eviction-hardこのしきい値に達したらPodをevictする

予約が足りないと、Podがノードのメモリをすべて消費し、カーネルまたはkubelet自体がOOMになります。ノードはNotReadyになり、そこで動くすべてのPodが影響を受けます。個々のPodでOOMが起きるよりはるかに深刻です。

OOMよりevictionの方が望ましい結果です。 evictionではKubernetesが制御された方法でPodを移動しますが、OOM killerはカーネルがプロセスを突然終了させます。カーネルOOMより前にKubernetesが介入するよう、--eviction-hardを設定してください。

PSIで圧力を観測する ​

cgroup v2のPSIは、使用量より適切なシグナルを示します。

bash
# Whole node
cat /proc/pressure/memory
cat /proc/pressure/cpu
cat /proc/pressure/io

# A specific cgroup
: "${KERNEL_CGROUP_PATH:?Set the inspected cgroup directory}"
cat "$KERNEL_CGROUP_PATH/memory.pressure"

some avg10は、直近10秒のうち少なくとも1つのタスクがそのリソースを待って停止していた時間の割合です。使用量グラフが落ち着いているのにこの値が増加する場合は、回収または競合に時間を使っています。

ネットワーク: 根拠のある調整 ​

conntrack ​

ここまで説明したとおり、実際の障害原因としてもっとも多い項目です。

項目内容
症状新規接続が通知なく破棄され、アプリケーションにはタイムアウト/拒否だけが見える
照合する証拠conntrack -Sのinsert_failed増加。これだけではテーブル枯渇の証明にならない
補助シグナルdmesgのnf_conntrack: table full、nf_conntrack_count/nf_conntrack_maxの比率
調整経路kube-proxy-config ConfigMapのconntrack.maxPerCore/conntrack.min(EKSでは優先される)
コストエントリーごとにノードメモリを使用。無制限に引き上げられない
根本対策接続の入れ替わりを減らし、データプレーン/マップの負荷を調べる。headless DNSだけでは追跡は無効にならない

maxPerCoreを使う理由も理解しておきましょう。絶対値ではなくコア数に比例するため、同じ設定がノードサイズに応じて変わります。nf_conntrack_maxのような絶対値を固定すると、小さなノードでは過剰に、大きなノードでは不足する値になります。

タイムアウトも調整できます。既定値が非常に長いnf_conntrack_tcp_timeout_establishedを短くすると、エントリーを早く回収できます。ただし、正当に長時間維持する接続を切断しないよう注意してください。

ソケットバッファーとキュー ​

パラメーター使用する状況
net.core.somaxconnacceptキューがあふれた場合。接続が集中するサーバーでよく調整する
net.ipv4.tcp_max_syn_backlogSYNが集中する場合
net.core.netdev_max_backlog受信softirqの処理が追い付かない場合
net.ipv4.tcp_rmem/tcp_wmemTCPサイズ調整の上限/既定値。これを変更しても自動調整が単独で無効になるわけではない。測定したBDP/メモリの証拠に基づく場合だけ調整する
net.ipv4.ip_local_port_range送信元ポートが枯渇した場合。アウトバウンド通信が多いノードで実際に起きる
net.ipv4.tcp_tw_reuseTIME_WAITが蓄積した場合。動作を理解したうえで適用する

somaxconnとip_local_port_rangeは、根拠のある調整の代表例です。前者は証拠となるカウンター(nstatのTcpExtListenOverflows)があり、後者は接続失敗として直接確認できます。

測定結果が変更を正当化しない限り、妥当なtcp_rmem/tcp_wmemの範囲を維持してください。Linuxのドキュメントによると、明示的なソケット単位のSO_RCVBUF/SO_SNDBUF設定は該当ソケットの自動サイズ調整を無効にします。sysctlでmin/default/max値を設定することとは混同しないでください。

qdisc ​

ノード内で破棄が確認された場合(tc -s qdiscのdropped)、ここを調整対象とします。

  • fq_codel: バッファーブロート対策(遅延が問題の場合)
  • fq: ペーシング(bbr利用時)
  • キュー長(txqueuelen)を増やすと破棄は減りますが、遅延が増えます。トレードオフを理解して決めてください。

割り込みの分散 ​

/proc/interruptsで1つのコアに偏り、mpstat -P ALLでそのコアの%softが急増している場合は、RSS/RPS/RFSを確認します。ただし、現在のENAドライバーとインスタンスタイプは既定でマルチキューとRSSを使用するため、これは問題になることがまれです。

kube-proxyモード ​

ノードのカーネルパラメーターではありませんが、データプレーン性能に最も大きく影響します。

状況推奨事項
iptablesモードでServiceが多いnftablesモードを検討する。1.33でGA、O(1)検索と差分更新に対応。カーネル5.13以降が必要(AL2023は満たす)
IPVSモードを実行中移行計画が必要。1.35で非推奨、上流は1.40で既定無効化、1.43で削除を予定。推奨される移行先はnftables
既定のままにするnftablesがGAでも、既定は引き続きiptablesです。切り替えは明示的に判断します

ストレージ ​

パラメーター内容
IOスケジューラーNVMeではnone(またはmq-deadline)が一般的です。複雑なスケジューラーを使ってもNVMeではあまり効果がありません
vm.dirty_ratio/dirty_background_ratio書き込みバッファー量。書き込みバースト時の遅延挙動に影響する
エフェメラルストレージカーネルパラメーターよりも、実際にはoverlayfsのcopy-upコストが問題です。書き込みの多いパスはボリュームに移す(コンテナを支えるカーネル機能)
EBS性能カーネルの問題ではなく、ボリュームタイプ、IOPS、スループット設定の問題(EBS gp2とgp3のベンチマーク)

ワークロード別 ​

症状から確認するための表です。

ワークロードよく必要となる調整証拠となるカウンター
多数の接続を扱うゲートウェイ/プロキシconntrack上限、somaxconn、ip_local_port_rangeinsert_failed、TcpExtListenOverflows、ポート枯渇
遅延に敏感(金融取引、リアルタイム)CPU上限の見直し、CPU Manager staticポリシー、fq_codelcpu.statのスロットリング、cpu.pressure
高スループット(バッチ、データ処理)バッファー上限(長距離通信のみ)、netdev_max_backlogqdiscのdropped、softirqの偏り
検索/インデックス(OpenSearchなど)vm.max_map_count、ファイル記述子の上限起動失敗ログ
高密度ノードkernel.pid_max、kubelet予約、evictionしきい値PID枯渇、ノードのNotReady
ブロックチェーンノードファイル記述子、ディスクIOPS、ソケットバッファーブロックチェーンノードの運用

変更を管理する ​

長期的にはチューニングそのものより、どう管理するかが重要です。

原則理由
コードとして管理する(KarpenterのEC2NodeClass、起動テンプレート、Bottlerocket設定)ノードごとに値が異なるのを防ぐ
理由をコメントに記録する6か月後に「なぜこの値か」を知る人がいなければ、誰も元に戻せない
ノードグループを分けるワークロードごとに必要なチューニングは異なる。すべてに1つのプロファイルを強制しない
カーネルを固定するか、移行計画を立てるkernel-default AMIは気付かないうちにカーネルが変わる
適用後に実値を確認する特にconntrack。別のコンポーネントに上書きされる場合がある
同じ条件で変更前後を測定する測定なしのチューニングは迷信になる

まとめ ​

  • 大半は既定のままにしてください。 カーネルは負荷に応じて自動調整します。根拠のない調整は再現できない設定や、カーネルアップグレード時の問題を生みます。
  • チューニングの前提条件は測定です。破棄カウンター(insert_failed、qdiscのdropped、NICの破棄数)から確認します。
  • 選択したAMIと実行中のカーネルを確認してください。既定AMIファミリーは新しいものへ移行する場合がありますが、AMI IDを固定するとノード置換だけでは自動変更されません。
  • CPUスロットリングの根本原因は、多くの場合、アプリケーションが認識するCPU数とクォータの不一致です。GOMAXPROCS/ActiveProcessorCountから確認してください。
  • ノードの安定性には、カーネル調整よりもkubeletの予約とevictionしきい値が有効です。カーネルOOMよりevictionの方が望ましい動作です。
  • 根拠があれば調整しやすい代表例は、conntrack上限、somaxconn、ip_local_port_range、vm.max_map_countです。いずれも直接的な証拠となるカウンターがあります。
  • TCPのsysctl上限と、ソケット単位の自動調整の上書きは別のものです。測定の証拠がある場合だけ調整してください。
  • IPVSモードを実行している場合は移行計画が必要です(1.35で非推奨、1.40で既定無効化、1.43で削除を予定)。展開前に、以下にリンクした保守中のKEP-5495スケジュールを確認してください。

参考資料 ​

ドキュメントに質問する

Enter で送信、Shift+Enter で改行します。