[應用] redis 部署與測試教學(含注意事項) === ###### tags: `K8s / app` ###### tags: `Kubernetes`, `k8s`, `app`, `redis`, `使用教學` <br> [TOC] <br> :::info ## 最常用的教學流程 ```bash # 建立 Namespace kubectl create namespace demo # 部署 Redis Pod & Service kubectl -n demo run redis --image=redis --restart=Always kubectl -n demo expose pod/redis --name=redis --port=6379 # 測試 redis 連線 & 操作 redis kubectl -n demo run -it --rm --image=redis --restart=Never redis-shell -- bash # 進 shell 再下 redis-cli -h redis # 操作名為 "hello" 的 queue # redis:6379> LRANGE hello 0 -1 # [] (不用事先建立 "hello") # redis:6379> LPUSH hello apple # ["apple"] # redis:6379> LPUSH hello banana # ["banana", "apple"] # redis:6379> RPUSH hello cherry # ["banana", "apple", "cherry"] # redis:6379> LRANGE hello 0 -1 # ["banana", "apple", "cherry"] # redis:6379> LLEN hello # 3 # redis:6379> LPOP hello # ["apple", "cherry"] # redis:6379> RPOP hello # ["apple"] # redis:6379> LRANGE hello 0 -1 # ["apple"] # redis:6379> LLEN hello # 1 # redis:6379> DEL hello # [] ``` ::: <br> > by gpt4.1 (2025/08/01) ## 步驟 1:建立 Namespace(可選) 建議所有測試資源放進一個專屬 namespace,方便管理和清理。 ```bash kubectl create namespace demo ``` <br> ## 步驟 2:部署 Redis Pod & Service ### 建立 Redis Pod ```bash kubectl -n demo run redis --image=redis --restart=Always ``` > 注意:這會建一個名為 `redis` 的 Pod ### 暴露 Redis Service ```bash kubectl -n demo expose pod/redis --name=redis --port=6379 ``` > 這樣會有一個名為 `redis`、type=ClusterIP 的 service,K8s 內部可用 > Service 名稱將決定你後續 redis-cli 連線時要用的 host 名稱 <br> ## **步驟 3:確認 Redis 運作** ```bash kubectl -n demo get pods kubectl -n demo get svc ``` 或是: ```bash kubectl -n demo get all ``` > 應該看到一個 Running 的 redis pod 與 redis 服務,port 6379。 <br> ## **步驟 4:用 redis-cli 測試連線與操作** ### **正確安全的「互動式」進入方法** > 由於 K8s TTY attach 行為,**建議永遠用「先進 shell,再下 redis-cli」**,保證互動正常。 ```bash kubectl -n demo run -it --rm --image=redis --restart=Never redis-shell -- bash ``` 進到 shell 後執行: ```bash redis-cli -h redis ``` 你應該看到: ``` redis:6379> ``` 這時可自由互動! <br> --- ### **常用 Redis 指令教學** > 指令:不區分大小寫 | 動作 | 指令 | 說明 | | ------- | ------------------- | -------------------- | | 存資料 | `SET foo bar` | 設 foo=bar | | 取資料 | `GET foo` | 查 foo | | 發送訊息 | `LPUSH hello msg1` | 將 msg1 推入 hello list | | 取出訊息 | `LPOP hello` | 從 hello 取出一個 | | 看所有訊息 | `LRANGE hello 0 -1` | 查 hello 目前全部內容 | | 查數量 | `LLEN hello` | 查 hello 目前有幾筆 | | 清空 list | `DEL hello` | 刪除 hello 這個 list | <br> --- ### 一次性(非互動)指令測試法 如果只想查詢而不需進互動模式: ```bash kubectl -n demo run -it --rm --image=redis --restart=Never redis-cli-tmp -- redis-cli -h redis LRANGE hello 0 -1 ``` 這會直接查詢 hello list 的所有內容,然後退出。 <br> ## 補充:多種錯誤與注意事項 ### 1. Pod 名稱/Service 名稱/Namespace 必須對齊! - 如果你 expose 的 service 叫 `myredis`,你連線要寫 `redis-cli -h myredis` - 指令中的 `-n demo` 要和你的 pod/service 所在 namespace 一致 ### 2. 直接用 `kubectl run ... redis-cli ...` 容易卡住或沒 prompt - 這是 K8s attach 與互動命令的機制問題,跟你的指令無關 - 保險作法是「先進 shell,再下 redis-cli」 ### 3. redis 官方 image 有時沒 bash,只能用 sh - 安全起見一律用 `sh` - 若你確定 image 有 bash,當然也可用 bash ### 4. Service/Pod 沒 ready 會導致 redis-cli 卡住 - 若 service 或 pod 沒起來,redis-cli 會等不到主機,畫面一直卡在連線 ### 5. 不要忘了 `--restart=Never` - 若不用 `--restart=Never`,Pod 可能會以 Deployment 形式啟動,造成 Pod 一結束又自動重建,不利測試和管理 ### 6. 善用 --rm 自動清除測試 Pod - `--rm` 保證 Pod 結束即自動刪除,避免殘留 ### 7. **清理所有資源** 最後測完可以一鍵刪除 namespace,回到乾淨狀態: ```bash kubectl delete namespace demo ``` ### 8. 遇到問題怎麼辦? 1. 先確認 pod 和 service 都在 Running 2. 檢查 namespace/名稱有沒有打錯 3. 用 busybox 測 service DNS ```bash kubectl -n demo run -it --rm --image=busybox --restart=Never test -- nslookup redis ``` <br> ## 討論 ### redis-cli 指令,為何要進到 shell 後,才執行 `redis-cli -h redis`? ``` kubectl -n demo run -it --rm --image=redis --restart=Never redis-shell -- redis-cli -h redis ``` 1. 會卡住沒有反應... 2. 因為本地的 terminal 還沒連接上 Pod 內的標準輸入(stdin)、標準輸出(stdout)、標準錯誤(stderr)。 3. `redis-cli` 判斷自己不是互動終端機(isatty() 為 false),就進入「非互動模式」或直接結束、什麼都不顯示 - ### 核心說明 > gpt-4.1 (2025/08/01) K8s 的 `kubectl run` 在「直接執行互動式指令」時,attach/tty 行為有時間差、stdin 問題,甚至各版本 Kubernetes、kubectl、底層 containerd/Docker 行為都可能不同。 ### 1. **為何「直接 run redis-cli」可能卡住/沒 prompt?** * `kubectl run ... -- sh -c "redis-cli -h redis"` 這個用法,**你會預期應該進 redis-cli prompt**,但現實上 K8s/Tty attach 時機不對,導致 redis-cli 可能沒法偵測到 tty,或 stdin 沒 attach 成功,最後就沒有互動 prompt(或你打什麼都沒反應)。 * **這現象有很高機率出現在不同 kubectl/k8s 版本,或你 cluster 的 runtime 實作跟 CLI 工具本身互動偵測方式不合。** * 這也是為什麼大部分 K8s 高手都**強烈建議:真的要做互動,一律直接 exec 到一個已 attach 的 shell,再下互動命令**! ### 2. **為什麼進 shell 再下 redis-cli 就正常?** * 你在已經「attach 完整、stdin/stdout 都建立」的 shell 裡啟動 redis-cli,這時不會 race,stdin/out/tty 都正常,redis-cli 自然偵測得到。 ### 3. **這不是只有你會遇到** * 很多 user、甚至老手都遇過這種「直接執行互動命令沒反應、進 shell 再執行就正常」的狀況。 * 甚至**同一個指令在不一樣的 k8s/dockerd/containerd 環境會有不同結果**。 --- ### 你可以親自實驗: 1. **進 shell 再下**: ```bash kubectl -n demo run -it --rm --image=redis \ --restart=Never redis-shell -- sh # 在 shell 內下 redis-cli -h redis ``` 幾乎百分百能進 prompt。 2. **直接下 redis-cli(sh -c 也一樣)**: ```bash kubectl -n demo run -it --rm --image=redis \ --restart=Never redis-client -- sh -c "redis-cli -h redis" ``` 很容易「沒 prompt」、「沒互動」,甚至打什麼都沒回應! 3. **[補充] 可以 work 的版本**:延遲執行 `redis-cli -h redis` ```bash $ kubectl -n demo run -it --rm --image=redis \ --restart=Never redis-client -- sh -c "sleep 5; redis-cli -h redis" If you don't see a command prompt, try pressing enter. redis:6379> ``` --- ### 實用建議 1. **想要「100%互動」→ 永遠用進 shell 再執行互動命令!** 2. **如果只是要跑一次性 command,可直接下,但不要預期有 prompt。** 3. **你遇到的就是業界實際會遇到的坑,所以大家都推薦用 shell 包起來做互動。** <br> ### [接續] 解釋 Kubernetes 為何「直接執行互動式命令」時常常會卡住沒 prompt,而「先進到 shell 再手動執行互動命令」就沒事? - ### gpt-4.1 (2025/08/01) ## **什麼叫 shell attach?它 attach 到哪裡?** ### 1. **Attach 是什麼?** * 「attach」意思是你的終端機(本地 terminal)**連接上 Pod 內的標準輸入(stdin)、標準輸出(stdout)、標準錯誤(stderr)**。 * 這樣你在本機輸入、Pod 內程式會收到;Pod 輸出會出現在你螢幕上。 <br> ### 2. **Kubernetes Pod 啟動時序**(以 kubectl run 為例) 1. 你下 `kubectl run ... -- sh -c "redis-cli -h redis"` 2. k8s 先建一個 Pod、啟動 Container 3. Container 啟動後,立刻開始執行 command(這時通常是 sh -c "redis-cli -h redis") 4. **同時 kubectl 這邊再嘗試將你的本地 terminal attach 上 container 的 stdin/stdout/tty** <br> ### 3. **Race Condition(賽跑現象)** * **重點:attach 不一定比 command 執行還快!** * 有時候 container 一啟動,command(redis-cli)就已經在跑 * 這時 attach 還沒來得及連上去,redis-cli 啟動時看不到標準輸入/tty * redis-cli 判斷自己不是互動終端機(isatty() 為 false),就進入「非互動模式」或直接結束、什麼都不顯示 * 如果是進 shell(sh、bash),它本身很擅長等 stdin/stdout attach 好再進入互動 * 你這時下 redis-cli,已經 attach 完了,所以一切正常 <br> ### 4. **底層原理:isatty() 判斷** * 幾乎所有 CLI 工具(redis-cli、mysql、psql、python REPL...)都會判斷 stdin 是否是「tty」(互動終端機) * 如果不是,進入非互動模式(沒 prompt,執行一行就退出,或卡住) <br> --- ## **流程圖(邏輯順序)** ```mermaid graph TD A[你下 kubectl run ... -- sh -c redis-cli -h redis] B[Pod 建立,Container 啟動] C[redis-cli 開始跑] D[kubectl 對接 stdin/stdout/tty] E[redis-cli 檢查 isatty 狀態] F[若非互動模式,沒 prompt] A --> B --> C B --> D C --> E D --> E E --> F ``` --- ## 用 shell 的差別 * shell(sh、bash)設計來等待 stdin/stdout/tty 都 attach 完畢才進互動模式,所以永遠不會出這問題。 * redis-cli、mysql 等啟動就判斷是否 tty,判斷到非互動就不理你。 --- ## **Docker 本地和 K8s 的差異** * 本地 docker run 幾乎總是 attach 很快,幾乎不會遇到這問題。 * K8s 必須先排程 pod,建立 container,然後 kubelet 才能幫你 attach,會有短暫時間差。 --- ## **總結:為什麼「先進 shell」就安全?** * shell 已經 attach 好,之後所有子程序(redis-cli)都能正確得到 tty,永遠能互動。 * 直接 run 互動命令有機率來不及 attach(race),tty 判斷失敗,導致卡住或沒 prompt。 --- ## **專業建議** * 任何需要「人機互動 prompt」的命令,在 K8s 永遠「先進 shell,再執行互動命令」! * 若只是一次性查詢(不互動),直接 run 即可。 <br> {%hackmd vaaMgNRPS4KGJDSFG0ZE0w %}