Slide 1

Slide 1 text

Kubernetes Meetup Tokyo #10 2018/03/08 Takashi Kusumi Debugging Applications in Kubernetes

Slide 2

Slide 2 text

Kubernetes でのデバッグの悩み ▶ Pod や Service にクラスタ外からアクセスできない ▶ コンテナにデバッグツールが⼊っていない + tcpdump や strace など使い慣れたツールを使いたい + ⼀⽅コンテナのサイズは最⼩にしたい 2 # NH 96566-KB First Computer "Bug", 1945

Slide 3

Slide 3 text

アジェンダ ▶ kubectl でのデバッグの基本 + kubectl (run | logs | exec | port-forward | cp | top) ▶ Pod と Linux 名前空間 ▶ デバッグツールが含まれない場合 ▶ 将来⼊りそうな便利機能 + kubectl debug、PodShareProcessNamespace 3

Slide 4

Slide 4 text

kubectl でのデバッグの基本

Slide 5

Slide 5 text

デバッグに使える kubectl のサブコマンド 5 run Pod をコマンドだけで作成する logs コンテナのログを表⽰する exec コンテナ内の任意コマンドを実⾏する port-forward コンテナ内にポートフォワードする cp コンテナとローカルの間でファイルを転送する top Pod や Node の利⽤状況を表⽰する

Slide 6

Slide 6 text

kubelet の Debugging handler 6 Controller Master scheduler etcd apiserver Node kubectl kubelet kube-proxy container runtime debugging handler kubelet kube-proxy container runtime debugging handler kubelet ͷ --enable-debugging-handlers ͰઃఆՄɻσϑΥϧτtrue exec ౳ͷ৔߹ kubelet ͷ API Λར༻ port: 10250 exec ౳ͷ৔߹ SPDY ʹ upgrade

Slide 7

Slide 7 text

kubectl run 7 クラスタ内から Pod や Service にアクセスしたいときに最適 # Pod を立ち上げシェルをアタッチして操作する $ kubectl run -it --rm --restart=Never debug --image alpine /bin/sh # 必要に応じてツールをインストール (Pod 内のシェル) (pod) $ apk add --update curl # DNS サービスディスカバリを使って Service にアクセス (pod) $ curl http://mynginx/ # 終了すると Pod も削除される (--rm --restart=Never) (pod) $ exit

Slide 8

Slide 8 text

--serviceaccount オプション 8 ServiceAccount の権限周りのデバッグに便利 # ServiceAccount を指定して起動 $ kubectl run -it --restart=Never --rm \ --serviceaccount robot \ --image gcr.io/google_containers/hyperkube:v1.9.3 \ debug # 実際に kubectl で権限を確認 (pod) $ kubectl get pods

Slide 9

Slide 9 text

--overrides オプション 9 overrides オプションを使うと JSON で値の上書きが可能 run のオプションで指定できないフィールドも全て設定できる # ノードを指定して Pod をデプロイする $ kubectl run --overrides ' {"spec": {"nodeName": "$NODE_NAME"}} ' -it --rm --restart=Never debug --image alpine

Slide 10

Slide 10 text

ホストの Docker を操作 ☠ 10 $ kubectl run -it --rm --restart=Never --overrides ' { "spec": { "nodeName": "$NODE_NAME", "containers": [ { "name": "docker", "image": "docker", "stdin": true, "tty": true, "command": ["/bin/sh"], "securityContext": {"capabilities": {"add": ["SYS_PTRACE"]}}, "volumeMounts": [ {"name": "docker-sock", "mountPath": "/var/run/docker.sock"} ] } ], "volumes": [ {"name": "docker-sock", "hostPath": {"path": "/var/run/docker.sock"}} ] } } ' mydocker --image docker # ホストの Docker ソケットをマウントして操作

Slide 11

Slide 11 text

kubectl logs 11 # Pod のログを表示する $ kubectl logs # tail -f 相当 $ kubectl logs -f # 1時間以内のログをタイムスタンプ付きで表示 $ kubectl logs --since --timestamp 1h # Deployment の Pod の一つ目だけのログを表示 $ kubectl logs deploy/

