Chrome Pointer

2023年9月12日 星期二

如何理解Kubernetes的架構 - 筆記

k8s是軟件定義的數據中心,和傳統數據中心有所不同


Cluster集群裡面有很多Nodes,
有Master Nod和Worker Nodes,
每個Node裡面可以有好幾個Pods。

每個pod裡面通常會有一個Container或多個Container(利用docker容器化技術),
Container裡面有應用程式,像是php、python都可以當成一個ocntainer,
你可以寫想要的應用程式版本,本地端沒有的時候會去docker hub抓取。












理解k8s的pod






kubectl apply -f xxx.yaml


kubectl get all


取得 pod:
kubectl get pod xxx
kubectl get pods xxx
kubectl get po xxx

- Pod是k8s雲平台的虛擬機資源

理解K8s的NodePort Service



Service當中有SelectorPod當中有Labels
Selector的app名稱 和 Lables的app名稱相同時,
Service會連接至app名稱相同的Pod裡面。

type: LoadBalancer只有公有雲才可以用,像是AWS之類的。
本地只能使用type: NodePort。
port: 80   代表server反向代理要暴露的 集群端口port
target port: 80 代表server轉接到後台的pod的端口port
若target port不填寫,默認會是port的值,此例為80

把下面圖片的8080改成80,
Chrome進來Service時的反向代理(proxy)暴露 集群端口是port,
從Service指向後台pod裡的是target port。
metadata=詮釋資料;後設資料(用於解釋或幫助理解信息的數據)
裡面的name代表kind: Sevice的名稱。

nodePort: 31080代表本機要暴露給外網的端口,之後測試時要輸入這個port值

為了要讓kind: Service找的到kind: Pod,
kind: Pod必須要加上labels,

kind: Service的selector的app: xxx 和 kind: Pod的labels的app: xxx名字沒有相同的話,
Service就會找不到Pod。


kubectl apply -f .    #可以一次把當前目錄下的所有文件都發佈

describe :顯示一個或多個資源的詳細狀態,


kubectl delete svc xxx    #刪除Service
kubectl delete po xxx     #刪除Pod


Service主要負責反向路由和附載均衡(LoadBalancer)

通過Service實現藍綠發佈(Blue/Green Deployment)

藉由version的修改 及 Selector和Labels的配合 來達到藍綠發佈
當要升級時,只要把Service中的 Selector的version從v1.0.0 改成 v1.0.1,
就可以進到藍色的pod當中,

若新版本有問題,想要回退(roll back)時,
只要修改Selector的version從 v1.0.1 改成 v1.0.0,
Service又會指向綠色的Pod了。


apiVersion: v1
kind: Service
metadata:
  name: petclinic
spec:
  ports:
    - name: http
      port: 8080
      targetPort: 8080
      nodePort: 31080
  selector:
    app: petclinic
    version: v1.0.1
  type: NodePort
apiVersion: v1 kind: Pod metadata: name: petclinic-v1.0.0 labels: app: petclinic version: v1.0.0 spec: containers: - name: petclinic image: spring2go/spring-petclinic:1.0.0.RELEASE
apiVersion: v1 kind: Pod metadata: name: petclinic-v1.0.1 labels: app: petclinic version: v1.0.1 spec: containers: - name: petclinic image: spring2go/spring-petclinic:1.0.1.RELEASE







kubectl grt po --show-labels  #可以顯示出所有pod的LABELS
kubectl describe svc petclinic  #可以查看名叫petclinic的 Services的詳細訊息



kubectl delete po --all  #--all可以刪除全部的pods
kubectl delete svc --all  #--all可以刪除全部的services

一直存在的service/kubernates,就算被刪掉後,
再使用kubectl get all來查看,會發現又出現了,

service/kubernates是default的,所以一直都在,不會被刪掉,
但我們創建的service/petclinic成功刪除了。

理解k8s的ReplicaSet

