什麼是 Kubernetes? - ianchen0119/Introduce-to-5GC GitHub Wiki
Kubernetes(或是 K8s)用於管理、部署、擴充容器化的應用程式,該專案最初由 Google 設計,並捐贈給 CNCF 維護。 本篇文章並不會詳細的介紹如何建構 Kubernetes 環境或是基於 Kubernetes 的應用程式,而是盡可能的加深讀者對於 Kubernetes 的認知。
在真正了解 Kubernetes 之前,我們必須定義一下什麼是 image:
- Image 是一個囊括依賴套件與設定檔的套件(它是靜態的,而非處於執行狀態的程式)
而 Pod 是 K8s 中的最小單位,它可以包含一個以上的 Container,但實務上通常只會包含一個 Container:
apiVersion: v1
kind: Pod
metadata:
namespace: default
name: bastion
spec:
containers:
- name: centos
image: centos:latest
command:
- sh
- -c
- while true; do sleep 60; done
- 上方程式碼描述了一個運作著 centos 的 pod,它會運作在 default 命名空間。
- Kubernetes 的物件皆可以使用 yaml 檔案描述,提供一個通用、標準化的開發方式,這麼做還能夠降低物件與物件之間的耦合度。
Kubernetes 可以由多個 worker node 組合成一個 cluster,為部署在 Kubernetes 上的服務增加保障,下圖是 Kubernetes 的架構圖:
上圖取自 Kubernetes 官方文件。
參考上圖,我們可以將它拆成兩個面向來看:
- Master node (control plane)
- Worker node
Master node 負責調度所有的 worker node,在 Master node 上會運作四個非常重要的 process,它們分別是:
- API server
- etcd
- Controller
- Scheduler
API server 是整個 Kubernetes cluster 的入口點,它負責處理來自 client(使用 kubectl)或是 kubelet 的請求。
etcd 是一個分散式的資料庫專案,它使用 raft 演算法作為共識機制,能夠保證分散式節點上的資料一致性。
- Kubernetes 使用它存放最重要的資訊
- 如果有 Pod 故障,它會以 etcd 上存放的資料復原 Pod
- etcd 是 key/value based database
- 被 Hyperledger fabric 採納
Kubernetes 的內部會有多個 controller,它們分別負責不同的任務。
- 當使用者使用 kubectl,相關命令會改變 etcd 所儲存的內容,而非直接影響 kubernetes 的狀態。
- Controller 負責觀察這些狀態的變化,並且以最快的速度響應這些變化
Scheduler 負責管理哪些 Pod 能夠獲得 cpu 資源。
- 當它收到來自 API server 的請求,如果有 Pod 需要分配到資源,它會請求目標 target node 上的 kubelet 執行這個 Pod。
Worker node 可以是實體機器或是虛擬機器,它是應用程式的執行者,每個 Worker node 會運作:
- Container runtime
- kubelet
- kube-proxy
- Container runtime 運作在每一個工作節點上
- Container runtime 負責執行 container
- kubelet 負責節點上 pod 的排程
- kubelet 能夠與 container 以及 worker node 溝通
- kube-proxy 同樣在每個節點上工作
- 負責流量的轉發:外部流量或是 pod 之間的流量該導向哪(也就是 service 物件)
- 底層使用 iptables 實現轉發功能,所以在效能上還有進步空間(像是利用先前介紹的 xdp 技術)
kubectl apply -f YOUR_POD.yaml
kubectl apply
屬於 Declarative Management,我們可以使用它動態的調整先前已經套用的設定。
間單來說,如果我們已經建立好一個 Pod,並且我們希望修改它的部分設定,那我們可以再撰寫一個 yaml 檔案說明清楚想要調整的欄位後再使用 kubectl apply
。
kubectl create -f YOUR_POD.yaml
kubectl create
屬於 Imperative Management,使用 kubectl create
修改 Pod 的設定時,它會先刪除現有的全部設定再建立新的,因此,如果重複的使用 kubectl create
套件同一份 yaml 檔案會得到失敗的結果。
主要有三種:
- 使用 shared volumes
- 使用 IPC (Inter-process communications)
- 使用 Network
namespace 是一個用來組織、隔離 Cluster 資源的機制:
- 使用 RoleBindings 做到分隔租戶以及授權存取
- 分割出多個虛擬的 sub-clusters
- 執行資源管理策略,可以使用 ResourceQuatas 或是 LimitRanges 實現
- 使用 NetworkPolicy 區分網路環境
建立 namespace 的方法:
kubectl create namespace ian
建立一個名為 ian
的 namespace。
取得當前 cluster 的所有 namespaces:
kubectl get namespace
指定某個 namespace 為預設的 namespace:
kubectl config set-context -current -namespace=ian
- Request 代表請求的最小資源
- Limit 代表最大上限
如果一個 pod 要求 500m CPU,並且主機有 2 CPU,那麼這一個 pod 可以獲得 2 CPU 的硬體資源
Labels 是一對可辨識的 key/value 形式的標籤,像是:
- "release": "GA"
- "env": "production"
- "stage": "dev"
等等,key 與 value 可以由我們自由定義。 如果將多個 Label 貼上 Pod,我們就可以清楚地知道這個 Pod 的狀態、功能、開發進度...等細節。
此外,K8S 更是提供了 Label selectors 幫助我們根據 label 關鍵字找到我們想要使用的 Pod:
$ kubectl get pods -l environment=production,tier=frontend
或是使用 set-based
的方式尋找:
kubectl get pods -l 'environment in (production, qa),environment notin (frontend)'
Kubernetes 提供了許多物件,像是 Pod、Service、ReplicaSet、Deployment,為了降低物件之間的耦合性,它們在管理資源皆是使用 label 與 selector 做到的,比如說: 假設我撰寫了一份 replicaSet 規格文件:
# Source: https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: frontend
labels:
app: guestbook
tier: frontend
spec:
# modify replicas according to your case
replicas: 3
selector:
matchLabels:
tier: frontend
template:
metadata:
labels:
tier: frontend
spec:
containers:
- name: php-redis
image: gcr.io/google_samples/gb-frontend:v3
當我使用 kubectl apply -f rs.yaml
後,相關的 controller 會去追蹤符合 tier=frontend
條件的 pod 的數量是否為 3,如果不是,Kubernetes 會為我們控制它的數量。
更多使用方法可以參考 kubernetes.io/docs/。
前面提到的 Labels 是具有識別用途的標籤,相對的,K8S 也提供了不具識別用途的標籤 Annotations,我們可以在 Annotations 上面打上開發者的聯絡方式或是其他方便開發者使用的資訊。 最後還是要強調,Annotations 與 Labels 最大的差異就是 Annotations 並不會被 K8S 使用。
apiVersion: v1
kind: Pod
metadata:
namespace: ian
name: nginx-1
labels:
app: nginx
annotations:
version: latest
contact: [email protected]
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
為 Pod 打上標籤後,可以使用:
$ kubectl describe pods YOUR_POD
查看 Pod 的細節。
- 部屬多個 Pod 的方式
kubectl run web-depl --image="<image>" --replicas=2 --labels="ver=1, app=web, env=production"
kubectl delete deployment --all
或是使用 selector:
kubectl delete deployment --selector="<cond>"
因為 Pods 會被 K8S 動態的控制,所以具有 volatile 的特性,為了讓服務實體可以穩定的將流量或是請求導向它們,我們會需要 Service 的幫忙。
![image](https://user-images.githubusercontent.com/42661015/183261159-839a2e1f-683a-4556-aca7-b8a065180924.png)
ClusterIP
類型的 Service 只有 Cluster 內部的成員可見,這可以用於保護某些特定的 Service 不被外網存取。
LoadBalancer
類型的 Service 就是一個平衡附載器,外部成員可以透過存取這類的 Service 取得想要的服務。
如果是在 GKE 上使用 LoadBalancer
,GKE 會為它分配一個 IP Address 並將流量導向該服務。
NodePort
類型的 Service 比 ClusterIP
多了指定端口,若不指定端口則會交給 K8S 去處理。
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
type: NodePort
selector:
app: nginx
ports:
- name: http
port: 80
protocol: TCP
targetPort: 80
![](https://user-images.githubusercontent.com/42661015/183261301-0b780761-5519-4cce-b1cc-ca33df1dd0db.png)
以下 Configure 使用 GKE 產生:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
ingress.kubernetes.io/backends: '{"k8s1-813d351a-lab-nginx-1-80-ed0b083e":"Unknown","k8s1-813d351a-lab-nginx-2-80-1be8d82e":"Unknown"}'
ingress.kubernetes.io/forwarding-rule: k8s2-fr-1ze89fat-lab-outer-s7si9ddi
ingress.kubernetes.io/target-proxy: k8s2-tp-1ze89fat-lab-outer-s7si9ddi
ingress.kubernetes.io/url-map: k8s2-um-1ze89fat-lab-outer-s7si9ddi
creationTimestamp: "2022-03-16T13:10:50Z"
finalizers:
- networking.gke.io/ingress-finalizer-V2
generation: 1
managedFields:
- apiVersion: networking.k8s.io/v1
fieldsType: FieldsV1
fieldsV1:
f:spec:
f:defaultBackend:
.: {}
f:service:
.: {}
f:name: {}
f:port:
.: {}
f:number: {}
f:rules: {}
manager: GoogleCloudConsole
operation: Update
time: "2022-03-16T13:10:50Z"
- apiVersion: networking.k8s.io/v1
fieldsType: FieldsV1
fieldsV1:
f:metadata:
f:annotations:
.: {}
f:ingress.kubernetes.io/backends: {}
f:ingress.kubernetes.io/forwarding-rule: {}
f:ingress.kubernetes.io/target-proxy: {}
f:ingress.kubernetes.io/url-map: {}
f:finalizers:
.: {}
v:"networking.gke.io/ingress-finalizer-V2": {}
f:status:
f:loadBalancer:
f:ingress: {}
manager: glbc
operation: Update
time: "2022-03-16T13:12:05Z"
name: outer
namespace: lab
resourceVersion: "500208"
uid: 03c27b4d-f3e4-4753-a48a-64abcb638cf8
spec:
defaultBackend:
service:
name: nginx-1
port:
number: 80
rules:
- http:
paths:
- backend:
service:
name: nginx-2
port:
number: 80
path: /nginx-2/*
pathType: ImplementationSpecific
- backend:
service:
name: nginx-1
port:
number: 80
path: /nginx-1/*
pathType: ImplementationSpecific
status:
loadBalancer:
ingress:
- ip: 34.111.224.185