Slide 12

Slide 12 text

wercker/stern 12 複数の Pod のログをまとめて表⽰できる便利ツール https://github.com/wercker/stern

Slide 13

Slide 13 text

kubectl exec 13 # 任意コマンドの実行。オプションを使いたい場合は -- を置く $ kubectl exec nginx-3272110360-n2dq6 -- ls -l # シェルをインタラクティブ操作 $ kubectl exec -it nginx-3272110360-n2dq6 -- /bin/sh # コンテナ内に tcpdump をインストール (コンテナ内シェル) (pod) $ apt-get update && apt-get install -y tcpdump # コンテナ内で tcpdump を実行 (pod) $ tcpdump -i any -X コンテナ内の任意コマンドを実⾏する

Slide 14

Slide 14 text

kubectl port-forward 14 コンテナ内のポートをフォーワードする ローカルのみ listen しているポートにもアクセスできる # ローカルの 8080 ポートをコンテナの 80 に転送 $ kubectl port-forward 8080:80 Forwarding from 127.0.0.1:8080 -> 80 # コンテナの 80 をランダムなローカルポートに転送 $ kubectl port-forward :80 Forwarding from 127.0.0.1:53706 -> 80

Slide 15

Slide 15 text

v1.10 で Service / Deploy 指定もサポート 15 # ローカルの 8443 ポートを Service の 443 に転送 $ kubectl port-forward svc/ 8443:443 # Deploy を指定して 5000 ポートと 6000 ポートを転送 $ kubectl port-forward deployment/ 5000 6000 kubectl 側で Service / Deploy のセレクタを使って 最初の Pod を選択しているので分散されるわけではない

Slide 16

Slide 16 text

kubectl top nodes 16 ノードの CPU, メモリ使⽤量が簡単に⾒える $ kubectl top nodes NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% node-cqkj6 88m 1% 3298Mi 20% node-fgq9d 110m 1% 3776Mi 23% node-kg2r6 99m 1% 3461Mi 21% node-4nqgg 1568m 19% 20297Mi 33% node-jrwj2 66m 0% 7631Mi 12% node-pkzhd 84m 1% 5219Mi 8% node-trtr2 91m 1% 6779Mi 11%

Slide 17

Slide 17 text

kubectl top pods 17 Pod の CPU, メモリ使⽤量が簡単に⾒える $ kubectl top pods -n kube-system NAME CPU(cores) MEMORY(bytes) alertmanager-2731826431-5bwb9 0m 7Mi prometheus-2216016132-84s23 1428m 19879Mi default-http-backend-462227202-0wlrn 0m 3Mi grafana-2108099539-0c2dk 0m 27Mi heapster-629638580-xcw2v 3m 65Mi kube-dns-4058640398-92363 1m 36Mi kube-state-metrics-4210456282-m9d2v 2m 49Mi

Slide 18

Slide 18 text

Pod と Linux 名前空間

Slide 19

Slide 19 text

Linux 名前空間と Pod 19 名前空間 分離対象 Pod 内 IPC 共有メモリやセマフォ等によるプロセス間通信 (IPC) 共有 Network ネットワークデバイス、IP アドレスネット等のネットワーク 共有 Mount マウントポイント 分離 PID プロセス ID 分離 User ユーザ ID とグループ ID (UID, GID) 共有 UTS ホスト名とドメイン名 分離 Cgroup cgroup のルートディレクトリ 共有 *後述

Slide 20

Slide 20 text

Pod と pause コンテナ 20 pause Container A Container B ڞ༗͢Δ໊લۭؒ͸ pause ίϯςφ͕อ࣋ # 別のコンテナ($C)の名前空間 # 使って起動する $ docker run -it \ —pid container:$C \ —ipc container:$C \ —network container:$C \ # 起動するコンテナイメージ ubuntu Pod ಺

Slide 21

Slide 21 text

See also: Ian さんの Pause コンテナの記事 21 https://www.ianlewis.org/en/almighty-pause-container

Slide 22

Slide 22 text

