dockerコマンドで、コンテナにログインする様な行為、docker run -it centos:6 bash
と同じことを Kubernetesの環境ではどうするんだっけ? と基本的なことから、ポッドに二つのコンテナを動作させた場合の特徴的な振る舞いについて、書きました。
NGINXコンテナを起動する
kubectl apply -f shell-demo.yaml
を実行して、NGINXのHTTPサーバーのポッドを起動する。
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 です。
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"]
2つのコンテナを動かすポッドで、指定して対話シェルを起動
ポッドの最大の特徴は、一つのポッドで複数のコンテナを動作させる事ができる点だと思います。以下のYAMLファイルを利用して、2つのコンテナが動作するポッドを起動します。
$ kubectl apply -f shell-demo-2in1.yaml
YAMLファイルの補足として、spec.containers で、 二つの名前があり、一つはnginxで、もう一つはbusyboxです。 そのままコンテナのイメージ名となっていますが、異なる名前を付与する事ができます。 busyboxはコマンドを指定して、1時間は終了しない様にしておきます。
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 となっていて、 コンテナを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