返回首頁Kubernetes

Kubernetes 核心物件完整教學:Pod、Deployment、Service 一次學會

19 min 分鐘閱讀
#Kubernetes#K8s#Pod#Deployment#Service#ConfigMap#Secret#核心物件

Kubernetes 核心物件完整教學:Pod、Deployment、Service 一次學會

Kubernetes 核心物件完整教學:Pod、Deployment、Service 一次學會

學 Kubernetes,最重要的是搞懂「物件」。

Pod、Deployment、Service⋯⋯這些名詞一開始很容易搞混。但只要理解它們各自的角色,Kubernetes 就會變得清晰很多。

這篇文章會帶你完整走過 Kubernetes 最重要的核心物件。

Kubernetes 的基本介紹,請參考 Kubernetes 完整指南。架構說明請參考 Kubernetes 架構完整解析


Pod 完整解析

Pod 是 Kubernetes 最基本的部署單位。

Pod 是什麼

一句話說明: Pod 是一個或多個容器的組合,是 Kubernetes 調度的最小單位。

重點理解:

  • 你不會直接部署容器,你部署的是 Pod
  • Pod 裡的容器共享網路和儲存
  • Pod 是短暫的,隨時可能被刪除重建
特性說明
最小單位Kubernetes 不管理單個容器,管理 Pod
共享網路同 Pod 內的容器用 localhost 溝通
共享儲存可以掛載同一個 Volume
短暫性Pod 死了就死了,不會復活

單容器 vs 多容器 Pod

單容器 Pod(最常見):

一個 Pod 裡只有一個容器。90% 以上的情況都是這樣。

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
spec:
  containers:
  - name: nginx
    image: nginx:1.25
    ports:
    - containerPort: 80

多容器 Pod:

當多個容器需要緊密協作時才使用。

模式說明範例
Sidecar輔助主容器日誌收集、代理
Ambassador代理外部連線資料庫代理
Adapter標準化輸出監控指標轉換

Sidecar 範例:

apiVersion: v1
kind: Pod
metadata:
  name: app-with-logging
spec:
  containers:
  - name: app
    image: my-app:1.0
    volumeMounts:
    - name: logs
      mountPath: /var/log/app
  - name: log-collector
    image: fluentd:latest
    volumeMounts:
    - name: logs
      mountPath: /var/log/app
  volumes:
  - name: logs
    emptyDir: {}

主容器寫日誌,Sidecar 容器收集日誌。兩個容器共享同一個 Volume。

Pod 生命週期

Pod 有明確的生命週期狀態:

狀態說明
Pending已被接受,但容器還沒準備好
Running至少有一個容器在執行
Succeeded所有容器成功執行完畢
Failed至少有一個容器失敗
Unknown無法取得 Pod 狀態

生命週期流程:

建立 Pod
    ↓
Pending(調度中、下載映像檔)
    ↓
Running(容器執行中)
    ↓
Succeeded / Failed / 被刪除

重要觀念:

Pod 不會「修復」自己。如果 Pod 掛了,它就是掛了。新的 Pod 會被建立來取代它(如果你有用 Deployment)。

Pod YAML 完整範例

apiVersion: v1
kind: Pod
metadata:
  name: my-app
  labels:
    app: my-app
    environment: production
spec:
  containers:
  - name: app
    image: my-app:1.0
    ports:
    - containerPort: 8080
    resources:
      requests:
        memory: "128Mi"
        cpu: "250m"
      limits:
        memory: "256Mi"
        cpu: "500m"
    env:
    - name: DATABASE_URL
      valueFrom:
        secretKeyRef:
          name: db-secret
          key: url
    livenessProbe:
      httpGet:
        path: /health
        port: 8080
      initialDelaySeconds: 30
      periodSeconds: 10
    readinessProbe:
      httpGet:
        path: /ready
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 5
  restartPolicy: Always

重要欄位說明:

欄位用途
labels標籤,用於選擇和分類
resources資源請求和限制
env環境變數
livenessProbe存活檢查
readinessProbe就緒檢查
restartPolicy重啟策略

插圖:白板上繪製的 Pod 生命週期流程圖

場景描述: 白板上繪製的 Pod 生命週期流程圖,從左到右依序標示 Pending、Running、Succeeded/Failed 三個狀態方塊,中間有箭頭連接,每個狀態下方有簡短文字說明該狀態的含義。需要顯示的中文字:等待中、執行中、完成、失敗

視覺重點:

  • 主要內容清晰呈現

必須出現的元素:

  • 依據描述中的關鍵元素

