はじめに
ここでは、Kubernetes 1.16 で実装された Ephemeral Containers (エフェメラルコンテナ) をみていきます。
- alpha レベルは実験段階の機能です。検証目的でのみ使用し、プロダクションで使用することはやめましょう。
- 1.16 時点での情報が記載されています。その後に仕様が変更されている可能性があることに注意してください。
エフェメラルコンテナとは
エフェメラルコンテナは、実行中の Pod に対してエフェメラルな(揮発的な、一時的な)コンテナを後から追加する機能です。何がうれしいかというと、これまで実行中の Pod のコンテナでデバッグしたいときには kubectl exec
コマンドを使ってデバッグしたいコンテナ内で任意のコマンドを実行するということをやっていました。この方法での問題は、デバッグ対象のコンテナが scratch イメージ(空の何も含まれていないイメージ)をベースイメージとしているとシェルさえもない場合もあり、あとからコマンドをインストールすることもできず、デバッグが困難です。デバッグ用のコンテナをサイドカーとして一緒にデプロイしておくこともできますが、全ての Pod のサイドカーとして追加しておくのはコストがかかります。あとから必要なときにデバッグ用のコンテナを Pod に追加できれば、アプリケーションコンテナにデバッグ用のコマンドを含む必要もなく、デメリットなしに最小のイメージを作成できます。
エフェメラルコンテナは、Kubernetes 1.16 で全体を構成する一部の機能が alpha として提供されました。全ての機能が alpha ステージで出揃うのは 1.18 が予定されています。より詳しい情報は、KEP を参照してください。
エフェメラルコンテナを有効にしたクラスタの作成
ここでは、minikube を使用してエフェメラルコンテナを有効にしたクラスタを用意します。エフェメラルコンテナは、alpha ステージの機能のため、デフォルトでは有効化されていません。使用するには kube-apiserver の Feture Gates EphemeralContainers
を明示的に有効にする必要があります。
$ minikube version
minikube version: v1.4.0
commit: 7969c25a98a018b94ea87d949350f3271e9d64b6
$ minikube start --kubernetes-version=v1.16.0 --feature-gates=EphemeralContainers=true
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"16", GitVersion:"v1.16.0", GitCommit:"2bd9643cee5b3b3a5ecbd3af49d09018f0773c77", GitTreeState:"clean", BuildDate:"2019-09-19T14:00:14Z", GoVersion:"go1.12.9", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"16", GitVersion:"v1.16.0", GitCommit:"2bd9643cee5b3b3a5ecbd3af49d09018f0773c77", GitTreeState:"clean", BuildDate:"2019-09-18T14:27:17Z", GoVersion:"go1.12.9", Compiler:"gc", Platform:"linux/amd64"}
$ kubectl get po -n kube-system kube-apiserver-minikube -o yaml | grep feature-gates
- --feature-gates=EphemeralContainers=true
kubectl-debug
プラグインのインストール
1.16 で提供されたのはエフェメラルコンテナの機能を構成する一部分で、実際に kubectl コマンドを使ってエフェメラルコンテナを追加するサブコマンドはまだ提供されていません。このサブコマンドは kubectl debug
コマンドとして 1.17 で提供予定となっていますが、PoC 実装である kubectl-debug
プラグインが用意されています。ここではこの kubectl プラグインを使用します。
$ cd $(mktemp -d)
$ curl -LO https://github.com/verb/kubectl-debug/releases/download/v0.1.0/kubectl-debug_darwin_amd64.tar.gz
$ tar xvzf kubectl-debug_darwin_amd64.tar.gz
$ mkdir -p ~/bin
$ mv kubectl-debug ~/bin/
$ export PATH="$HOME/bin:$PATH"
$ kubectl debug -h
kubectl プラグインの動作について知りたい方は、kubectl のプラグイン機能 kubectl plugin を使おう!を参照してください。
デバッグ対象の Pod の作成
次に今回デバッグ対象とする Pod を作成します。ここでは Node.js ランタイムのみを含む distroless/nodejs をベースイメージにしたコンテナを含む debugtest
Pod を作成します。
$ cat <<EOL | kubectl apply -f-
apiVersion: v1
kind: Pod
metadata:
name: debugtest
spec:
shareProcessNamespace: true
containers:
- name: myapp
image: docker.io/superbrothers/distroless-examples-nodejs-hello-http
EOL
pod/debugtest created
$ kubectl exec -it debugtest /bin/sh
OCI runtime exec failed: exec failed: container_linux.go:345: starting container process caused "exec: \"/bin/sh\": stat /bin/sh: no such file or directory": unknown
command terminated with exit code 126
Node.js ランタイムしか含まないイメージをベースとしているコンテナなので、kubectl exec
コマンドで /bin/sh
を実行しようとしても存在しないため、実行できずデバッグできない状態です。
ここで注意する点として、1.16 時点でデバッグ対象とする Pod は「プロセスネームスペースの共有」機能(Pod spec.shareProcessNamespace
)を有効にしておく必要があります。これはあとから追加されるエフェメラルコンテナから Pod に含まれるデバッグ対象のコンテナのプロセスをみられるようにしなければならないためです。将来的には「プロセスネームスペースの共有」機能を使用せず、あとからデバッグ対象のコンテナのプロセスネームスペース明示的に共有する機能が提供予定です(1.17)。
エフェメラルコンテナを追加する
では、最後に実際にエフェメラルコンテナを追加してみます。それには先にインストールした kubectl-debug
プラグインを使用します。現時点でデバッグ用コンテナに利用されるイメージは busybox がデフォルトとなっていますが、--image
フラグで任意のイメージに変更できます。
ここでは、デバッグ対象のアプリケーションコンテナで名前解決ができていないかもしれないことを確認するというシナリオとします。このアプリケーションコンテナには nslook コマンドはおろか、sh コマンドでさえインストールされていないため、そのままではデバッグが困難です。
$ kubectl debug debugtest --attach
If you don't see a command prompt, try pressing enter.
/ # cat --help 2>&1 | head -n 1
BusyBox v1.31.0 (2019-09-04 17:25:45 UTC) multi-call binary.
/ # ps aux
PID USER TIME COMMAND
1 root 0:00 /pause
6 root 0:00 /nodejs/bin/node hello_http.js
48 root 0:00 sh
53 root 0:00 ps aux
/ # cat /proc/6/root/etc/resolv.conf
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
/ # nslookup kubernetes.default.svc.cluster.local
Server: 10.96.0.10
Address: 10.96.0.10:53
Name: kubernetes.default.svc.cluster.local
Address: 10.96.0.1
*** Can't find kubernetes.default.svc.cluster.local: No answer
/ # exit
Session ended, resume using 'kubectl attach debugtest -c debugger -i -t' command when the pod is running
以上から、アプリケーションコンテナの /etc/resolv.conf
の内容に問題はなく、busybox コンテナに含まれる nslook コマンドで名前解決できることを確認できました。
エフェメラルコンテナの情報を確認する
ここからは少し詳細についてみていきます。 エフェメラルコンテナを追加した Pod はその情報が spec.ephemeralContainers
フィールドとしてマニフェストに追加されます。また、エフェメラルコンテナのステータスは status.ephemeralContainerStatuses
に追加されます。
$ kubectl get po debugtest -o yaml
(略)
spec:
(略)
ephemeralContainers:
- image: busybox
imagePullPolicy: IfNotPresent
name: debugger
resources: {}
stdin: true
terminationMessagePolicy: File
tty: true
(略)
status:
(略)
ephemeralContainerStatuses:
- containerID: docker://c123e9f7e000f00d5a4660a845616af78f7a6d9470aeebee4a9a4ad8c0a88dac
image: busybox:latest
imageID: docker-pullable://busybox@sha256:fe301db49df08c384001ed752dff6d52b4305a73a7f608f21528048e8a08b51e
lastState: {}
name: debugger
ready: false
restartCount: 0
state:
terminated:
containerID: docker://c123e9f7e000f00d5a4660a845616af78f7a6d9470aeebee4a9a4ad8c0a88dac
exitCode: 0
finishedAt: "2019-09-20T06:36:21Z"
reason: Completed
startedAt: "2019-09-20T06:35:34Z"
エフェメラルコンテナを操作する Kubernetes API
エフェメラルコンテナの操作は Kubernetes API としては Pod の ephemeralcontainers
サブリソースで表現されています。操作は取得(GET)と更新(PUT)のみです。
/api/v1/namespaces/<namespace-name>/pods/<pod-name>/ephemeralcontainers
client-go ライブラリからは次のように使用します。これは、エフェメラルコンテナを追加する操作のみなので、アタッチする場合は、kubectl attach
相当の処理が必要です。
pods := o.clientset.CoreV1().Pods(info.Namespace)
ec, err := pods.GetEphemeralContainers(info.Name, metav1.GetOptions{})
if err != nil {
return err
}
ec.EphemeralContainers = append(ec.EphemeralContainers, o.debugContainer)
ec, err = pods.UpdateEphemeralContainers(info.Name, ec)
if err != nil {
return err
}
まとめ
エフェメラルコンテナは、実行中の Pod に対してエフェメラルな(揮発的な、一時的な)コンテナを後から追加する機能です。この機能によって scratch イメージ等をベースとした最小のイメージをコマンドが含まれておらずデバッグが困難というデメリットなしに使用できるようになります。1.16 リリース時点では、エフェメラルコンテナに関連する全ての機能が alpha レベルで提供されるのが 1.18 となっています。beta、GA での提供はまだまだ先ですが、期待して待ちましょう。