Debugging Applications in Kubernetes

Debugging Applications in Kubernetes

Kubernetes Meetup Tokyo #10
2018.03.08
https://k8sjp.connpass.com/event/76816/

365dfdeb6858bb8b82baedb582bfe1cf?s=128

Takashi Kusumi

March 08, 2018
Tweet

Transcript

  1. 2.

    Kubernetes でのデバッグの悩み ▶ Pod や Service にクラスタ外からアクセスできない ▶ コンテナにデバッグツールが⼊っていない +

    tcpdump や strace など使い慣れたツールを使いたい + ⼀⽅コンテナのサイズは最⼩にしたい 2 # NH 96566-KB First Computer "Bug", 1945
  2. 3.

    アジェンダ ▶ kubectl でのデバッグの基本 + kubectl (run | logs |

    exec | port-forward | cp | top) ▶ Pod と Linux 名前空間 ▶ デバッグツールが含まれない場合 ▶ 将来⼊りそうな便利機能 + kubectl debug、PodShareProcessNamespace 3
  3. 5.

    デバッグに使える kubectl のサブコマンド 5 run Pod をコマンドだけで作成する logs コンテナのログを表⽰する exec

    コンテナ内の任意コマンドを実⾏する port-forward コンテナ内にポートフォワードする cp コンテナとローカルの間でファイルを転送する top Pod や Node の利⽤状況を表⽰する
  4. 6.

    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
  5. 7.

    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
  6. 8.

    --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
  7. 9.

    --overrides オプション 9 overrides オプションを使うと JSON で値の上書きが可能 run のオプションで指定できないフィールドも全て設定できる #

    ノードを指定して Pod をデプロイする $ kubectl run --overrides ' {"spec": {"nodeName": "$NODE_NAME"}} ' -it --rm --restart=Never debug --image alpine
  8. 10.

    ホストの 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 ソケットをマウントして操作
  9. 11.

    kubectl logs 11 # Pod のログを表示する $ kubectl logs <POD_NAME>

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

    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 コンテナ内の任意コマンドを実⾏する
  11. 14.

    kubectl port-forward 14 コンテナ内のポートをフォーワードする ローカルのみ listen しているポートにもアクセスできる # ローカルの 8080

    ポートをコンテナの 80 に転送 $ kubectl port-forward <POD_NAME> 8080:80 Forwarding from 127.0.0.1:8080 -> 80 # コンテナの 80 をランダムなローカルポートに転送 $ kubectl port-forward <POD_NAME> :80 Forwarding from 127.0.0.1:53706 -> 80
  12. 15.

    v1.10 で Service / Deploy 指定もサポート 15 # ローカルの 8443

    ポートを Service の 443 に転送 $ kubectl port-forward svc/<SVC_NAME> 8443:443 # Deploy を指定して 5000 ポートと 6000 ポートを転送 $ kubectl port-forward deployment/<DEPLOY_NAME> 5000 6000 kubectl 側で Service / Deploy のセレクタを使って 最初の Pod を選択しているので分散されるわけではない
  13. 16.

    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%
  14. 17.

    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
  15. 19.

    Linux 名前空間と Pod 19 名前空間 分離対象 Pod 内 IPC 共有メモリやセマフォ等によるプロセス間通信

    (IPC) 共有 Network ネットワークデバイス、IP アドレスネット等のネットワーク 共有 Mount マウントポイント 分離 PID プロセス ID 分離 User ユーザ ID とグループ ID (UID, GID) 共有 UTS ホスト名とドメイン名 分離 Cgroup cgroup のルートディレクトリ 共有 *後述
  16. 20.

    Pod と pause コンテナ 20 pause Container A Container B

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

    /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)
  18. 23.

    デバッグには Network, PID の共有が便利 ▶ Network 名前空間 + tcpdump, netstat

    ▶ PID 名前空間 (Pod 内では分離されている) + ps, strace, kill (シグナル) + /proc/[pid]/root でファイルシステムにもアクセスできる 23
  19. 24.

    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 ...
  20. 26.

    コンテナにツールが含まれない場合 26 Mount Network PID 備考 Pod にパッケージをインストール ⼀番⼿軽 デバッグ⽤イメージを作成

    開発中に便利 デバッグ⽤サイドカーを⼊れる パッケージマネージャーが ない場合に便利 docker run で名前空間を共有 ※1 scratch イメージも対応可能 ※1 /proc/[PID]/root 経由でファイルにアクセス可能
  21. 27.

    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 ...
  22. 30.

    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
  23. 31.

    Configurable Pod Process Namespace Sharing #495 31 ▶ Pod 間の

    PID 名前空間の共有を設定可能にする機能 ▶ v1.10 でα機能として⼊る予定 + pod.spec.securityContext.shareProcessNamespace
  24. 32.
  25. 33.

    まとめ ▶ デバッグの基本 + kubectl (run | logs | exec

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