需要顯示的中文字:

顏色調性: 專業、清晰

避免元素: 抽象圖形、齒輪、發光特效

Slug: kubernetes-pod-lifecycle-diagram


Deployment 深入解析

實際上你幾乎不會直接建立 Pod。你會建立 Deployment。

為什麼需要 Deployment

直接建立 Pod 的問題:

問題說明
沒有自動重啟Pod 掛了就沒了
沒有擴展機制無法輕鬆增減數量
更新很麻煩要手動刪除舊的、建立新的
沒有版本控制無法回滾

Deployment 解決這些問題:

功能說明
自動維持數量掛一個補一個
宣告式擴展改個數字就好
滾動更新零停機時間更新
版本歷史可以快速回滾

ReplicaSet 的角色

Deployment 不直接管理 Pod,它管理 ReplicaSet,ReplicaSet 再管理 Pod。

Deployment
    ↓ 管理
ReplicaSet
    ↓ 管理
Pod, Pod, Pod

為什麼要這樣設計?

更新時,Deployment 會建立新的 ReplicaSet,逐步把 Pod 從舊 ReplicaSet 轉移到新 ReplicaSet。舊的 ReplicaSet 保留著,方便回滾。

Deployment YAML 範例

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  labels:
    app: my-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: app
        image: my-app:1.0
        ports:
        - containerPort: 8080
        resources:
          requests:
            memory: "128Mi"
            cpu: "250m"
          limits:
            memory: "256Mi"
            cpu: "500m"
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0

關鍵欄位:

欄位說明
replicas要維持幾個 Pod
selector用什麼標籤選擇 Pod
templatePod 的模板
strategy更新策略

滾動更新機制

當你更新 Deployment(例如換新的映像檔):

kubectl set image deployment/my-app app=my-app:2.0

滾動更新過程:

初始狀態:3 個 v1 Pod

第一步:建立 1 個 v2 Pod
v1: ●●●
v2: ●

第二步:v2 Ready 後,刪除 1 個 v1
v1: ●●
v2: ●

第三步:建立第 2 個 v2
v1: ●●
v2: ●●

第四步:刪除 1 個 v1
v1: ●
v2: ●●

第五步:建立第 3 個 v2
v1: ●
v2: ●●●

第六步:刪除最後 1 個 v1
v1:
v2: ●●●

完成!

策略參數:

參數說明範例值
maxSurge最多可以多幾個 Pod1 或 25%
maxUnavailable最多可以少幾個 Pod0 或 25%

回滾操作

更新出問題?可以快速回滾。

# 查看更新歷史
kubectl rollout history deployment/my-app

# 回滾到上一版
kubectl rollout undo deployment/my-app

# 回滾到指定版本
kubectl rollout undo deployment/my-app --to-revision=2

# 查看回滾狀態
kubectl rollout status deployment/my-app

🏗️ 需要 Kubernetes 架構規劃?

正確的物件設計影響系統的可維護性和穩定性。讓專家幫你規劃。

👉 預約架構諮詢


Service 網路存取

Pod 有了,但外界怎麼存取它?這就是 Service 的工作。

Service 的必要性

問題:Pod 的 IP 會變。

  • Pod 重啟後 IP 會變
  • Pod 被重新調度到其他 Node,IP 會變
  • 擴展時新 Pod 有新的 IP

Service 提供穩定的存取點:

特性說明
固定 IPService 的 ClusterIP 不會變
DNS 名稱可以用名稱存取,例如 my-service
負載均衡自動分配流量到後端 Pod

ClusterIP、NodePort、LoadBalancer

Kubernetes 提供三種 Service 類型:

類型存取方式使用場景
ClusterIP叢集內部 IP內部服務(預設)
NodePortNode IP + Port測試、開發
LoadBalancer外部負載均衡器生產環境對外服務

ClusterIP 範例:

apiVersion: v1
kind: Service
metadata:
  name: my-app-service
spec:
  type: ClusterIP
  selector:
    app: my-app
  ports:
  - port: 80
    targetPort: 8080

只能從叢集內部存取:http://my-app-service:80

NodePort 範例:

apiVersion: v1
kind: Service
metadata:
  name: my-app-nodeport
spec:
  type: NodePort
  selector:
    app: my-app
  ports:
  - port: 80
    targetPort: 8080
    nodePort: 30080

可以從外部存取:http://<node-ip>:30080

LoadBalancer 範例:

apiVersion: v1
kind: Service
metadata:
  name: my-app-lb