下圖為傳統的做法,並非k8s的做法,
下面中間綠色的盒子代表 反向代理(Reverse proxy)

Pod是ephemeral(轉瞬即逝的),代表它隨時會掛掉,
掛掉後它自己是不會自動恢復的,

要透過ReplicaSet才能達到自癒能力(self-healing)
也就是你可以輸入一個ReplicaSet,並設定Pod的數量,

假設Pod數量為3,
當有Pod死掉,並導致Pod數量小於3時,
就會自動產生新的Pod,使Pod的數量一直維持在3個,此為self-healing

並會把流量隨機分配到三個Pod中。

ReplicaSet發佈規範樣例。

template: 對應到之前的Pod發佈規範,
template裡面和 Pod相對應。

apiVersion: extensions/v1beta1 kind: ReplicaSet metadata: name: petclinic spec: replicas: 3 template: metadata: labels: app: petclinic #pods的標籤 spec: containers: - name: petclinic image: spring2go/spring-petclinic:1.0.0.RELEASE
1. petclinic-replicaset.yml

apiVersion: v1 kind: Service metadata: name: petclinic spec: ports: - name: http port: 8080 targetPort: 8080 nodePort: 31080 selector: app: petclinic #尋找所有 具有petclinic標籤的pods type: NodePort
2. petclinic-service.yml




刪除一個Pod後,馬上又生成了一個新的Pod

kubectl describe rs petclinic  #rs是ReplicaSet的簡寫,查看詳細訊息

kubectl delete rs petclinic  #會把名叫petclinic的ReplicaSet刪除掉

當我們刪除掉ReplicaSet後,它裡面產生的Pods也會一起被刪掉
可以看到Pods的STATUS皆為Terminating,
之後再輸入一次kubectl get all,可以發現Pod皆已刪除。

理解滾動發佈和k8s的Deployment

一種高級發佈策略,
依次替換老版本,
逐步升級到新版本。

發佈過程中,
應用不中斷,
用戶體驗平滑。

下圖為滾動發佈,v1為舊版本;v2為新版本。

此範例 每批次發佈的v2數量為1個,
實際上,每批次發佈的數量可以>1
而且每批次發佈的數量也可以不同,你要同時發佈5個v2也可以。

Deployment把ReplicaSet進行封裝,
使用Deployment來進行滾動發佈
將舊版本滾動(Rolling)到新版本,
同時也可以將新版本滾動(Rolling)回舊版本

Selector下面的matchLabels標籤必須要和 template下面的labels一致,
表示Deployment要選擇管理的是帶有 app: petclinic的 Pods。

apiVersion: apps/v1 kind: Deployment metadata: name: petclinic spec: selector: matchLabels: app: petclinic minReadySeconds: 10 replicas: 3 template: metadata: labels: app: petclinic spec: containers: - name: petclinic image: spring2go/spring-petclinic:1.0.1.RELEASE #<<在這裡進行滾動發佈,
                                                             1.0.0 or 1.0.1都在這裡更改
1. petclinic-deployment.yml

apiVersion: v1 kind: Service metadata: name: petclinic spec: ports: - name: http port: 8080 targetPort: 8080 nodePort: 31080 selector: app: petclinic #尋找所有 具有petclinic標籤的pods type: NodePort
2. petclinic-service.yml




Deployment可以用來進行滾動式發佈,

使用kubectl rollout可以對Deployment進行控制,

kubectl rollout history deployment/petclinic
REVISION
        1          #代表v1.0.0版本
        2          #代表v1.0.1版本 目前版本

kubectl rollout undo deployment/petclinic  #回退到上一個版本

kubectl rollout status deployment/petclinic  #查看滾動式發佈 Pods的變動過程

kubectl rollout history deployment/petclinic
REVISION
        2          #代表v1.0.1版本
        3          #代表v1.0.0版本 目前版本

kubectl rollout undo deployment/petclinic --to-revision=2 #指定退回版本2
REVISION
        3          #代表v1.0.0版本
        4          #代表v1.0.1版本 目前版本 (回退回版本2, 版本2就是v1.0.1)
