k8sの実行中のコンテナで対話型シェルを実行してアレコレやってみた


dockerコマンドで、コンテナにログインする様な行為、`docker run -it centos:6 bash` と同じことを Kubernetesの環境ではどうするんだっけ？　と基本的なことから、ポッドに二つのコンテナを動作させた場合の特徴的な振る舞いについて、書きました。


## NGINXコンテナを起動する

`kubectl apply -f shell-demo.yaml` を実行して、NGINXのHTTPサーバーのポッドを起動する。

~~~shell-demo.yaml
apiVersion: v1
kind: Pod
metadata:
  name: shell-demo
spec:
  volumes:
  - name: shared-data
    emptyDir: {}
  containers:
  - name: nginx
    image: nginx
    volumeMounts:
    - name: shared-data
      mountPath: /usr/share/nginx/html
~~~

~~~
$ kubectl apply -f shell-demo.yaml
pod "shell-demo" created
~~~

### ポッドを起動を確認する

~~~
$ kubectl get pod shell-demo
NAME         READY     STATUS    RESTARTS   AGE
shell-demo   1/1       Running   0          36s
~~~


### NGINXコンテナで対話型シェルを動かす

コンテナには、ユーザーIDとパスワードで、利用者を識別して、利用を許可するという機能は無く、ポッド名（＝コンテナ）とシェルを指定してコンテナのプロセス空間にアクセスする。 

~~~
$ kubectl exec -it shell-demo -- /bin/bash
root@shell-demo:/# ls /
bin  boot  dev	etc  home  lib	lib64  media  mnt  opt	proc  root  run  sbin  srv  sys  tmp  usr  var
~~~


### コンテナにパッケージを追加

コンテナは、カーネルをコンテナのホストに依存するが、OSソフトウェアパッケージは、独立したLinuxディストリビューションなので、パッケージを更新したり、インストールしたりできる。

~~~
root@shell-demo:/# apt-get update
...
root@shell-demo:/# apt-get install -y tcpdump
~~~


## コンテナでカーネルが同じことを確認

わき道に逸れるのですが、コンテナ・ホストのカーネルを共有している事を見たいと思います。

### ノードOSのカーネル

まずは、ノードであるコンテナ・ホストのOSカーネルを見ておきます。

~~~ 
$ uname -a
Linux k8s1 4.4.0-121-generic #145-Ubuntu SMP Fri Apr 13 13:47:23 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
~~~


### NGINXのポッドのカーネル

Linuxのディストリビューションは、GNU/Debian 9 なんだけど、カーネルは、コンテナ・ホストと同じです。

~~~
$ kubectl exec -it shell-demo -- sh
root@shell-demo:/# uname -a
Linux shell-demo 4.4.0-121-generic #145-Ubuntu SMP Fri Apr 13 13:47:23 UTC 2018 x86_64 GNU/Linux
root@shell-demo:/# cat /etc/issue
Debian GNU/Linux 9 \n \l
~~~


### CentOS6のポッドのカーネル

CentOS6 のコンテナを起動して、カーネルのバージョンを見ます。　以下、CentOS 6.9 なのに、Ubuntu カーネル 4.4.0です。

~~~
$ kubectl apply -f shell-demo-c6.yaml 
pod "shell-demo-c6" created

$ kubectl exec -it shell-demo-c6 -- bash
[root@shell-demo-c6 /]# uname -a
Linux shell-demo-c6 4.4.0-121-generic #145-Ubuntu SMP Fri Apr 13 13:47:23 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
[root@shell-demo-c6 /]# cat /etc/issue
CentOS release 6.9 (Final)
Kernel \r on an \m
~~~

以下はポッドのYAMLファイルで、imageは、公式コンテナ CentOS:6 です。

~~~shell-demo-c6.yaml
apiVersion: v1
kind: Pod
metadata:
  name: shell-demo-c6
spec:
  volumes:
  - name: shared-data
    emptyDir: {}
  containers:
  - name: centos-v6
    image: centos:6
    volumeMounts:
    - name: shared-data
      mountPath: /mnt
    command: ["sleep","3600"]
~~~


## ２つのコンテナを動かすポッドで、指定して対話シェルを起動

ポッドの最大の特徴は、一つのポッドで複数のコンテナを動作させる事ができる点だと思います。以下のYAMLファイルを利用して、２つのコンテナが動作するポッドを起動します。

~~~
$ kubectl apply -f shell-demo-2in1.yaml
~~~

YAMLファイルの補足として、spec.containers で、 二つの名前があり、一つはnginxで、もう一つはbusyboxです。 そのままコンテナのイメージ名となっていますが、異なる名前を付与する事ができます。 busyboxはコマンドを指定して、１時間は終了しない様にしておきます。

~~~shell-demo-2in1.yaml
apiVersion: v1
kind: Pod
metadata:
  name: shell-demo-2in1
spec:
  volumes:
  - name: shared-data
    emptyDir: {}
  containers:
  - name: nginx
    image: nginx
    volumeMounts:
    - name: shared-data
      mountPath: /usr/share/nginx/html
  - name: busybox
    image: busybox
    volumeMounts:
    - name: shared-data
      mountPath: /work
    command: ["sleep","3600"]
~~~    

### 起動結果

このポッドは、READYの列で, 2/2 となっていて、 コンテナを２つ持っており、２つともREADYであることを示しています。

~~~
vagrant@k8s1:/vagrant/yaml/demo-shell$ kubectl get po
NAME                        READY     STATUS    RESTARTS   AGE
shell-demo                  1/1       Running   0          19m
shell-demo-2in1             2/2       Running   0          15s
shell-demo-c6               1/1       Running   0          19m
~~~

### コンテナを指定して対話シェルの実行

次の様に、YAMLファイルで指定したコンテナ名を利用して、同一ポッド内のそれぞれのコンテナで、シェルを実行できます。

* `$ kubectl exec -it shell-demo-2in1 --container nginx -- sh`
* `$ kubectl exec -it shell-demo-2in1 --container busybox -- sh`



### nginxコンテナと対話シェル実行

nginxを動作させるだけに、最小化されているので、psコマンドも入っていません。 echoでindex.htmlを作って、busyboxからアクセスを試みます。

~~~
$ kubectl exec -it shell-demo-2in1 --container nginx -- sh

# ps aux
sh: 1: ps: not found

# hostname
shell-demo-2in1

# echo Hello Container in same Pod > /usr/share/nginx/html/index.html

# cat /usr/share/nginx/html/index.html
Hello Container in same Pod
~~~


### busyboxコンテナと対話シェル実行

ps コマンで観ても、nginxは動作していません。 しかし、ローカルホストのHTTP(80)番ポートへアクセスすると 前述で書き込んだindex.htmlの結果が帰ってきます。 ホスト名、ネットワーク、ファイルシステムの一部を共有して、しかも、OSのプロセス空間が区切られているという事が判ると思います。

~~~
$ kubectl exec -it shell-demo-2in1 --container busybox -- sh

/ # wget -O - -q http://localhost:80/
Hello Container in same Pod

/ # ps aux
PID   USER     TIME  COMMAND
    1 root      0:00 sleep 3600
    6 root      0:00 sh
   13 root      0:00 ps aux

/ # hostname
shell-demo-2in1
~~~


# 参考資料

1. https://kubernetes.io/docs/tasks/debug-application-cluster/get-shell-running-container/