Kubernetes CKA課程筆記 46

Troubleshooting — 如何透過Pod的command與args來做測試

ZONGRU Li
10 min readNov 11, 2021

使用臨時的Pod來Debug — 使用BusyBox的Pod

  • 通常會利用臨時建立的Pod在裡面執行指令來做正常佈署應用程式的Pod的Debug
  • 因為由前面學到的,Pods間的網路架構與Cluster Node網路架構很不一樣!!
(自筆記21)如圖,所以同個Node內的不同Pod得以互相溝通,就好像有個虛擬網路與虛擬Router
  • 如圖Pods間的網路溝通有一層虛擬的網路
  • 可以透過不同Pod來確認另一個Pod的狀態
  • 常見附有很多工具的image則如busybox image
busybox Docker hub

busybox image內含以下工具:

  1. ficonfig
  2. mslookup
  3. netstat
  4. ping
  5. …etc

也可以直接到busybox wiki查看有哪些指令(連結)如下圖:

但是busybox沒有curl....,所以可以另找curl image:

curl image Docker hub

接著就來用imperative方式建立Busybox的Pod來當作測試用的Pod執行:

kubectl run debug-pod --image=busybox

建立後確認Pod狀態:

過一陣子在看:

所以這時候無法執行如下指令進入Pod內:

kubectl exec -it debug-pod -- sh

詳後面解釋

Container通常為了某些特定的任務運行,例如:

  1. 運行一個mysql DB
  2. 啟動一個Web Application
  3. Syncronize data

並且最終Container隨著任務結束而消失

換句話說Container僅存活到任務的Process結束時

所以可能mysql DB或是Web Application crash了,則Container exits

至於是在哪邊定義Container中的Process的啟動? →要看Dockerfile

譬如來到docker hub找nginx

link

然後就會看到建立該image的Dockerfile:

同理也可以找到postgres:

下拉看到:

所以其實就是Docker file內的CMD command

在決定Container啟動時執行的Process!

所以同理來看看busybox的image:

link

下拉

sh並不是啟動Process或應用程式的指令,而是shell等待terminal輸入參數執行

因為並沒有實際的terminal,所以就會exits

所以剛剛如下起的Pod才會結束這麼快,因為根本沒有給任務!

所以該如何讓busybox的Pod持續活著?

選項有二:

1.透過interactive node(-it)建立busybox間的terminal

如下建立另一個名稱的busybox Pod,帶著-it:

kubectl run debug-pod-2 --image=busybox -it

此時就會進入到該Container的terminal內:

試著執行exit指令離開terminal後再次確認Pod狀態:

還在運行!

可以再執行以下再次進入到該Pod:

kubectl exec -it {pod名稱} -- sh

在busybox Pod的terminal模式下,就能夠執行我們要做的測試工作如:

nslookup nginx-servie

或是ping:

ping nginx-service

等等之類的測試活動

然後記得結束後要用指令將其移除,如下:

kubectl delete pod {pod name1} {pod name2}

2.在Configuration File內重新定義"command"與"args"

在透過docker指令運行Container時,可以透過指令直接改寫上述的"CMD":

docker run <image name> <command>

(直接改寫在上面的<command>)

但是如果不想改寫CMD,而是想直接提供一個參數來執行呢!?

比如上面busybox本身CMD內容只有"sh"情況下,我們給予參數變成:

"sh my-script.sh"

上述這種形式是沒辦法透過CMD (instruction)來做到

但是有個地方是"ENTRYPOINT" (instruction)可以允許附加其他commands

總結來說:

  • CMD:主要目的是提供預設的Container啟動
  • ENTRYPOINT:executable並持續運行,且允許附加commands
  • 有些情況甚至允許CMD + ENTRYPOINT

下圖可以看看一些範例:

在如上CMD + ENTRYPOINT範例中:

  • ENTRYPOINT是用來定義Container中的Process開始
  • CMD則是提供預設的參數給ENTRYPOINT (instruction)

至於以上的模式又如何套用在Kubernetes?

以一個PodConfiguration File來與Docker File對比:

沒錯!

K8s Pod的command = Docker file的ENTRYPOINT

K8s Pod的args = Docker file的CMD

(完全反過來...!)

也就是K8s Pod來說:

  • ENTRYPOINT是"command"
  • CMD則是"arguments"

在K8s官網doc也有提到這個問題:

link

由以上概念後,接著簡單建立一個測試用的busybox的Pod的yaml檔:

名稱取作bb-pod.yaml

並嘗試給予這個Pod一些args內容整體如下:

完成後儲存!

如上我並沒有定義command(也就是ENTRYPOINT)

但其實也可以只給command如下:

當然也可以兩個(args + command)都來:

最終上述定義的args或command內容將會取代image內原本設定的

其他範例還可以如下定義:

每5秒hello

或是:

甚至合併!!!!

執行建立並確認狀態:

再說一次:

透過K8s Configuration File

可以覆寫掉原本image上面定義的ENTRYPOINT與CMD!!!

然後其意義是反著的:

可以彈性的決定執行image本身定義或是自行給予(透過Configuration File)

不進入Pod內執行commands:

以前的學習或如上範例中都曉得如何進入到Pod內執行要跑的指令如下執行:

kubectl exec -it {Pod name} -- sh

(上述sh可以換成bash)

但有時候為了方便簡單測試一下ping

可能不一定會想特地進到測試用的Pod裡面去!

是的!可以! 就是直接給指令!! 範例如下:

kubectl exec -it {Pod name} -- sh -c "{指令}"

例如

kubectl exec -it {Pod name} -- sh -c "printenv"

我拿到我要的訊息,但我根本沒進到pod內!

或執行以下:

kubectl exec -it busybox-pod -- sh -c "while true; do echo hello; sleep 2; done"

看到每兩秒印出hello ctrl+c離開

當然也可以拿來ping service

kubectl exec -it busybox-pod -- sh -c "ping nginx-service"

或是看看Pod內Conatiner的netstat -lntp如下:

kubectl exec -it busybox-pod -- sh -c "netstat -lntp"

用這樣方式做一些測試工作會相對比較方便!!

另外特別注意

在exec時執行後面帶空格sh或是空格bash

到底該用哪一個?

  • bash 可以當作更強的sh
  • bash有更多功能語法

其實有些image內不支援bash…,只有經典的shell(sh)

sh就好像瘦身版本後的bash

所以嘗試在沒有bash的image執行bash就會像如下這樣錯誤出現!

所以通常就試試bash,沒有在退而求其次用sh

註:OpenShift類似的解決方案

https://www.redhat.com/sysadmin/how-oc-debug-works

參考課程(reference)

--

--

ZONGRU Li
ZONGRU Li

Written by ZONGRU Li

2022/11/17 開源部分個人筆記給LINE "Java程式語言討論區"社群,希望能對社群的技術學習做一點點貢獻.(掩面....記得退訂閱!

No responses yet