spec:
  type: LoadBalancer
  selector:
    app: my-app
  ports:
  - port: 80
    targetPort: 8080

雲端會自動建立負載均衡器,分配外部 IP。

Service 與 Endpoint

Service 怎麼知道要把流量送到哪些 Pod?

透過 Label Selector:

# Service
spec:
  selector:
    app: my-app  # 選擇有這個 label 的 Pod

Endpoint 自動維護:

Kubernetes 會自動建立和維護 Endpoint 物件,記錄符合 selector 的 Pod IP。

# 查看 Endpoint
kubectl get endpoints my-app-service

輸出:

NAME             ENDPOINTS                                   AGE
my-app-service   10.1.0.5:8080,10.1.0.6:8080,10.1.0.7:8080  1h

流量路徑:

Client → Service IP → kube-proxy → Pod IP

插圖:三欄式比較圖

場景描述: 三欄式比較圖,分別標示 ClusterIP、NodePort、LoadBalancer 三種 Service 類型,每欄下方有簡單的網路流向示意,顯示流量從外部或內部如何到達 Pod,使用不同顏色區分內部和外部流量。需要顯示的中文字:叢集內部、外部存取、負載均衡

視覺重點:

  • 主要內容清晰呈現

必須出現的元素:

  • 依據描述中的關鍵元素

需要顯示的中文字:

顏色調性: 專業、清晰

避免元素: 抽象圖形、齒輪、發光特效

Slug: kubernetes-service-types-comparison


ConfigMap 與 Secret

應用程式需要設定。把設定寫死在容器裡不是好主意。

設定外部化

為什麼要外部化設定?

問題說明
環境差異開發、測試、生產的設定不同
安全性密碼不該寫在程式碼裡
靈活性改設定不用重建映像檔

Kubernetes 的解法:

物件用途
ConfigMap一般設定(非敏感)
Secret敏感資訊(密碼、金鑰)

ConfigMap 使用

建立 ConfigMap:

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  DATABASE_HOST: "db.example.com"
  DATABASE_PORT: "5432"
  LOG_LEVEL: "info"
  config.json: |
    {
      "feature_flags": {
        "new_ui": true
      }
    }

使用方式一:環境變數

apiVersion: v1
kind: Pod
metadata:
  name: my-app
spec:
  containers:
  - name: app
    image: my-app:1.0
    env:
    - name: DATABASE_HOST
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: DATABASE_HOST
    # 或一次載入全部
    envFrom:
    - configMapRef:
        name: app-config

使用方式二:掛載為檔案

apiVersion: v1
kind: Pod
metadata:
  name: my-app
spec:
  containers:
  - name: app
    image: my-app:1.0
    volumeMounts:
    - name: config-volume
      mountPath: /etc/config
  volumes:
  - name: config-volume
    configMap:
      name: app-config

ConfigMap 的內容會變成 /etc/config/ 下的檔案。

Secret 使用

建立 Secret:

apiVersion: v1
kind: Secret
metadata:
  name: db-credentials
type: Opaque
data:
  username: YWRtaW4=      # base64 編碼的 "admin"
  password: cGFzc3dvcmQ=  # base64 編碼的 "password"

用 kubectl 建立(比較方便):

kubectl create secret generic db-credentials \
  --from-literal=username=admin \
  --from-literal=password=password

使用方式:

apiVersion: v1
kind: Pod
metadata:
  name: my-app
spec:
  containers:
  - name: app
    image: my-app:1.0
    env:
    - name: DB_USERNAME
      valueFrom:
        secretKeyRef:
          name: db-credentials
          key: username
    - name: DB_PASSWORD
      valueFrom:
        secretKeyRef:
          name: db-credentials
          key: password

Secret 的安全性

重要提醒:

事實說明
Base64 不是加密任何人都可以解碼
etcd 預設不加密Secret 明文存在 etcd
需要額外措施啟用 etcd 加密、用外部工具

增強安全性的方式:

方式說明
etcd 加密啟用 encryption at rest
RBAC限制誰可以讀取 Secret
外部方案HashiCorp Vault、AWS Secrets Manager
Sealed Secrets可以安全地存在 Git

💡 K8s 設定管理有困難?

正確的設定管理是穩定運作的基礎。讓我們幫你建立最佳實踐。

👉 預約免費諮詢


其他重要物件

除了上面介紹的核心物件,還有幾個常用的物件需要認識。

Namespace

用途: 邏輯隔離資源

apiVersion: v1
kind: Namespace
metadata:
  name: production

使用場景:

場景範例
環境隔離dev、staging、production
團隊隔離team-a、team-b
專案隔離project-x、project-y

