1. 背景
最近のプロジェクトでプログラムを運用する過程において、「kubectl get nodes」で「NotReady」状態になっていたり、「kubectl exec」が応答しなくなったり、Podが突然Evicted状態に変わったりするなど、さまざまな問題に遭遇しました。そこで、実際の運用中に遭遇した4種類の障害に基づき、事例を中心としたKubeEdge環境での問題対応ガイドを以下のようにまとめます。
2. はじめに
Kubernetesベースの一般的なクラスターとは異なり、KubeEdgeにはクラウドとエッジノードの間に CloudCore ↔ EdgeCore トンネルが追加で存在します。そのおかげで、ネットワークが不安定な現場環境でもエッジノードを運用できますが、同時に障害の原因もさらに複雑になります。
3. 障害の種類
|
障害の種類1 |
kubectl execの失敗 — "unexpected EOF" |
|---|
(1) 症状
$ kubectl exec -it my-app-6jf2m -n iot-edge -- /bin/bash
error: Internal error occurred: error sending request:
Post "https://192.168.1.3:10351/exec/...": unexpected EOF
「kubectl exec」を実行したところ、接続自体が切断され、何もできない状況です。同じノード上にある別のPodはRunning状態に見えるのに、execだけが動作しない場合もあります。
(2) 原因分析
KubeEdgeで「kubectl exec」を動作させるには、 EdgeStream機能が有効になっている必要があります。この機能が無効になっていると、API Server → CloudCore → EdgeCoreへと続くexecトンネル自体が確立されません。
一般的なKubernetesでは、API Serverがkubeletの10250ポートに直接アクセスしてexecを処理しますが、KubeEdgeにはこの経路がありません。EdgeStreamがなければ、exec、logs、port-forwardはすべて動作しません。
[kubectl exec flow in KubeEdge]
API Server
↓
CloudCore (streamPort: 10003)
↓ ← without this tunnel, unexpected EOF occurs
EdgeCore (edgeStream.server)
↓
컨테이너
(3) 解決方法
CloudCoreの設定確認および有効化:
# cloudcore.yaml
cloudStream:
enable: true
streamPort: 10003
tlsTunnelCAFile: /etc/kubeedge/ca/rootCA.crt
tlsTunnelCertFile: /etc/kubeedge/certs/server.crt
tlsTunnelPrivateKeyFile: /etc/kubeedge/certs/server.key
EdgeCoreの設定確認および有効化:
# edgecore.yaml
edgeStream:
enable: true
handshakeTimeout: 30
readDeadline: 15
server: <CloudCore_IP>:10004
tlsTunnelCAFile: /etc/kubeedge/ca/rootCA.crt
tlsTunnelCertFile: /etc/kubeedge/certs/server.crt
tlsTunnelPrivateKeyFile: /etc/kubeedge/certs/server.key
writeDeadline: 15
設定変更後は、両方を再起動する必要があります:
# On the master node where CloudCore is running
systemctl restart cloudcore.
# On the edge node
systemctl restart edgecore
|
障害の種類2 |
DiskPressureによるPod Eviction |
|---|
(1) 症状
$ kubectl get po -A -o wide | grep <NodeName>
iot-edge chronograf-xxxxx 0/1 Evicted 0 2m
iot-edge influxdb-xxxxx 0/1 Evicted 0 9m
iot-edge my-app-xxxxx 0/1 Evicted 0 14m
特定のノード上にあるPodが一斉にEvicted状態になります。1つや2つではなく、そのノード上のすべてのPodが退去させられる場合は、ノードレベルのリソース問題を疑う必要があります。
(2) 原因分析
Evictionは、kubelet(KubeEdgeではedgecore)がノードのリソース不足を検知した際に、Podを強制終了するメカニズムです。「kubectl describe node」で直接原因を確認できます:
kubectl describe node <NodeName> | grep -A5 "Conditions"
実際の事例では、以下のようなメッセージが表示されました:
DiskPressure True ...
Message: The node was low on resource: ephemeral-storage.
Threshold: 37556267476 (~35GB)
Available: 36674584Ki (~34.9GB)
空きディスク容量がしきい値を下回ると、kubeletがそのノードのPodを強制的に退去させます
ディスク使用量の確認
エッジノードにSSH接続し、どこでディスクを消費しているのかを確認します:
df -h
du -sh /* 2>/dev/null | sort -rh | head -15
実際の事例では、特定のアプリケーションのログディレクトリ1つが、ディスク全体の89%を占有していました。
$ du -sh /var/app/logs/*/
166G /var/app/logs/device-001.ASSET/
(3) 解決方法
古いログの整理(削除前に保存が必要かどうかを必ず確認してください!)
# Delete files older than N days
find /var/app/logs -mtime +7 -type f -delete
使用していないコンテナイメージの整理
crictl rmi --prune
edgecoreを再起動してDiskPressureを再評価
systemctl restart edgecore
Evicted Podの整理および再デプロイ
# On the master node
kubectl get pods -A | grep Evicted | awk '{print "kubectl delete pod " $2 " -n " $1}' | sh
|
障害の種類3 |
Init Container ImagePullBackOff — DNS障害 |
|---|
(1) 症状
$ kubectl describe pod my-app-qn6r8 -n iot-edge
Init Containers:
init-snapshot:
State: Waiting
Reason: ImagePullBackOff
Image: registry.company.internal:5000/infra/busybox:latest
メインコンテナではなく、Init ContainerでイメージのPullに失敗する場合です。Init Containerが失敗すると、メインコンテナは起動すらしません。
この場合、メインコンテナの以前の終了状態を確認すると、以下のように表示されます:
Last State: Terminated
Reason: Unknown
Exit Code: 255
Exit Code 255は、コンテナランタイムがプロセスを強制終了したことを意味し、多くの場合、ノードレベルの問題(以前のDiskPressure、ネットワーク切断など)による結果です。
(2) 原因分析 — プライベートレジストリのDNS障害
ImagePullBackOffの原因はさまざまですが、社内のプライベートレジストリを使用するIoT環境では、 DNS障害が特に頻繁に発生します。
確認方法:
# On the edge node
nslookup registry.company.internal
DNS SERVFAILが表示される場合、ドメイン自体を名前解決できていない状態です。
server can't find registry.company.internal: SERVFAIL
(3) 解決方法
迅速な一時対応 — /etc/hosts への登録
別の正常なノードでIPアドレスを確認した後、「/etc/hosts」に直接登録します。
# Resolve IP from a healthy node
nslookup registry.company.internal
# Add entry to /etc/hosts on the affected node
echo "<IP> registry.company.internal" >> /etc/hosts
# Test image pull
crictl pull registry.company.internal:5000/infra/busybox:latest
DNSの根本原因を解決
一時対応後、「systemd-resolved」の状態を確認して再起動します。
systemctl status systemd-resolved
systemctl restart systemd-resolved
# Verify DNS resolution is restored
nslookup registry.company.internal
DNS復旧後のPod再起動
# Force delete and recreate the Pod from the master node
kubectl delete pod my-app-qn6r8 -n iot-edge --force --grace-period=0
# Watch Pod status
kubectl get pod -n iot-edge -w | grep my-app
4. まとめ
- 「kubectl exec」が実行できない場合、kubeletの問題ではなく、EdgeStreamの設定に問題がある可能性がある。
- Podが大量にEvictedになる場合は、まずノードのディスク使用量を確認する。
- ImagePullBackOffはイメージの問題ではなく、DNS障害が原因である可能性がある。
エッジ環境には、データセンターとは異なり、現場ネットワークの不安定さ、限られたディスク容量、多数の分散ノードの管理という複合的な課題があります。上記のチェックリストをチーム内で共有しておけば、誰がオンコールを担当していても対応時間を短縮できます。
Jsia