自從上了K8S,專案更新都不帶停機的!
技術標籤:架構筆記程式人生dockerlinuxjavakubernetes大資料
其實K8S中還有一些高階特性也很值得學習,比如彈性擴縮應用、滾動更新、配置管理、儲存卷、閘道器路由等。今天我們就來了解下這些高階特性,希望對大家有所幫助!
核心概念
首先我們先來了解一些核心概念,瞭解這些核心概念對使用K8S的高階特性很有幫助。
ReplicaSet
ReplicaSet確保任何時間都有指定數量的Pod副本在執行。通常用來保證給定數量的、完全相同的Pod的可用性。建議使用Deployment來管理ReplicaSet,而不是直接使用ReplicaSet。
ConfigMap
ConfigMap是一種API物件,用來將非機密性的資料儲存到鍵值對中。使用時,Pod可以將其用作環境變數、命令列引數或者儲存卷中的配置檔案。使用ConfigMap可以將你的配置資料和應用程式程式碼分開。
Volume
Volume指的是儲存卷,包含可被Pod中容器訪問的資料目錄。容器中的檔案在磁碟上是臨時存放的,當容器崩潰時檔案會丟失,同時無法在多個Pod中共享檔案,通過使用儲存卷可以解決這兩個問題。
常用的儲存卷有如下幾種:
- configMap:configMap卷提供了向Pod注入配置資料的方法。ConfigMap物件中儲存的資料可以被configMap型別的卷引用,然後被Pod中執行的容器化應用使用。
- emptyDir:emptyDir卷可用於儲存快取資料。當Pod分派到某個Node上時,emptyDir卷會被建立,並且Pod在該節點上執行期間,卷一直存在。當Pod被從節點上刪除時emptyDir卷中的資料也會被永久刪除。
- hostPath:hostPath卷能將主機節點檔案系統上的檔案或目錄掛載到你的Pod中。在Minikube中的主機指的是Minikube所在虛擬機器。
- local:local卷所代表的是某個被掛載的本地儲存裝置,例如磁碟、分割槽或者目錄。local卷只能用作靜態建立的持久卷,尚不支援動態配置。
- nfs:nfs卷能將NFS(網路檔案系統)掛載到你的Pod中。
- persistentVolumeClaim:persistentVolumeClaim卷用來將持久卷(PersistentVolume)掛載到Pod中。持久卷(PV)是叢集中的一塊儲存,可以由管理員事先供應,或者使用儲存類(Storage Class)來動態供應,持久卷是叢集資源類似於節點。
Ingress
Ingress類似於K8S中的閘道器服務,是對叢集中服務的外部訪問進行管理的API物件,典型的訪問方式是HTTP。Ingress可以提供負載均衡、SSL終結和基於名稱的虛擬託管。
高階特性
擴縮應用
當流量增加時,我們需要擴容應用程式滿足使用者需求。當流量減少時,需要縮放應用以減少伺服器開銷。在K8S中擴縮是通過改變Deployment中的副本數量來實現的。
- 獲取所有Deployment可使用如下命令:
kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
kubernetes-nginx 1/1 1 1 43h
- 獲取所有ReplicaSet可使用如下命令:
kubectl get rs
NAME DESIRED CURRENT READY AGE
kubernetes-nginx-78bcc44665 1 1 1 43h
- 對應用進行擴容操作,擴容到4個例項,再檢視所有:
kubectl scale deployments/kubernetes-nginx --replicas=4
[[email protected] root]$ kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
kubernetes-nginx 4/4 4 4 43h
- 檢視所有Pod,發現已經有4個執行在不同的IP地址上了;
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
kubernetes-nginx-78bcc44665-8fnnn 1/1 Running 2 43h 172.17.0.3 minikube <none> <none>
kubernetes-nginx-78bcc44665-dvq4t 1/1 Running 0 84s 172.17.0.8 minikube <none> <none>
kubernetes-nginx-78bcc44665-thzg9 1/1 Running 0 84s 172.17.0.7 minikube <none> <none>
kubernetes-nginx-78bcc44665-w7xqd 1/1 Running 0 84s 172.17.0.6 minikube <none> <none>
- 對應用進行縮放操作,縮放到2個例項;
kubectl scale deployments/kubernetes-nginx --replicas=2
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
kubernetes-nginx-78bcc44665-8fnnn 1/1 Running 2 44h 172.17.0.3 minikube <none> <none>
kubernetes-nginx-78bcc44665-w7xqd 1/1 Running 0 11m 172.17.0.6 minikube <none> <none>
滾動更新
滾動更新允許通過使用新的例項逐步更新Pod例項,零停機進行Deployment更新。K8S不僅可以實現滾動更新,還可以支援回滾操作。
- 目前運行了4個Nginx1.10版本的例項:
[[email protected] root]$ kubectl get pods
NAME READY STATUS RESTARTS AGE
kubernetes-nginx-78bcc44665-8fnnn 1/1 Running 2 44h
kubernetes-nginx-78bcc44665-jpw2g 1/1 Running 0 5s
kubernetes-nginx-78bcc44665-w7xqd 1/1 Running 0 59m
kubernetes-nginx-78bcc44665-xx8s5 1/1 Running 0 5s
- 可以通過kubectl describe命令來檢視映象版本號:
[[email protected] root]$ kubectl describe pods |grep Image
Image: nginx:1.10
Image ID: docker-pullable://[email protected]:6202beb06ea61f44179e02ca965e8e13b961d12640101fca213efbfd145d7575
- kubectl set image 1.19 1.10 1.19
# 命令格式 kubectl set image Deployment的名稱 容器名稱=容器映象:映象版本號
kubectl set image deployments/kubernetes-nginx nginx=nginx:1.19
# 停止1箇舊例項並建立2個新例項
NAME READY STATUS RESTARTS AGE
kubernetes-nginx-66f67cd758-rbcz5 0/1 ContainerCreating 0 11s
kubernetes-nginx-66f67cd758-s9ck8 0/1 ContainerCreating 0 11s
kubernetes-nginx-78bcc44665-8fnnn 1/1 Running 2 45h
kubernetes-nginx-78bcc44665-jpw2g 0/1 Terminating 0 15m
kubernetes-nginx-78bcc44665-w7xqd 1/1 Running 0 75m
kubernetes-nginx-78bcc44665-xx8s5 1/1 Running 0 15m
# 1個例項已被停止2個新例項仍建立中
NAME READY STATUS RESTARTS AGE
kubernetes-nginx-66f67cd758-rbcz5 0/1 ContainerCreating 0 30s
kubernetes-nginx-66f67cd758-s9ck8 0/1 ContainerCreating 0 30s
kubernetes-nginx-78bcc44665-8fnnn 1/1 Running 2 45h
kubernetes-nginx-78bcc44665-w7xqd 1/1 Running 0 75m
kubernetes-nginx-78bcc44665-xx8s5 1/1 Running 0 15m
# 4個新例項均已建立完成
NAME READY STATUS RESTARTS AGE
kubernetes-nginx-66f67cd758-jn926 1/1 Running 0 48s
kubernetes-nginx-66f67cd758-rbcz5 1/1 Running 0 3m12s
kubernetes-nginx-66f67cd758-s9ck8 1/1 Running 0 3m12s
kubernetes-nginx-66f67cd758-smr7n 1/1 Running 0 44s
- 此時再使用kubectl describe命令來檢視映象版本號,發現Nginx已經更新至1.19版本:
[[email protected] root]$ kubectl describe pods |grep Image
Image: nginx:1.19
Image ID: docker-pullable://[email protected]:4cf620a5c81390ee209398ecc18e5fb9dd0f5155cd82adcbae532fec94006fb9
- 如果想回滾到原來的版本的話,直接使用kubectl rollout undo命令即可。
kubectl rollout undo deployments/kubernetes-nginx
配置管理
ConfigMap允許你將配置檔案與映象檔案分離,以使容器化的應用程式具有可移植性。接下來我們演示下如何將ConfigMap的的屬性注入到Pod的環境變數中去。
- nginx-config.yaml nginx-config data
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
namespace: default
data:
nginx-env: test
- 應用nginx-config.yaml檔案建立ConfigMap:
kubectl create -f nginx-config.yaml
- 獲取所有ConfigMap:
kubectl get configmap
NAME DATA AGE
kube-root-ca.crt 1 2d22h
nginx-config 1 13s
- 通過yaml格式檢視ConfigMap中的內容:
kubectl get configmaps nginx-config -o yaml
apiVersion: v1
data:
nginx-env: test
kind: ConfigMap
metadata:
creationTimestamp: "2021-01-08T01:49:44Z"
managedFields:
- apiVersion: v1
fieldsType: FieldsV1
fieldsV1:
f:data:
.: {}
f:nginx-env: {}
manager: kubectl-create
operation: Update
time: "2021-01-08T01:49:44Z"
name: nginx-config
namespace: default
resourceVersion: "61322"
uid: a477567f-2aff-4a04-9a49-f19220baf0d3
- 新增配置檔案nginx-deployment.yaml用於建立Deployment,部署一個Nginx服務,在Nginx的環境變數中引用ConfigMap中的屬性:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.10
ports:
- containerPort: 80
env:
- name: NGINX_ENV # 在Nginx中設定環境變數
valueFrom:
configMapKeyRef:
name: nginx-config # 設定ConfigMap的名稱
key: nginx-env # 需要取值的鍵
- 應用配置檔案檔案建立Deployment:
kubectl apply -f nginx-deployment.yaml
- 建立成功後檢視Pod中的環境變數,發現NGINX_ENV變數已經被注入了;
kubectl exec deployments/nginx-deployment -- env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=nginx-deployment-66fcf997c-xxdsb
NGINX_ENV=test
儲存卷使用
通過儲存卷,我們可以把外部資料掛載到容器中去,供容器中的應用訪問,這樣就算容器崩潰了,資料依然可以存在。
- 記得之前我們使用Docker部署Nginx的時候,將Nginx的html、logs、conf目錄從外部掛載到了容器中;
docker run -p 80:80 --name nginx \
-v /mydata/nginx/html:/usr/share/nginx/html \
-v /mydata/nginx/logs:/var/log/nginx \
-v /mydata/nginx/conf:/etc/nginx \
-d nginx:1.10
- Minikube可以認為是一臺虛擬機器,我們可以用Minikube的ssh命令來訪問它;
minikube ssh
- Minikube中預設有一個docker使用者,我們先重置下它的密碼;
sudo passwd docker
- 在Minikube中建立mydata目錄;
midir /home/docker/mydata
- 我們需要把Nginx的資料目錄複製到Minikube中去,才能實現目錄的掛載,注意docker使用者只能修改/home/docker目錄中的檔案,我們通過scp命令來複制檔案;
scp -r /home/macro/mydata/nginx [email protected]:/home/docker/mydata/nginx
- 新增配置檔案nginx-volume-deployment.yaml用於建立Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-volume-deployment
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.10
ports:
- containerPort: 80
volumeMounts:
- mountPath: /usr/share/nginx/html
name: html-volume
- mountPath: /var/log/nginx
name: logs-volume
- mountPath: /etc/nginx
name: conf-volume
volumes:
- name: html-volume
hostPath:
path: /home/docker/mydata/nginx/html
type: Directory
- name: logs-volume
hostPath:
path: /home/docker/mydata/nginx/logs
type: Directory
- name: conf-volume
hostPath:
path: /home/docker/mydata/nginx/conf
type: Directory
- 應用配置檔案建立Deployment;
kubectl apply -f nginx-volume-deployment.yaml
- 新增配置檔案nginx-service.yaml用於建立Service;
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
type: NodePort
selector:
app: nginx
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
nodePort: 30080
- 應用配置檔案建立Service;
kubectl apply -f nginx-service.yaml
- 檢視下Service服務訪問埠;
[[email protected] nginx]$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 6d23h
kubernetes-nginx NodePort 10.106.227.54 <none> 80:30158/TCP 5d22h
nginx-service NodePort 10.103.72.111 <none> 80:30080/TCP 7s
- 通過CURL命令可以訪問Nginx首頁資訊。
curl $(minikube ip):30080
閘道器路由
Ingress可以作為K8S的閘道器來使用,能提供服務路由和負載均衡等功能。
- Minikube預設沒有啟用Ingress外掛,需要手動開啟;
minikube addons enable ingress
- 開啟Ingress過程中遇到了一個坑,會在驗證的時候卡主,其實是Minikube內部無法下載Ingress映象導致的:
[[email protected] ~]$ minikube addons enable ingress
* Verifying ingress addon...
- 解決該問題需要手動下載第三方映象,並標記為需要的映象,並重新啟用Ingress外掛;
# 查詢啟動有問題的Pod
kubectl get pods -n kube-system
# 檢視啟動失敗原因
kubectl describe ingress-nginx-controller-xxx -n kube-system
# 連線到Minikube
minikube ssh
# 原來需要下載的映象(已經無法下載)
docker pull us.gcr.io/k8s-artifacts-prod/ingress-nginx/controller:v0.40.2
# 下載第三方替代映象(直接去DockerHub官網搜尋即可)
docker pull pollyduan/ingress-nginx-controller:v0.40.2
# 修改映象名稱
docker tag pollyduan/ingress-nginx-controller:v0.40.2 us.gcr.io/k8s-artifacts-prod/ingress-nginx/controller:v0.40.2
- 重啟外掛後檢查下Ingress是否在執行;
kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
ingress-nginx-admission-create-krpgk 0/1 Completed 0 46h
ingress-nginx-admission-patch-wnxlk 0/1 Completed 3 46h
ingress-nginx-controller-558664778f-wwgws 1/1 Running 2 46h
- 新增配置檔案nginx-ingress.yaml用於建立Ingress;
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- host: nginx-volume.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-service
port:
number: 80
- 應用配置檔案建立Ingress;
kubectl apply -f nginx-ingress.yaml
- 檢視所有Ingress,此時我們已經可以通過nginx-volume.com來訪問Pod中執行的Nginx服務了;
kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
nginx-ingress <none> nginx-volume.com 192.168.49.2 80 6s
- 需要修改下host檔案,注意切換到root賬號後修改:
# 切換到root使用者
su -
# 修改host檔案
vi /etc/hosts
# 新增如下記錄
192.168.49.2 nginx-volume.com
- 最後通過CURL命令可以訪問Nginx首頁資訊。
curl nginx-volume.com
總結
通過K8S擴充套件和管理容器化應用確實十分方便,通過幾個命令我們就可以實現零停機更新,出了故障也不怕,一個命令實現回滾。但是大量的命令列操作總顯得枯燥無味,要是有個視覺化工具可以直接管理K8S就更好了。
推薦閱讀
為什麼阿里巴巴的程式設計師成長速度這麼快,看完他們的內部資料我懂了
刷Github時發現了一本阿里大神的演算法筆記!標星70.5K
看完三件事❤️
如果你覺得這篇內容對你還蠻有幫助,我想邀請你幫我三個小忙:
點贊,轉發,有你們的 『點贊和評論』,才是我創造的動力。
關注公眾號 『 Java鬥帝 』,不定期分享原創知識。
同時可以期待後續文章ing