kubectl rollout delete deploy petclinic #刪除deployment
刪除Deployment後,
所有ReplicaSet都會一起被刪掉,
所有Pods也都會一起被刪掉。

ReplicaSet當中包含Pods,
Deployment當中包含ReplicaSet
這也是為什麼我們寫yml檔案的時候只需要寫兩個的原因
(Service和Deployment)

因為Deployment把ReplicaSet封裝起來了,
你寫了Deployment裡面就包含ReplicaSet和Pods。



理解k8s的ClusterIP Service內部反向代理

ClusterIp負責內部的服務訪問



apiVersion: v1
kind: Pod
metadata:
  name: mysql
  labels:
    app: mysql
spec:
  containers:
    - name: mysql
      image: mysql:5.7
      env:
        - name: MYSQL_ROOT_PASSWORD
          value: petclinic
        - name: MYSQL_DATABASE
          value: petclinic


apiVersion: v1 kind: Service metadata: name: mysql spec: selector: app: mysql ports: - name: tcp port: 3306 targetPort: 3306 type: ClusterIP


apiVersion: apps/v1 kind: Deployment metadata: name: petclinic spec: selector: matchLabels: app: petclinic replicas: 1 template: metadata: labels: app: petclinic spec: containers: - name: petclinic image: spring2go/spring-petclinic:1.0.1.RELEASE env: - name: SPRING_PROFILES_ACTIVE value: mysql - name: DATASOURCE_URL value: jdbc:mysql://mysql/petclinic
              #進入mysql的Service裡面,使用ClusterIP連到後台mysql的pod #mysql數據庫名稱
- name: DATASOURCE_USERNAME value: root - name: DATASOURCE_PASSWORD value: petclinic - name: DATASOURCE_INIT_MODE value: always


apiVersion: v1 kind: Service metadata: name: petclinic spec: ports: - name: http port: 8080 targetPort: 8080 nodePort: 31080 selector: app: petclinic type: NodePort



不能一次發佈(apply)全部的文件,
因為文件彼此之間有依賴關係

petclinic 依賴於mysql,
所以需要先把mysql給發佈。

發佈順序:
mysql-pod.yml >> 

mysql-service.yml >> 

petclinic-deployment.yml >>

petclinic-service.yml 



💛ClusterIP - 內部服務訪問
💛NodePort - 對外暴露服務
💛LoadBalancer - 對外暴露服務(公有雲 ex: AWS)

Deployment/Pod 發佈規範中可以添加環境變量(env),給Pod傳遞啟動參數

有狀態服務(ex: mysql),一般只能部署一個Pod實例。

理解K8s的Namespace和Kube-Dns


為什麼左邊petclinic的deployment可以連到mysql的Service呢?
網域到IP地址的轉換需要DNS的服務,

k8s有內建Dns服務
因此可以完成網域(mysql)到ClusterIP地址(10.96.235.168)的轉換。
kubectl get ns #ns是namespace的縮寫 #可以看到已經存在的名詞空間(ns)

如果只輸入kubectl get all,會無法看到名詞空間(Namespace),因為它是隱藏的。

你可以客製化,訂製屬於自己的名詞空間,
若沒有特別設定,
k8s預設將自動指向default裡面。
kubectl get all -n kube-system #可以看到kube-system(名詞空間)的內部
若沒有特別加上 -n 去指定哪一個Namespace,
預設都是進入default名詞空間當中

kube-apiserver, kube-controller, kube-proxy, kube-scheduler等等,
皆是住在kube-system裡面。

service/kube-dns是k8s的dns,可以透過訪問kube-dns,把網域轉換成ClusterIP地址。
petclinic(左上角藍色的pod)會先去訪問kube-system(名詞空間)裡面的kube-dns,
得到mysql-service的ClusterIP位址後,
才能對mysql-service發起調用,
調用成功才能訪問mysql-pod。

