K8s快速實戰(三)

今天是學習Kubernetes的第三天,昨天我們學習了許多Kubernetes中重要的元件,像是DeploymentPodNamespaces等等。今天我們要繼續學習更多Kubernetes的元件,透過了解這些元件的功能知道Kubernetes是怎麼在各種情境中運用的。

Selector

Selector的功能相當簡單,它的功能就是將兩個不同的元件可以彼此掛勾,它使用labels來辨識、描述以及把資源組合在一起,它使用key-value組合。

以下方的例子來說,Service 會根據 selector 找尋到對應的 Pod,啟動後我們可以利用 kubectl get ep [serviceName] 查看Service是否有連接到指令的Pod

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
apiVersion: v1
kind: Service
metadata:
name: myservice
spec:
ports:
- port: 80
targetPort: 80
selector:
app: myapp
type: front-end

apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
type: front-end
spec:
containers:
- name: nginx-container
image: nginx
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 250m
memory: 256Mi
ports:
- containerPort: 80

測試時遇到的突發狀況

我原先以為port80可以直接連線,但是實際上出錯了。因為type沒有設定,預設的ClusterIP是沒有辦法對外連線的,ClusterIP 類型,它只在 Kubernetes Cluster 內部可用。解決方法有

  1. 明確定義type,以及
  2. 使用port forwarding把本地的8080forward到80之中。
    如: kubectl port-forward service/myservice 8080:80

多容器的Pods

你可能會有疑問說,為甚麼要在一個Pods裡面跑多個Container呢?我們已經可以在Node外層管理自動建立與移除Pods,向是這樣在一個Pods裡面建立多個Container難道不會很不好管理嗎?
以下我們舉出幾個例子,告訴你這麼做有什麼好處。

1. Sidecar - Typical pattern
假設你有一個App會把API的log寫入一個log檔案中,而每天你要把log檔案拋到一個整合的FTP中。
這時拆開的好處有:

  • 主程式碼會很乾淨,拋送FTP的邏輯不會寫在App裡面,實現了關注點分離。
  • 拆開之後,元件的重用性就提升了,如果之後我們需要拋報表的話,拋送這段可以完全照用,不必重寫。
    main pod&Helper pod

2. Adapter - Typical pattern
假設你有一個App會回傳一個複雜的監控資訊,你就可以建立一個AdapterApp複雜的監控資訊,封裝成Monitor Service方便使用的通用格式。透過實作這個模式,你可以在不必調整App的程式碼的狀況下得到你的簡潔結果。
main pod&adapter

3. Ambassador - Typical pattern
假設你今天有一個App需要把資料存入到資料庫中,但是問題來了,DB近期可能因應上雲政策要把MySQL移動到Amazon Aurora,在沒有辦法確認資料庫的最終選擇前,透過建立一個Ambassador,你可以讓App只關注在重要的邏輯上,實際資料庫使用的Driver等等的交給Ambassador處理就好。
main pod&ambassador

Kubernetes網路

Kubernetes網路的小整理

Network Concept

同一個Pod的Container的溝通

Pod Communication

位於不同Pod的Container溝通

Inter Pod Communication

來自Node之外的請求

Pod Communication from outside

Workloads

  • 簡單來說,Workload就是一個跑在Kubernetes上面的應用程式,包含以下元件都是一個Workload
    • Pod (Represents a set of running containers)
    • ReplicaSet
    • Deployment
    • DeamonSet (Provide node-local facilities, such as a storage driver or network plugin)
    • Tasks that run to completion
      • Job
      • CronJob

ReplicaSet

ReplicaSet負責管理Pod Replica與生命週期,以提供自我修復能力。目的就是為了確保Pod數量符合預期。

雖然聽起來ReplicaSet已經有完整的功能了,但實務上當可以建立ReplicaSet時,建議先建立Deployments

注意!雖然Deployment有包含ReplicaSet的功能,但這兩者不是對立的關係,原因是因為建立Deployment時,也會隱含建立ReplicaSet。我們建議應該操作高級的抽象而不是底層的元件。

yaml

replicaSet

Deployment

  • 跟剛才提到的一樣,他是ReplicaSet的高級抽象,元件提供了以下功能:Self-healScaleUpdateRollback.
  • 實務上你的每一個微服務就代表一個Deployment。詳情可以看看下圖。

透過ReplicaSet與Deployment管理Pods

alt text

Deployment 重要欄位解說

