[軟體概念入門系列][Workshop] Linux與後端服務 #3

Brett Yu
Brett’s dev log
Published in
13 min readNov 27, 2023

前置準備

  1. 安裝minikube
    https://minikube.sigs.k8s.io/docs/start/

成功執行以下指令

#minikube不能用root user啟動, 需要先執行以下指令把你的user加入docker group中
sudo usermod -aG docker {linux user name} && newgrp docker


minikube start
alias kubectl="minikube kubectl --"
minikube dashboard

並可以存取畫面上顯示的網址

http://127.0.0.1:38099/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/

Workshop目標

  1. 理解K8S中Pod, Service, Deployment及Ingress的運作方式
  2. 將workshop #2的container都改為Pod, Nginx部分改為Ingress

你會學習到

  • 如何使用minikube作為一個本機的K8S cluster來部署物件
  • 透過kubectl指令或minikube dashboard查看各種物件的執行狀況
  • 使用deployment配合replica sets管理pods
  • 使用service實作load balance, 並配合ingress實作反向代理

建立python api pod及service

  1. 建立兩個pod

將以下script建立為新檔案 pod.yaml

apiVersion: v1
kind: Pod
metadata:
name: my-pod-1
labels:
app: workshop-app
spec:
containers:
- name: flask-api-container
image: bretthiggs/flask-api:1.0
ports:
- containerPort: 3000
---
apiVersion: v1
kind: Pod
metadata:
name: my-pod-2
labels:
app: workshop-app
spec:
containers:
- name: flask-api-container
image: bretthiggs/flask-api:1.0
ports:
- containerPort: 3000

以上yaml檔表示會建立兩個pod, 分別為my-pod-1及my-pod-2
每個pod裡面都只包含一個container, 會由docker hub取得image
而image名稱版本為bretthiggs/flask-api:1.0

接著執行kubectl建立這兩個pod

kubectl apply -f pod.yaml

#確認pod是否正確產生
kubectl get pods

2. 建立service以存取pods

將以下script建立為service.yaml

apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: workshop-app
type: NodePort
ports:
- protocol: TCP
port: 3001
targetPort: 5566
nodePort: 30390

以上yaml會建立service物件, 並透過selector “workshop-app”將請求導到有篩選到的pod
port: 在k8s cluster中service本身要被內部服務呼叫用的port
targetPort: service要對應到的pod使用的port
nodePort: service要開放到k8s cluster外部被呼叫用的port

接著執行kubectl建立這個service

kubectl apply -f service.yaml

#確認service是否正確產生
kubectl get service

3. 確認service是否真的可被連接

以下curl可以重複執行幾次, 可看到請求會被分配到不同的pod上

#從minikube內部, 按下ctrl+d可以離開minikube ssh
minikube ssh
curl {service的cluster-ip}:3001

#從minikube外部
minikube ip
curl {minikube的ip}:30390

4. 查看pod log, 並透過minikube dashboard觀察相關物件

kubectl logs {pod name}

minikube dashboard

以deployment建立python api pod

由於自行管理pod並不是一個有效率的方式, 因此接下來我們會操作使用deployment並借助replica sets來部署並管理多個pod

  1. 移除剛剛建立的pod並撰寫deployment設定檔
kubectl delete -f pod.yaml

將以下script建立為deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment
spec:
replicas: 3
template:
metadata:
labels:
app: workshop-app
spec:
containers:
- name: flask-api-container
image: bretthiggs/flask-api:1.0
ports:
- containerPort: 3000
selector:
matchLabels:
app: workshop-app

以上script將會以template中的內容建立3個pod, 而selector代表這個deployment透過”workshop-app”這個label取得並管理符合條件的pod

接著執行以下指令套用deployment並確認相關物件有產生

kubectl apply -f deployment.yaml
kubectl get deployment
kubectl get pods

2. 確認pods可透過service存取

執行剛剛的語法確認請求有被分配到三個pod

#從minikube內部, 按下ctrl+d可以離開minikube ssh
minikube ssh
curl {service的cluster-ip}:3001

#從minikube外部
minikube ip
curl {minikube的ip}:30390

3. 調整deployment中的replicas數量並套用, 觀察replica sets及pod行為

將deployment.yaml中的replicas從3改為7, 並重新執行以下指令