步驟:
💙petclinic-pod想要訪問mysql-pod,且它已在環境env設定mysql的網域(mysql)>> 

💚petclinic-pod先訪問kube-dns,並且得到mysql-service的ClusterIP>>

💛petclinic-pod藉由mysql-service的ClusterIP位址,成功進入mysql-service>>

💜找到mysql-service就可以訪問mysql-pod,此時,petclinic-pod已成功訪問mysql-pod。


Namespace(名詞空間)是k8s提供的資源邏輯隔離機制
若沒有指定名詞空間,我們運行的資源會住在default當中

kube-system是k8s的系統名詞空間,住著k8s的系統組件,
kube-dns住在kube-system中。

理解K8s的ConfigMap

ConfigMap可以綁定到Pod的環境變量(env)中,配置更新傳播





apiVersion: v1 kind: ConfigMap metadata: name: petclinic-config-v2 data: SPRING_PROFILES_ACTIVE: mysql DATASOURCE_URL: jdbc:mysql://mysql/petclinic DATASOURCE_USERNAME: root DATASOURCE_PASSWORD: petclinic DATASOURCE_INIT_MODE: always TEST_CONFIG: test_config_v2
1. petclinic-config.yml

Deployment和Service中間加上" --- "做為分隔,可以寫進同一個.yml文件當中
apiVersion: apps/v1 kind: Deployment metadata: name: petclinic spec: selector: matchLabels: app: petclinic replicas: 1 template: metadata: labels: app: petclinic spec: containers: - name: petclinic image: spring2go/spring-petclinic:1.0.1.RELEASE envFrom: - configMapRef: name: petclinic-config-v2 #在這裡訪問petclinic-config
                                           並把env環境變數匯入petclinic中 --- apiVersion: v1 kind: Service metadata: name: petclinic spec: ports: - name: http port: 8080 targetPort: 8080 nodePort: 31080 selector: app: petclinic type: NodePort
2. petclinic-svc.yml


apiVersion: v1 kind: Pod metadata: name: mysql labels: app: mysql spec: containers: - name: mysql image: mysql:5.7 env: - name: MYSQL_ROOT_PASSWORD value: petclinic - name: MYSQL_DATABASE value: petclinic --- apiVersion: v1 kind: Service metadata: name: mysql spec: selector: app: mysql ports: - name: tcp port: 3306 targetPort: 3306
type: ClusterIP
3. mysql-svc.yml


kubectl get cm #cm是CongigMap的縮寫

kubectl describe cm petclinic-config #cm是CongigMap的縮寫 #查看詳情

要先啟動Mysql,才能啟動Petclinic,
因為Petclinic裡面env有需要關連到Mysql。






修改petclinic-config後,還需要重啟Pod,才會把環境變數傳進Pod當中。
下圖為只修改config,但沒重啟Pod的結果,
可以看到版本還是舊的test_config_v1。
當更新環境變數後,建議更改config的name,此例將名字改成v2,
並把deployment引用的地方也改成v2,
這樣做可以觸發滾動式發布,
達到版本控制的效果。
記得更改完成後,
Deplyment和Config接續要再次發佈(apply)
先發佈config,之後再發佈deployment(下圖此例的deployment寫在petclinic-svc.yml當中)。

ConfigMap綁定到Pod的環境變量(env)中後,
需要重啟Pod,
建議更新Config的版本名稱,以及deployment引用的版本名稱,
以達到滾動式發佈。

ConfigMap綁定到Volume時,可以達到熱更新,
也就是說不用重啟Pod,並直接把ConfigMap中的配置體現出來,即時進行更新。


理解K8s的Secret













Secret只能提供有限安全,因為它用base64可以很容易破解,

你可以把重要資料放進Secret中,為其單獨設置更安全的訪問策略







沒有留言:

張貼留言

喜歡我的文章嗎? 喜歡的話可以留言回應我喔! ^^