alt text

yaml

alt text

DaemonSet

DaemonSet是一種控制器,它常常用來確保在每一個Node上都執行一個特定的Pod。這種設計常見於固定的系統需求,比方說收集log、監控服務等等。
它會

  • 每個 Node 都會部署一個 Pod(除非被排除)
  • 自動新增 Pod 到新加入的 Node
  • 刪除 DaemonSet 時不會自動刪除其產生的 Pod(除非加上 –cascade)
    此外你還可以做一些特別設定,比方說使用Toleration參數,讓DaemonSet不在master node上面執行。

yaml

alt text

StatefulSet

StatefultSet是一個有點特別的元件,一般來說在Kubernetes中的服務屬於**Stateless(無狀態)**的,Stateless意思是它本身不保存狀態,像是資料不會被暫存在應用程式內,每一次的Pod重啟,其實都是不同的IP等等。但當應用需要保存資料狀態(例如資料庫、叢集節點、主從架構),就需要StatefulSet。

Statefult的特性

  • Deployment不同,StatefulSet維持讓每一個Pods都有一個固定的辨認身分
  • 每一個Pods都有持久化的,固定的辨認身分。如 web-0, web-1, web-2。
  • 如果Pod掛了,他會使用同樣的辨認身分換一個新的Pod出來。
  • 建立與刪除都是有序地,也就是以0~X 的順序建立Pods, 以X~0的順序刪除Pods。
  • Containers本身以Stateless設計的。實務上,最好是使用Cloud provider database services來取代StatefulSet功能。
  • 刪除StatefulSet不會刪除PVCs,你必須手動刪除。

StatefulSet怎麼設定

想要建立一個StatefulSet,你應該先將ServiceclusterIP定義為None,使它變成一個Headless serviceHeadless service意思是這個Pod不會擁有一個虛擬IP,而是會使用DNS名稱,比如說:mysql-0.mysql

接著,在你定義好的StatefulSet中綁定剛剛的Service,這樣一來你的StatefulSet中每一個Pod都會有一個固定名稱(mysql-0, mysql-1, mysql-2…)與一個固定的儲存空間(pvc/data-mysql-0 等),設定如圖:
alt text

補充:

剛剛提到了StatefulSet可以用來在資料庫上面,那當我們可以有多個資料庫時,就會誕生出資料庫之間的同步問題,此時一個常見的同步解決方案是,採用讀寫分離的架構設計資料庫。

但資料庫此時我們就必須要分得出,哪一個資料庫是允許WRITE的,哪些資料庫只允許READ,這點原先的Stateless設計中是做不到的。

如果是StatefulSet,我們就可以透過將mysql-0.mysql固定成一個可以寫入的資料庫,讓其他的mysql-1.mysqlmysql-2.mysql…只允許讀取。

1
2
3
// 程式碼的話就可以這樣設定
WRITE -> mysql-0.mysql:3306
READ -> mysql.mysql:3306 # Service 名稱會 round-robin 所有 replica

常見Kubernetes 指令

Command Description
1 kubectl create -f [yml file] Create a pod
2 kubectl exec -it [podName] -c [containerName] -- /bin/sh Exec into a container
3 kubectl logs [podname] -c [containerName] Get the logs for a container
4 kubectl delete [yaml file] --force --grace-period=0 Clean up
5 kubectl apply -f [definition.yml] Create a ReplicaSet
6 kubectl get rs List all ReplicaSet
7 kubectl describe rs [rsName] Get Info
8 kubectl delete -f [yml file] Delete a ReplicaSet
9 kubectl delete rs [rsName] Delete a ReplicaSet
Deployment cheatsheet
1 kubectl create deploy [deploymentName] --image=[imageName] --replicas=X --port=80 The imperative way
2 kubectl get deploy List deployments
3 kubectl describe deploy [deploymentName] Get Info
4 kubectl get rs List Replica
5 kubectl delete deploy [deploymentName] Delete a deployment
6 kubectl get ds List DaemonSets
7 kubectl describe ds [rsName] Get info
StatefulSet
1 kubectl get sts List StatefulSets
2 kubectl describe sts [rsName] Get info

學習資源

  1. (https://www.youtube.com/watch?v=kTp5xUtcalw)

K8s快速實戰(三)
https://clark1945.github.io/2025/11/08/My-third-day-started-learning-Kubernetes/
Author
Clark Liu
Posted on
November 8, 2025
Licensed under