kubectl apply -f deployment.yaml
kubectl get replicaset
kubectl get pods

反覆這樣的動作調整replicas並觀察replica sets及pod
也可透過dashboard觀看

以deployment, service, ingress建立python api pod並設定反向代理

  1. 移除先前的deployment及service

執行以下指令移除deployment及service

kubectl delete -f deployment.yaml
kubectl delete -f service.yaml

2. 建立分成兩個群組的pod分群

將以下script建立成deployment-reverse-proxy.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment-a
spec:
replicas: 2
template:
metadata:
labels:
app: workshop-app-group-a
spec:
containers:
- name: flask-api-container-group-a
image: bretthiggs/flask-api:1.0
ports:
- containerPort: 3000
selector:
matchLabels:
app: workshop-app-group-a
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment-b
spec:
replicas: 2
template:
metadata:
labels:
app: workshop-app-group-b
spec:
containers:
- name: flask-api-container-group-b
image: bretthiggs/flask-api:1.0
ports:
- containerPort: 3000
selector:
matchLabels:
app: workshop-app-group-b

接著執行以下指令建立deployment

kubectl apply -f deployment-reverse-proxy.yaml

3. 建立兩個service分別對應到兩個pod的分群

將以下script建立成service-reverse-proxy.yaml

apiVersion: v1
kind: Service
metadata:
name: my-service-group-a
spec:
selector:
app: workshop-app-group-a
type: NodePort
ports:
- protocol: TCP
port: 3001
targetPort: 5566
---
apiVersion: v1
kind: Service
metadata:
name: my-service-group-b
spec:
selector:
app: workshop-app-group-b
type: NodePort
ports:
- protocol: TCP
port: 3002
targetPort: 5566

接著執行以下指令建立service

kubectl apply -f service-reverse-proxy.yaml

4. 建立ingress將指定的路徑對應到個別的service

將以下script建立為ingress-reverse-proxy.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: workshop-reverse-proxy.com
http:
paths:
- path: /group-a
pathType: Prefix
backend:
service:
name: my-service-group-a
port:
number: 3001
- path: /group-b
pathType: Prefix
backend:
service:
name: my-service-group-b
port:
number: 3002

以上script幾點簡述
host: 代表要定義的domain
path: 代表此domain下符合的路徑要做的處理
service: 符合的路徑要轉導到的service名稱
port: 對應到該service開放的port
nginx.ingress.kubernetes.io/rewrite-target: 代表符合的路徑被導轉後要改寫url成什麼值, 以此範例來說會被改寫為根目錄

綜合以上
workshop-reverse-proxy.com/group-a會被導轉到service “my-service-group-a” 以存取到後面的pod, 而url會被改寫為“/”, 亦即url會變成
“http://{my-service-group-a的cluster-ip}:3001/”

workshop-reverse-proxy.com/group-b以此類推

如果你的minikube從來沒有啟用過ingress, 請先執行以下指令, 否則可以跳過此步

minikube addons enable ingress
kubectl get pods -n ingress-nginx

接著執行以下指令建立ingress

kubectl apply -f ingress-reverse-proxy.yaml

5. 驗證ingress是否有效

接著我們要設定wsl中的host file, 以讓workshop-reverse-proxy.com可以解析為minikube ip

sudo vim /etc/hosts

請在檔案中加入一條記錄, 若你是從workshop #1做過來的請留意這條可能已經存在, 就直接調整ip即可

{minikube ip} workshop-reverse-proxy.com

接著我們可以嘗試以下指令看是否ingress有生效

curl workshop-reverse-proxy.com/group-a
curl workshop-reverse-proxy.com/group-b

Recap

回顧我們這次做過的內容

  1. 撰寫pod描述檔並以docker image建立對應的pod, 使用service讓pod可以被存取
  2. 撰寫deployment描述檔管理對應的pod, 調整replica數量套用後, K8S會自動增減pod
  3. 使用ingress依據不同的path將請求導轉到service, 以實現反向代理

延伸思考

  1. K8S怎麼判斷pod是否健康, 何時需要產生新的pod來取代舊的
  2. K8S有辦法依據pod資源使用量來auto scaling嗎
  3. 如何使用K8S實作藍綠部署或其他的部署策略
  4. 如何用ConfigMap, Secret管理設定檔

--

--