はじめに
この記事は、先日リリースされた Kubernetes 1.18 1 でエフェメラルコンテナ関連機能の実装がほぼ完了して、デバッグ目的のエフェメラルコンテナ 2 を作成する kubectl alpha debug
コマンドが追加されたということで、これらを使って Pod をデバッグするまでの流れをまとめたものとなります。
エフェメラルコンテナ? kubectl debug コマンドってそもそもなんだ? となった方は Kubernetes 1.18: SIG-CLI の変更内容 で詳細に解説されていますので、まずはそちらを一読するのが良いかと思います。
それでは実際にやっていきます。
エフェメラルコンテナ機能を有効にしたクラスタ作成
Feature Gates で EphemeralContainers
を指定してエフェメラルコンテナ機能を有効にして Kubernetes 1.18 クラスタを作成します。
minikube start --kubernetes-version=v1.18.0 --feature-gates=EphemeralContainers=true
kubectl
のバージョンが 1.18 未満では kubectl alpha debug
がサポートされていないので、以下のように 1.18 にバージョンアップしておくことも忘れずに。
$ kubectl version --client -o yaml
clientVersion:
buildDate: "2020-03-26T06:16:15Z"
compiler: gc
gitCommit: 9e991415386e4cf155a24b1da15becaa390438d8
gitTreeState: clean
gitVersion: v1.18.0
goVersion: go1.14
major: "1"
minor: "18"
platform: darwin/amd64
検証用の Pod 作成
k8s.gcr.io/pause:3.1
3 という scratch イメージ(中身が空のコンテナイメージで)がベースとなった、デバッグツールが無ければシェルさえも含まれていないイメージを使って検証用の Pod を作成します。1.16 時点でプロセス名前空間を共有するために必要だった shareProcessNamespace: true
は 1.18 での機能追加により指定不要となっています。
cat << EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
name: config
data:
demo.conf: demo
---
apiVersion: v1
kind: Pod
metadata:
name: ephemeral-demo
spec:
containers:
- name: ephemeral-demo-container
image: k8s.gcr.io/pause:3.1
env:
- name: DEMO
value: demo
volumeMounts:
- name: config
mountPath: /config
volumes:
- name: config
configMap:
name: config
EOF
Pod が作成された後で kubectl exec
でシェルさえ起動できない状態であることを確認します。これでは Pod 内で何かしらの問題が起きたときにトラブルシューティングを実施できません。
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
ephemeral-demo 1/1 Running 0 22s
$ kubectl exec -it ephemeral-demo -- sh
OCI runtime exec failed: exec failed: container_linux.go:349: starting container process caused "exec: \"sh\": executable file not found in $PATH": unknown
command terminated with exit code 126
kubectl alpha debug でのデバッグ
kubectl alpha debug
を実行するとエフェメラルコンテナが作成されて Pod にアタッチされます。-it
が指定されているとシェルが起動する仕様です。実行時には --image
でエフェメラルコンテナのイメージを --container
でエフェメラルコンテナ名を --target
でプロセス名前空間を共有するコンテナを指定することができます。
$ kubectl alpha debug -it ephemeral-demo --image=busybox --container=debugger --target=ephemeral-demo-container
If you don't see a command prompt, try pressing enter.
/ #
プロセス名前空間を共有しているのでエフェメラルコンテナに含まれる ps コマンドで ephemeral-demo-container
コンテナ内で実行されている /pause プロセスを確認できました。
/ # ps --help 2>&1 | head -n 1
BusyBox v1.31.1 (2020-03-09 21:47:38 UTC) multi-call binary.
/ # ps -ef
PID USER TIME COMMAND
1 root 0:00 /pause
6 root 0:00 sh
11 root 0:00 ps -ef
エフェメラルコンテナに含まれるデバッグツールで ephemeral-demo-container
コンテナに対して様々なオペレーションが行えることが確認できました。トラブルシューティングで実施したい作業に合わせてイメージを指定すると良いと思います。
/ # netstat
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
Active UNIX domain sockets (w/o servers)
Proto RefCnt Flags Type State I-Node Path
/ # nslookup google.com
Server: 10.96.0.10
Address: 10.96.0.10:53
Non-authoritative answer:
Name: google.com
Address: 172.217.24.142
/proc/<PID>/root
直下を参照することで ephemeral-demo-container
コンテナのファイルシステムにアクセスできることが確認できました。4
/ # ps -ef
PID USER TIME COMMAND
1 root 0:00 /pause
6 root 0:00 sh
11 root 0:00 ps -ef
/ # ls -l /proc/1/root/
total 740
drwxrwxrwx 3 root root 4096 Apr 3 19:46 config
drwxr-xr-x 5 root root 360 Apr 3 19:46 dev
drwxr-xr-x 2 root root 4096 Apr 3 19:46 etc
-rwxr-xr-x 1 root root 742472 Dec 20 2017 pause
dr-xr-xr-x 144 root root 0 Apr 3 19:46 proc
dr-xr-xr-x 12 root root 0 Apr 3 19:46 sys
drwxr-xr-x 3 root root 4096 Apr 3 19:46 var
/ # cat /proc/1/root/config/demo.conf
demo
/proc/<PID>/environ
直下を参照することで ephemeral-demo-container
コンテナの環境変数を参照できることが確認できました。
/ # cat -e /proc/1/environ | sed -e 's/\^@/\n/g'
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=ephemeral-demo
DEMO=demo
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
KUBERNETES_SERVICE_HOST=10.96.0.1
KUBERNETES_SERVICE_PORT=443
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_PORT=443
エフェメラルコンテナを抜けたあとで Pod マニフェストを確認してみると、エフェメラルコンテナ関連の Spec と Status が追加されていることが確認できます。
/ # exit
Session ended, resume using 'kubectl alpha attach ephemeral-demo -c debugger -i -t' command when the pod is running
$ kubectl get pods ephemeral-demo -o yaml
apiVersion: v1
kind: Pod
metadata:
name: ephemeral-demo
namespace: default
spec:
...
ephemeralContainers:
- image: busybox
imagePullPolicy: IfNotPresent
name: debugger
resources: {}
stdin: true
targetContainerName: ephemeral-demo-container
terminationMessagePolicy: File
tty: true
...
status:
...
ephemeralContainerStatuses:
- containerID: docker://afc7f76a5ef59bdb514f081d045827eabde834b0c97a91d8e03233e40fa91ba6
image: busybox:latest
imageID: docker-pullable://busybox@sha256:b26cd013274a657b86e706210ddd5cc1f82f50155791199d29b9e86e935ce135
lastState: {}
name: debugger
ready: false
restartCount: 0
state:
terminated:
containerID: docker://afc7f76a5ef59bdb514f081d045827eabde834b0c97a91d8e03233e40fa91ba6
exitCode: 0
finishedAt: "2020-04-03T19:47:56Z"
reason: Completed
startedAt: "2020-04-03T19:46:48Z"
...
最後に Pod でエラーが発生して起動していない状態で kubectl alpha debug
を実行するとどうなるか見ていきます。以下のマニフェストを適用して、crash コマンドが存在しないことによりエラーとなる Pod を作成します。
cat << EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: ephemeral-crash-demo
spec:
containers:
- name: ephemeral-crash-demo-container
image: k8s.gcr.io/pause:3.1
command:
- "crash"
EOF
エラーになっていることを確認して kubectl alpha debug
を実行すると、--target
で指定した ephemeral-crash-demo-container
コンテナに接続できずに出力が何も得られないまま無言状態となります。
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
ephemeral-crash-demo 0/1 CrashLoopBackOff 1 25s
$ kubectl alpha debug -it ephemeral-crash-demo --image=busybox --container=debugger --target=ephemeral-crash-demo-container
ephemeral-crash-demo-container
コンテナが起動していないのでデバッグできないのは当たり前ですが、--target
なしにすることで Pod のネットワークをデバッグすることは可能になっております。具体的なケースがパッと浮かんではきませんが、これでなにかしらトラブルシューティングは行えるかもしれません。
$ kubectl alpha debug -it ephemeral-crash-demo --image=busybox --container=no-taret-debugger
If you don't see a command prompt, try pressing enter.
/ # ps -ef
PID USER TIME COMMAND
1 root 0:00 sh
6 root 0:00 ps -ef
以上が kubectl alpha debug でのデバッグの流れとなります。
さいごに
ここまでで Kubernetes 1.18 で kubectl alpha debug
を使って Pod をデバッグする流れをまとめてみました。alpha 機能なので本番環境での使用は出来ませんが非常に便利そうなので、minikube や kind などの開発用途のクラスタで活用していこうかと思います
参考資料
- Debugging with an ephemeral debug container - Kubernetes Documentation v1.18
- New in Kubernetes 1.18 — kubectl alpha debug
おまけ: 今後改善されると良いなと思ったところ
現時点で alpha なので今後改善されていくであろうという前提で書き留めておきます。
その1: 作成済みのエフェメラルコンテナに再アタッチすることができない
エフェメラルコンテナから抜ける際にサジェストされる kubectl alpha attach
コマンドが現時点でサポートされておらず、作成済みのエフェメラルコンテナに再アタッチすることができない。
$ kubectl alpha debug -it ephemeral-demo --image=busybox --container=debugger --target=ephemeral-demo-container
If you don't see a command prompt, try pressing enter.
/ # exit
Session ended, resume using 'kubectl alpha attach ephemeral-demo -c debugger -i -t' command when the pod is running
$ kubectl alpha attach ephemeral-demo -c debugger -i -t
Error: unknown shorthand flag: 'c' in -c
See 'kubectl alpha --help' for usage.
同じコマンドを再実行するとエフェメラルコンテナ名が重複していると怒られるので、--container
の値を変更して新たにエフェメラルコンテナを作成することは可能な状態であることは把握した。
$ kubectl alpha debug -it ephemeral-demo --image=busybox --container=debugger --target=ephemeral-demo-container
error: error updating ephemeral containers: Pod "ephemeral-demo" is invalid: spec.ephemeralContainers[1].name: Duplicate value: "debugger"
$ kubectl alpha debug -it ephemeral-demo --image=busybox --container=new-debugger --target=ephemeral-demo-container
If you don't see a command prompt, try pressing enter.
/ #
その2: エフェメラルコンテナ名なしは便利だが Pod マニフェストが肥大化する
--container
が指定されていない場合にはエフェメラルコンテナ名が自動生成されるので、その1 のようなオペレーションが不要になるので手間が掛からない。
$ kubectl alpha debug -it ephemeral-demo --image=busybox --target=ephemeral-demo-container
Defaulting debug container name to debugger-xsztc.
If you don't see a command prompt, try pressing enter.
/ # Session ended, resume using 'kubectl alpha attach ephemeral-demo -c debugger-xsztc -i -t' command when the pod is running
$ kubectl alpha debug -it ephemeral-demo --image=busybox --target=ephemeral-demo-container
Defaulting debug container name to debugger-s5p2h.
If you don't see a command prompt, try pressing enter.
/ # Session ended, resume using 'kubectl alpha attach ephemeral-demo -c debugger-s5p2h -i -t' command when the pod is running
$ kubectl alpha debug -it ephemeral-demo --image=busybox --target=ephemeral-demo-container
Defaulting debug container name to debugger-z9gbv.
If you don't see a command prompt, try pressing enter.
/ # Session ended, resume using 'kubectl alpha attach ephemeral-demo -c debugger-z9gbv -i -t' command when the pod is running
ただし、Pod マニフェストに実行数分のエフェメラルコンテナ関連の Spec. Status が追加されるので Pod マニフェストが肥大化していきます。Pod マニフェストの肥大化が Kubernetes クラスタにどのような影響を及ぼすのかはわかりませんが良くはないような気がしています。
$ kubectl get pods ephemeral-demo -o yaml
apiVersion: v1
kind: Pod
metadata:
...
name: ephemeral-demo
namespace: default
...
spec:
...
ephemeralContainers:
- image: busybox
name: debugger-xsztc
...
- image: busybox
name: debugger-s5p2h
...
- image: busybox
name: debugger-z9gbv
...
...
status:
ephemeralContainerStatuses:
- containerID: docker://aa66c73b8811367fdef8c440dff5606f91e3dfe7a05424754cbc463705df1d40
image: busybox:latest
imageID: docker-pullable://busybox@sha256:b26cd013274a657b86e706210ddd5cc1f82f50155791199d29b9e86e935ce135
name: debugger-s5p2h
...
- containerID: docker://1d7223f454e1439fa61a5e81da855160aa67fc0e49d19b8af446e9a3921a4f26
image: busybox:latest
imageID: docker-pullable://busybox@sha256:b26cd013274a657b86e706210ddd5cc1f82f50155791199d29b9e86e935ce135
name: debugger-xsztc
...
- containerID: docker://9c95e166c151f5f7113843680d6afb6d03eb70dfec5c81c5d2179f2610eca899
image: busybox:latest
imageID: docker-pullable://busybox@sha256:b26cd013274a657b86e706210ddd5cc1f82f50155791199d29b9e86e935ce135
name: debugger-z9gbv
...
-
https://github.com/kubernetes/kubernetes/releases/tag/v1.18.0 ↩
-
https://kubernetes.io/docs/concepts/workloads/pods/ephemeral-containers/ ↩
-
https://github.com/kubernetes/kubernetes/blob/v1.18.0/build/pause/Dockerfile ↩
-
OS に詳しくないので正確な情報はわかりませんが
/proc/<PID>
配下のファイルを使用したオペレーションはエフェメラルコンテナのディストリビューションによって仕様が異なるかと思います。 ↩