從 Kind 到 K3s: Local Registry 與 Production 部署流程
DevOps 學習筆記
用 kind 學完 K8s 核心概念後, 換成 k3s 並搭配 local registry, 讓本機練習更貼近 production 的部署流程。同時釐清 K8s 網路隔離機制, 以及 production 不會用 kubectl set image 的原因
為什麼從 kind 換成 k3s
kind 學概念夠用, 但有幾個跟 production 差很遠的地方:
| 功能 | kind | k3s | Production (GKE/AKS) |
|---|---|---|---|
| Ingress controller | 沒有, 要自己裝 | 內建 Traefik | 內建 cloud LB |
| Service LoadBalancer | 拿不到外部 IP | 內建 ServiceLB, 拿得到 IP | 真的外部 IP |
| 多 Node | 可以但很少人用 | 輕鬆開 multi-node | 自動管理 |
| Local storage | 要自己設 | 內建 local-path provisioner | 自動 (Persistent Disk) |
| Image 載入 | kind load (非標準) |
從 registry pull (標準流程) | 從 Artifact Registry pull |
k3s 是完整的 K8s, 只是更輕量。裝完就有 Ingress 和 LoadBalancer 可以用, 不需要 port-forward
安裝與設定
|
|
kind 安裝完會自動設定 kubeconfig, 但 k3s 把 kubeconfig 放在 root-only 的路徑, 需要手動複製到 ~/.kube/config, 讓一般使用者的 kubectl 能讀到
Local Registry — 模擬 Production 的 Image 流程
kind 的做法 (非標準)
|
|
這是 kind 專屬的指令, production 環境不存在。實際上 K8s 是從 registry pull image 的
k3s + Local Registry (標準流程)
跑一個 local registry container, 跟 Docker Hub / GHCR / Artifact Registry 是同一種東西, 只是在本機:
|
|
注意 port mapping: registry 內部固定聽 5000, 對外可以用任意 port。5050:5000 代表 host 的 5050 → container 的 5000
Build → Push → Pull 流程
|
|
跟 production 的對比:
|
|
只有目的地不同, 流程一模一樣。K8s 看到 Deployment 裡的 image: 127.0.0.1:5050/go-api:0.0.3, 會自己去 registry pull
Deployment YAML
|
|
K8s 網路隔離
為什麼本機連不到 Service
K8s cluster 有自己獨立的網路, 跟 host 網路是隔離的:
|
|
go-api 這個 DNS 名字只有 K8s 內部的 CoreDNS 認識, 本機的 DNS 不知道它是什麼
從 cluster 內部驗證 Service Discovery
|
|
kubectl run --rm -it 的參數:
--rm: remove Pod when done (like docker run –rm)-i: interactive, connect stdin-t: allocate tty-- sh: run shell inside the Pod
在 Pod 裡面用 http://go-api:8080 能連到, 是因為 Pod 在 K8s 網路裡, 可以查 CoreDNS
Production 怎麼讓外部連進來
本機連不到 cluster 內部, 那外部使用者怎麼連?
| 方式 | 用途 |
|---|---|
kubectl port-forward |
開發測試用, 不是 production 做法 |
Service type: LoadBalancer |
k3s / cloud 環境, 拿到真的外部 IP |
| Ingress | production 標準做法, 一個入口路由到多個 Service |
kind 拿不到 LoadBalancer IP, 只能用 port-forward。k3s 內建 ServiceLB, 改成 type: LoadBalancer 就能拿到外部 IP
Production 部署流程 vs 練習捷徑
練習時的捷徑 (不要帶到 production)
|
|
Production 的做法
改 YAML → commit → push → CI/CD 自動 apply:
|
|
|
|
為什麼不用 kubectl set image
kubectl set image |
YAML + git push | |
|---|---|---|
| 紀錄 | 無, 誰改的都不知道 | git history 完整追蹤 |
| 回滾 | kubectl rollout undo |
git revert (更可靠) |
| 審核 | 無法 review | PR review 後才 merge |
| 一致性 | cluster 狀態跟 YAML 不一致 | git = single source of truth |
這就是 GitOps 的核心 — git 裡的 YAML 永遠代表 production 的真實狀態。ArgoCD 這類工具就是監控 git repo, YAML 一變就自動 sync 到 cluster
從 Docker Compose 到 K8s 的對應
如果已經有跑在 EC2 + Docker Compose 的服務, 轉 K8s 時的對應關係:
| Docker Compose | K8s |
|---|---|
services: each service |
Deployment + Service YAML |
ports: |
Service (ClusterIP / LoadBalancer) |
environment: |
ConfigMap / Secret |
volumes: |
PersistentVolumeClaim (PVC) |
depends_on: |
K8s 不管啟動順序, app 要自己 retry |
logging: awslogs |
GKE 內建送 Cloud Logging |
restart: always |
Deployment 預設行為 (reconciliation loop) |
| nginx reverse proxy | Ingress controller 取代 |
轉換時 application code 和 Dockerfile 完全不用改, 改的只是部署方式 — 從 Compose 換成 K8s YAML
References
- k3s Documentation — k3s 安裝與設定
- Docker Registry HTTP API V2 — registry 的 HTTP API 規格
- Kubernetes Networking Model — K8s 網路模型
- Kubernetes Service — Service types 與 service discovery