[指令] kubectl ... === ###### tags: `K8s / commands` ###### tags: `Kubernetes`, `k8s`, `kubectl`, `kubectl explain`, `kubectl logs`, `CRD`, `CR`, `finalizers` <br> [TOC] <br> ## kubectl logs | 指令 | 預設行為 | |------|----------| | `kubectl logs <pod>` | 顯示 **整個容器的 log**(除非加了 `--tail` 或其他限制)。 | | `kubectl logs -l <label>` | 只會顯示 **每個符合條件 Pod 的最後 10 行 log**(除非指定 `--tail`)。 | | `kubectl logs -f ...` | 會跟著 log 持續更新(stream 模式)。 | --- ### `--tail=-1`(或指定筆數)情境 ``` # 顯示所有 log kubectl logs -n soperator -l control-plane=controller-manager -c manager --tail=-1 # 顯示最近 100 行 kubectl logs -n soperator -l control-plane=controller-manager -c manager --tail=100 ``` - `--tail=-1` 表示「不要限制 log 行數」,等同於 `cat` 整份 log。 - 為什麼會這樣設計? - 使用 `-l` 可能會選到很多 Pod(例如某些 deployment 有 replicas), - 為了避免意外撈出大量 log,Kubernetes 預設只會顯示每個 Pod 的最後 10 行。 - 小技巧:加上 `--prefix` 幫你辨識是誰的 log ``` kubectl logs -n soperator -l control-plane=controller-manager -c manager --tail=100 --prefix ``` - 每行前面都有 `[PodName]`,便於辨識多個 Pod 的 log 混在一起時,誰是誰。 <br> ## kubectl api-resources ### 列出可查詢清單的資源 ``` kubectl api-resources --verbs=list --namespaced -o name ``` - 執行結果: ``` configmaps endpoints events limitranges persistentvolumeclaims pods podtemplates replicationcontrollers resourcequotas secrets serviceaccounts services ... ... ``` <br> ### 掃描某個 namespace 下的資源 - ### 單行 (使用 xargs) ```bash= kubectl api-resources --verbs=list --namespaced -o name \ | xargs -n 1 -I {} kubectl get {} -n tj-slurm4 --ignore-not-found ``` - ### `-n <count>` - **功能**:每次執行命令時,從輸入中取 `<count>` 個參數,放到一次命令呼叫裡。 - **範例**: - `-n 1`:每次只取一個(最常見的用法)。 - 如果不用 `-n`,預設會盡可能多地把所有參數傳給一次執行(一次呼叫)——但有時候一次傳太多參數會超過系統限制或不符合命令預期。 - ### `-I <replace-str>` - **功能**:指定一個「替換字串」`<replace-str>`,每讀到一筆輸入,就把這個字串替換成輸入的內容,再呼叫一次目標命令。 - **範例**: ```bash echo pod deployment | xargs -n 1 -I {} kubectl get {} -n my-namespace ``` - 先讀到 `pod`,執行 `kubectl get pod -n my-namespace` - 再讀到 `deployment`,執行 `kubectl get deployment -n my-namespace` - ### 單行 (使用 for-loop) ```for res in `kubectl api-resources --verbs=list --namespaced -o name`; do echo "===== $res ====="; kubectl get $res -n tj-slurm4 --ignore-not-found; done``` - ### 多行 ```bash for res in $(kubectl api-resources --verbs=list --namespaced -o name); do echo "===== $res =====" kubectl get "$res" -n tj-slurm4 done ``` <br> ### 為何 api-resources 不一定是 CRD ? - ### gpt-4.1-mini (2025/06/17) ### 1. Kubernetes API 資源類型的分類 Kubernetes 裡的 API 資源可以分成三類: | 類別 | 說明 | 是否 CRD? | | -------------- | -------------------------- | ------- | | **內建資源** | 系統本來就有的資源,比如 Pod、Service 等 | 不是 CRD | | **自訂資源 (CRD)** | 使用者自己定義並新增的資源 | 是 CRD | | **擴充資源** | 透過額外服務新增的資源(非 CRD) | 不是 CRD | --- ### 2. `kubectl api-resources` 是什麼? * 這個指令會列出目前 Kubernetes 裡所有可用的 API 資源,包括內建、自訂和擴充資源。 --- ### 3. 為什麼有些資源不是 CRD? #### 3.1 內建資源 * 系統一開始就有的資源,不用特別新增 CRD,就能直接用。 #### 3.2 擴充資源 * 透過額外服務加進來的資源,不是用 CRD 方式新增,但一樣能用。 --- ### 4. 總結 | 問題 | 答案 | | ---------------------------- | --------------------- | | `kubectl api-resources` 是什麼? | 列出所有可用的 Kubernetes 資源 | | 為什麼有些資源不是 CRD? | 因為它們是系統內建或額外加進來的擴充資源 | | CRD 是什麼? | 用來新增自訂資源的機制 | --- 想知道某資源是不是 CRD,可以用: ```bash kubectl get crd | grep 資源名稱 ``` 找不到不代表不存在,可能是內建或擴充資源。 <br> ## kubectl delete ### 強制刪除 Pod(不等、直接砍) ``` kubectl delete pod <your-pod> --grace-period=0 --force --wait=false ``` - ### 如果還是卡住(通常是有 finalizers),移除 finalizers 後再刪 ```bash # 先看有沒有 finalizers kubectl get pod <your-pod> -o jsonpath='{.metadata.finalizers}{"\n"}' # 直接把 finalizers 清空 kubectl patch pod <your-pod> --type=merge -p '{"metadata":{"finalizers":[]}}' # 再刪一次(保險) kubectl delete pod <your-pod> --grace-period=0 --force --wait=false ``` <br> ### 用 kubectl raw 觀察刪除流程 ``` kubectl delete namespace <your-namespace> --v=8 ``` - 如果想看到 API Server 真正執行的呼叫,可以用高 verbose 模式呼叫刪除: - 它會列出每一個底層的 HTTP request(GET、DELETE)到 `/api/v1/namespaces/tj-slurm2/...`、`/apis/external.metrics.k8s.io/v1beta1/...`,並印出錯誤回應。 <br> --- --- <br> ## Blogs - Q & A ### [How to run kubectl commands inside a container?](https://stackoverflow.com/questions/42642170/) ``` curl http://localhost:8080/api/v1/namespaces/default/pods ``` <br> ### [Kubernetes: kubectl run: command not found](https://stackoverflow.com/questions/55360666/) ``` curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl" ``` - `curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt` `v1.31.0` - `-s, --silent` Silent mode - `-O, --remote-name` Write output to a file named as the remote file - `-L` 應指 Location - [[MDN Web Docs] HTTP 的重定向](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Guides/Redirections) - ### Taiwan LLM (2025/04/10) -L 參數用於告訴 curl 在遇到 HTTP 重定向時自動跟隨新的 URL。 在這個命令中,使用者透過 -L 參數確保即使下載連結(`https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl`)返回 301 或 302 狀態碼指向另一個 URL,curl 也會跟隨該重定向,繼續下載檔案。這避免了手動處理重定向的麻煩,確保無論原始 URL 如何變更,都能正確下載 Kubernetes 的 kubectl 二進位。 同時,-L 與 -O 參數配合使用,允許下載的檔案命名為 URL 的最後一段路徑,而不是預設的檔案名稱。這樣 維持了檔名的可預測性,方便後續使用。 總結:-L 參數的作用是自動跟隨重定向,確保下載過程的 完整性和可靠性。 - ### gpt-o3-mini-high (2025/04/10) 在 curl 中,`-L` 參數的作用是讓 curl 自動跟隨 HTTP 重定向(redirects)的 URL。例如,當伺服器返回 3xx 狀態碼(如 301、302 等)時,curl 會根據回應中的 Location 標頭自動發出新的請求,直到獲取最終的資源位置。 在這個例子中: ```bash curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl" ``` - `-L` 使 curl 自動跟隨可能的重定向。 - `-O` 則指示 curl 使用遠端檔案的檔名來儲存下載的文件。 這樣,即使初始 URL 發生重定向,使用了 `-L` 參數後,curl 仍能正確跟蹤到最終的檔案位置並下載它。 - ### Google Gemini 2.0 Flash Thinking (experimental) `curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl"` 在上面的 `curl` 命令中,`-L` 參數的作用是 **指示 `curl` 跟隨 HTTP 重定向 (HTTP redirects)**。 以下是更詳細的解釋: * 當伺服器收到一個 HTTP 請求,但請求的資源已經移動到另一個 URL 時,伺服器通常會發送一個 HTTP 重定向響應(例如,HTTP 301 Moved Permanently 或 HTTP 302 Found)。 * 預設情況下,`curl` 不會自動跟隨這些重定向。它會將重定向響應作為結果返回。 * 使用 `-L` 參數後,`curl` 會檢查伺服器的響應頭。如果響應頭包含指示重定向的資訊(例如,`Location` 頭),`curl` 會自動向新的 URL 發送另一個請求,並繼續下載資源。 在這個特定的命令中,`-L` 確保了如果 Kubernetes 發布的穩定版本 URL 發生了重定向,`curl` 仍然能夠找到並下載 `kubectl` 二進制檔案。 總之,`-L` 參數使得 `curl` 能夠處理網站或資源移動的情況,確保命令能夠成功地獲取到最終的目標資源。 - ### kubectl 檔案大小: 54M - ### 接續 kubectl 安裝指令: ```bash # Make the kubectl binary executable: chmod +x ./kubectl # Move the binary in to your PATH: sudo mv ./kubectl /usr/local/bin/kubectl # Test to ensure the version you installed is up-to-date: kubectl cluster-info kubectl version ``` - ### 測試 kubectl 指令 ``` $ kubectl version Client Version: v1.31.0 Kustomize Version: v5.4.2 Server Version: v1.29.4 WARNING: version difference between client (1.31) and server (1.29) exceeds the supported minor version skew of +/-1 $ kubectl cluster-info Kubernetes control plane is running at https://10.96.0.1:443 CoreDNS is running at https://10.96.0.1:443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy ``` - 留意這個 endpoint `https://10.96.0.1:443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy` <br> --- --- <br> ## 討論 ### `rollout restart` vs `scale --replicas=<amount>` - ### Question ``` # rollout 指令會無法重啟 controller,controller 會起不來 $> kubectl -n slurm rollout restart statefulset.apps/slurm-controller # 只能用 scale 指令: replicas: 1 -> 0 -> 1 $> kubectl -n slurm scale statefulset.apps/slurm-controller --replicas=1 ``` 不確定兩者在底層的差異 - ### gpt-4.1 (2025/07/115) 你問得非常好,這也是很多在操作 StatefulSet(或 Deployment)時常見的疑惑。 ### 兩種重啟 StatefulSet 的方法 1. **rollout restart** ```bash kubectl -n slurm rollout restart statefulset.apps/slurm-controller ``` * **作用**:會「溫和地」逐台重新建立 Pod,背後原理是更新 `pod-template-hash`,強制重新 create Pod,通常用於 image 有更新或想無痛重啟應用程式。 * **K8s 運作**:它其實是**patch**了 StatefulSet 的 `spec.template.metadata.annotations`(加個時間戳),讓 StatefulSet controller 感知到「Pod 內容變了」,然後滾動更新(restart)。 * **常見問題**:有些狀況,像 StatefulSet 管理的 controller pod 內部有鎖(或 DB/lock 等資源沒釋放),Pod 就算 delete,也無法順利啟動,或因資源未釋放而卡住。 2. **scale** ```bash kubectl -n slurm scale statefulset.apps/slurm-controller --replicas=0 kubectl -n slurm scale statefulset.apps/slurm-controller --replicas=1 ``` * **作用**:直接將 StatefulSet **縮為 0**,把所有 pod 都「殺掉」(不是滾動,而是直接刪除),再開回 1,等於「全新啟動」。 * **K8s 運作**:這是**完全刪除 pod**,並從 0 開始建立新 pod,這對於有些 sticky/lock 問題特別有效。 * **常見用途**:這是 K8s 裡最「物理」的 restart,尤其解決 stuck 或 dirty state 問題最直接。 --- ### 你遇到的情況 * **rollout restart 無法重啟**: 多半是 StatefulSet(或裡面的應用)有 resource lock、volume lock、或其他 dirty state,導致 Pod restart 起來時卡住。 * **scale to 0 再 scale to 1 可以**: 因為你強制「全關全開」,把所有 pod 狀態清除掉,再讓 controller 重新 create,通常 sticky/lock 問題都能解決。 --- ### 進階差異 | 方法 | 適合用途 | 風險 | 原理 | | --------------- | -------------- | ------------------ | -------------------- | | rollout restart | 溫和、滾動更新(不中斷服務) | 卡 lock/dirty state | patch + recreate pod | | scale 0 → 1 | 強制重啟、清除所有狀態 | 全部 shutdown 期間無服務 | 完全 kill pod 再重建 | --- ### 建議 * **正常服務重啟** → rollout restart。 * **服務卡死/lock stuck/Dirty State** → scale to 0/1。 * StatefulSet 比 Deployment 更容易遇到 lock/stickiness 問題,因為 volume/persistent storage 是 sticky 的。 --- ### 一句話總結 * `rollout restart` 只是 patch metadata 讓 K8s 滾動重建 pod,但有時 sticky 狀態無法解掉。 * `scale to 0/1` 是最強制的 reset,可以解掉 sticky/lock 問題,但會有停機。 - ### 自我小結 | 指令 | 作用 | 狀態 | |------|-----|-----| | `rollout restart` | 透過 patch 修改 annotations | pod 狀態可能沒有清除 | | `scale --repliacas` | 直接 kill pod 重來 | pod 狀態會被 reset | - 簡單講 - `rollout restart` -> 溫和重啟 (狀態:維持原本狀態) - `scale --repliacas` -> 暴力重啟 (狀態:Terminating -> Init) - ### sticky 狀態,中文為何?如何解釋? - ### gpt-4.1 (2025/07/115) ### 中文翻譯 * **sticky 狀態**:常被翻譯為「**黏著狀態**」、「**黏滯狀態**」、「**黏著性問題**」、「**卡住狀態**」,或依上下文直接描述為「某個資源被鎖住,無法釋放」。 * 在 K8s 或 IT 維運語境裡,**sticky** 比較像是「某個狀態/資源**被綁定**、**未釋放**,導致後續動作都受影響」。 ### 說明範例 * **技術解釋**: 當一個 Pod 因為資源(像是 Volume、lock file、socket 等)還被綁著沒釋放,導致重啟時仍然無法正常啟動,就稱為進入了 sticky 狀態。 * **白話說法**: 「Pod 之前使用過的某些資源沒有被釋放(例如:檔案鎖還在、資料卷沒卸載),所以即使重啟,還是會卡住。這種就叫做 sticky 狀態。」 --- ### 建議用詞 * **正式一點**: * 黏著狀態 * 黏滯狀態 * 資源未釋放狀態 * 資源卡住狀態 * **口語/維運常用**: * 卡住狀態 * 被綁住 --- ### 例句 * 這個 StatefulSet pod 因為 volume 還沒卸載,導致 sticky 狀態,重啟後還是卡住。 * 如果遇到 sticky 狀態,建議直接 scale 到 0 再 scale 回 1,強制清掉所有綁定資源。 <br> {%hackmd vaaMgNRPS4KGJDSFG0ZE0w %}
×
Sign in
Email
Password
Forgot password
or
Sign in via Google
Sign in via Facebook
Sign in via X(Twitter)
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
Continue with a different method
New to HackMD?
Sign up
By signing in, you agree to our
terms of service
.