はじめに
本番運用しているEKSクラスタで、ある日突然次のような状態になりました。
• kubectl get nodes に何も表示されない
• kubectl get pods の結果では、Podがずっと Pending
• でも、Auto Scaling Group(ASG)にはEC2インスタンスが正常に存在している
…え、なにこれ?
⸻
原因を探る
まず疑ったのは以下のような基本的なチェックポイントです:
• kubelet がちゃんと起動しているか(journalctl -u kubelet)
• EC2のIAM RoleにEKS関連のポリシーが付いているか
• TLS証明書が期限切れになっていないか
• 古いノードが再登録されていないか
しかし、どれも該当せず。
⸻
犯人はNATだった
最終的に辿り着いた結論は…
NATインスタンスが死んでいた
EKSのノード(EC2)はプライベートサブネットにいて、外部インターネットへはNATインスタンス経由で通信する構成。
そのNATが落ちていたため、ノードがEKS APIサーバー(外部)にアクセスできず、クラスタに登録されていなかったわけです。
⸻
NAT障害で起きることまとめ
• kubelet がクラスタ登録に失敗
• Podネットワーク(CNI)の初期化が失敗
• ECRからコンテナイメージをpullできない
• yumやcurlなど外部アクセスもすべて死ぬ
結果、見た目上はEC2が正常に起動してるのに、EKSではノードとして認識されないという現象になる。
⸻
一時的な対応
問題のEC2をASGからデタッチ → 新しいノードを立て直すことで回復。
が、根本はNATだったので再発防止が必須。
⸻
監視対策:Slack通知スクリプト
監視スクリプトで異常検知 & Slack通知するようにして、次回からはすぐ気づけるようにしました。
- サイトの疎通確認
#!/bin/bash
URL="https://your-service.example.com"
SLACK_WEBHOOK="https://hooks.slack.com/services/xxx/yyy/zzz"
STATUS=$(curl -s -o /dev/null -w "%{http_code}" $URL)
if [ "$STATUS" -ne 200 ]; then
MESSAGE="🚨 サイトが応答していません!HTTPステータス: $STATUS ($URL)"
echo "$(date): $MESSAGE" >> /var/log/eks-site-health.log
curl -X POST -H 'Content-type: application/json' --data "{\"text\":\"$MESSAGE\"}" "$SLACK_WEBHOOK"
fi
- ノードのReady状態確認
#!/bin/bash
SLACK_WEBHOOK="https://hooks.slack.com/services/xxx/yyy/zzz"
READY_NODES=$(kubectl get nodes --no-headers | grep -c " Ready")
if [ "$READY_NODES" -eq 0 ]; then
MESSAGE="❗️EKSクラスタにReadyノードが存在しません!"
echo "$(date): $MESSAGE" >> /var/log/eks-nodes.log
curl -X POST -H 'Content-type: application/json' --data "{\"text\":\"$MESSAGE\"}" "$SLACK_WEBHOOK"
fi
⸻
再発防止のポイント
• NATインスタンスではなくNAT Gatewayを使う(マネージド+高可用性)
• サブネットのルートテーブルを定期的に確認
• NATの死活監視も追加(例:外部のECR
まとめ
• 「ASGにはEC2あるのに、EKSのノードが見えない」問題の原因は意外とNAT障害かも
• kubeletやIAMだけじゃなく、ネットワークの出口(NAT)も要チェック
• 監視スクリプト+Slack通知で素早く気付ける体制を