常用指令:

# 列出所有 namespace
kubectl get namespaces

# 在特定 namespace 操作
kubectl get pods -n production

# 設定預設 namespace
kubectl config set-context --current --namespace=production

PersistentVolume 與 PVC

Pod 是短暫的,但有些資料需要持久保存。

PersistentVolume (PV): 叢集管理員提供的儲存空間

apiVersion: v1
kind: PersistentVolume
metadata:
  name: my-pv
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: standard
  hostPath:
    path: /data/my-pv

PersistentVolumeClaim (PVC): 使用者請求儲存空間

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
  storageClassName: standard

在 Pod 中使用:

apiVersion: v1
kind: Pod
metadata:
  name: my-app
spec:
  containers:
  - name: app
    image: my-app:1.0
    volumeMounts:
    - name: data
      mountPath: /data
  volumes:
  - name: data
    persistentVolumeClaim:
      claimName: my-pvc

Ingress

用途: HTTP/HTTPS 路由,比 LoadBalancer 更靈活

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
spec:
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 80
  - host: web.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 80

優點:

功能說明
域名路由不同域名到不同服務
路徑路由/api 和 /web 到不同服務
TLS 終止統一處理 HTTPS
成本多個服務共用一個 LB

更詳細的網路說明,請參考 Kubernetes 網路架構指南

DaemonSet、StatefulSet、Job

DaemonSet: 每個 Node 跑一個 Pod

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: log-collector
spec:
  selector:
    matchLabels:
      app: log-collector
  template:
    metadata:
      labels:
        app: log-collector
    spec:
      containers:
      - name: fluentd
        image: fluentd:latest

使用場景: 日誌收集、監控 agent、網路插件

StatefulSet: 有狀態應用

特性說明
穩定網路 IDpod-0、pod-1、pod-2
穩定儲存每個 Pod 有自己的 PVC
有序部署按順序啟動和關閉

使用場景: 資料庫、分散式系統(Kafka、Elasticsearch)

Job / CronJob: 一次性或定期任務

# Job:執行一次
apiVersion: batch/v1
kind: Job
metadata:
  name: backup-job
spec:
  template:
    spec:
      containers:
      - name: backup
        image: backup-tool:1.0
      restartPolicy: Never

# CronJob:定期執行
apiVersion: batch/v1
kind: CronJob
metadata:
  name: daily-backup
spec:
  schedule: "0 2 * * *"  # 每天凌晨 2 點
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: backup
            image: backup-tool:1.0
          restartPolicy: Never

FAQ:常見問題

Q1: Pod 和容器有什麼差別?

容器 是實際執行的程序。 Pod 是 Kubernetes 的調度單位,包含一個或多個容器。

你可以把 Pod 想成容器的「殼」,提供共享的網路和儲存。

Q2: 什麼時候用多容器 Pod?

只有當容器需要緊密協作時。

判斷標準:

  • 這些容器一定要一起跑嗎?
  • 它們需要共享檔案系統嗎?
  • 它們的生命週期一樣嗎?

如果答案都是「是」,用多容器 Pod。否則用多個單容器 Pod。

Q3: Deployment 和 ReplicaSet 差在哪?

ReplicaSet 只負責維持 Pod 數量。 Deployment 在 ReplicaSet 之上,加上滾動更新、回滾等功能。

實務上,你幾乎只會直接使用 Deployment。

Q4: ClusterIP、NodePort、LoadBalancer 怎麼選?

場景選擇
內部服務ClusterIP
開發測試NodePort
生產對外LoadBalancer 或 Ingress

Q5: ConfigMap 改了,Pod 會自動更新嗎?

要看使用方式:

方式自動更新
環境變數❌ 需要重啟 Pod
Volume 掛載✅ 會自動更新(有延遲)

如果用環境變數,改 ConfigMap 後要重啟 Pod 才會生效。


下一步

學會這些核心物件後,你可以:

目標行動
動手實作閱讀 Kubernetes 入門教學
深入網路閱讀 Kubernetes 網路架構指南
了解架構閱讀 Kubernetes 架構完整解析
選擇工具閱讀 Kubernetes 工具生態系指南

🚀 需要 Kubernetes 導入協助?

從核心物件設計到生產環境部署,CloudInsight 提供完整的技術支援。

👉 立即預約諮詢


延伸閱讀


參考資料

需要專業的雲端建議?

無論您正在評估雲平台、優化現有架構,或尋找節費方案,我們都能提供協助

預約免費諮詢

相關文章