/proc/[pid]/ns で実際に⾒てみる 22 $ sudo ls -l /proc/15627/ns total 0 ... cgroup -> cgroup:[4026531835] ... ipc -> ipc:[4026532337] ... mnt -> mnt:[4026532335] ... net -> net:[4026532340] ... pid -> pid:[4026532338] ... user -> user:[4026531837] ... uts -> uts:[4026532336] $ sudo ls -l /proc/15784/ns total 0 ... cgroup -> cgroup:[4026531835] ... ipc -> ipc:[4026532337] ... mnt -> mnt:[4026532442] ... net -> net:[4026532340] ... pid -> pid:[4026532549] ... user -> user:[4026531837] ... uts -> uts:[4026532443] pause ίϯςφ (pid 15627) nginx ίϯςφ (pid 15784)

Slide 23

Slide 23 text

デバッグには Network, PID の共有が便利 ▶ Network 名前空間 + tcpdump, netstat ▶ PID 名前空間 (Pod 内では分離されている) + ps, strace, kill (シグナル) + /proc/[pid]/root でファイルシステムにもアクセスできる 23

Slide 24

Slide 24 text

PID がマウントするルート: /proc/[pid]/root ▶ /proc/[pid]/root でその PID がマウントしているルートが⾒れる ▶ PID 名前空間を共有していればアクセス可能 + デバッグ対象にシェルが含まれない場合に便利 24 $ docker run -it \ --pid container:$CONTAINER_ID \ # PID 名前空間を共有 alpine # 任意のコンテナイメージ # /proc/[pid]/root で PID を共有したコンテナのファイルを見れる (pod) $ ls /proc/1/root/ Dockerfile dashboard dev etc ...

Slide 25

Slide 25 text

デバッグツールが含まれない場合

Slide 26

Slide 26 text

コンテナにツールが含まれない場合 26 Mount Network PID 備考 Pod にパッケージをインストール ⼀番⼿軽 デバッグ⽤イメージを作成 開発中に便利 デバッグ⽤サイドカーを⼊れる パッケージマネージャーが ない場合に便利 docker run で名前空間を共有 ※1 scratch イメージも対応可能 ※1 /proc/[PID]/root 経由でファイルにアクセス可能

Slide 27

Slide 27 text

docker run で他のコンテナと名前空間を共有 27 $ docker run -it \ --pid container:$CONTAINER_ID \ # PID 名前空間 --network container:$CONTAINER_ID \ # ネットワーク名前空間 --privileged \ # strace などを利用したい場合 alpine # 任意のコンテナイメージ # 共有したコンテナのプロセスが見える (シグナルや strace も可能) (pod) $ ps PID USER TIME COMMAND 1 root 0:04 /dashboard --port=9090 ... # /proc 経由で共有したコンテナのファイルも見れる (pod) $ ls /proc/1/root/ Dockerfile dashboard dev etc ...

Slide 28

Slide 28 text

scratch-debugger 28 scratch イメージに busybox シェルを差し込むスクリプト

Slide 29

Slide 29 text

将来⼊りそうな便利機能

Slide 30

Slide 30 text

Debug Containers #277 ▶ k8s v1.7くらいからマイルストーンに⼊っている機能 + 最近も v1.10 -> v1.11 にずれ込んだ ▶ 最近開発が進んだので v1.11 に期待 30 # Pod 上でデバッグコンテナを起動 $ kubectl debug target-pod # イメージ等を指定して起動 $ kubectl debug -c debug-shell --image=debian target-pod -- bash

Slide 31

Slide 31 text

Configurable Pod Process Namespace Sharing #495 31 ▶ Pod 間の PID 名前空間の共有を設定可能にする機能 ▶ v1.10 でα機能として⼊る予定 + pod.spec.securityContext.shareProcessNamespace

Slide 32

Slide 32 text

まとめ

Slide 33

Slide 33 text

まとめ ▶ デバッグの基本 + kubectl (run | logs | exec | port-forward | cp | top) ▶ デバッグツールが含まれない場合 + パッケージージインストール or docker で名前空間を共有 + PID 空間を共有すると /proc/[pid]/root でファイルも⾒れる ▶ kubectl debug に期待 33

Slide 34

Slide 34 text

We are hiring! bit.ly/zlab-careers