### 一、pod簡介
Pod是Kubernetes最小的管理單位,一個Pod可以封裝一個容器或多個容器。
一個Pod里的多個容器可以共享存儲和網絡,一個pod可以看作一個邏輯上的主機。
因為多個容器共享同一個network namespace,所以一個Pod內的多個容器之間可以通過localhost來進行通信,所需要注意的是不同容器要注意不要有端口沖突即可。
一個Pod里的多個容器可以共享存儲卷,這個存儲卷會被定義為Pod的一部分,並且可以掛載到該Pod里的所有容器的文件系統上。
二、pod分類
pod分為兩類,不受控制器管理的自主式Pod,跟受控制器管理的Pod
-
自主式pod:沒有副本控制器控制,刪除自主式pod后不會重新創建
-
控制器管理的pod:控制器會按照定義的策略控制pod的數量,發現pod數量少了,會立即自動建立出來新的pod;一旦發現pod多了,也會自動殺死多余的Pod。
三、Pod創建
3.1 命令行創建pod
kubectl run nginx --image=nginx --replicas=3
- kubectl run:運行容器
- nginx:pod名
- --image:鏡像名稱
- --replicas:副本數
3.2 yaml文件創建pod
1.創建包含一個容器的pod
這里定義一個自主式pod,即沒有控制器控制的pod,注意在生產環境中,都是使用控制器來控制pod的,這里僅作案例介紹使用
編輯名為pod_stress.yaml的文件,添加如下內容
apiVersion: v1 # api版本(不同版本語法有少量差異),這里為v1
kind: Pod # 資源類型為Pod
metadata: #定義該pod的元數據,即屬性
name: memory-demo #pod的名稱
spec: #定義規則
containers:
- name: demo #容器名
image: polinux/stress #鏡像名
imagePullPolicy: IfNotPresent #拉取鏡像規則,本地沒有就從網絡上拉取
command: ["stress"] #壓力測試命令,讓容器立即使用150M內存
args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]
polinux/stress這個鏡像用於壓力測試,在啟動容器時傳命令與參數就是相當於分配容器運行時需要的壓力
imagePullPolicy:鏡像拉取策略
Always : 只從網絡鏡像倉庫中下載鏡像
Never : 只使用本地鏡像
IfNotPresent: 如果本地存在就直接使用, 不存在才從網絡鏡像倉庫中下載
2.應用ymal文件
kubectl apply -f pod_stress.yaml
3.驗證
kubectl get pod -o wide
kubectl describe pod memory-demo #查看pod詳細信息
kubectl top pod
使用
kubectl top pod
查看使用資源信息,需要安裝Metrics-server組件,安裝方法看這里
4.刪除pod
kubectl delete -f pod_stress.yaml
kubectl delete pod memory-demo
2.創建包含多個容器的pod
1, 准備yml文件
$ vim pod_Multiple.yml
apiVersion: v1
kind: Pod
metadata:
name: pod-multiple
spec:
containers:
- name: memory-demo-ctr-1 #容器名不能一樣,因為他們在同一個pod中
image: polinux/stress
imagePullPolicy: IfNotPresent
resources:
limits:
memory: "200Mi"
requests:
memory: "100Mi"
command: ["stress"]
args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]
- name: memory-demo-ctr-2
image: polinux/stress
imagePullPolicy: IfNotPresent
resources:
limits:
memory: "200Mi"
requests:
memory: "100Mi"
command: ["stress"]
args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]
2.應用yaml文件
kubectl apply -f pod_Multiple.yml
3.驗證
kubectl get pods -o wide
docker ps -a |grep stress
4.刪除pod
kubectl delete -f pod_Multiple.yml
kubectl delect pod pod-multiple
3.3 yaml文件注解
1.完整的定義pod的yaml文件注解
apiVersion: v1 #必選,版本號,例如v1
kind: Pod #必選,Pod
metadata: #必選,元數據
name: string #必選,Pod名稱
namespace: string #必選,Pod所屬的命名空間
labels: #自定義標簽
- name: string #自定義標簽名字
annotations: #自定義注釋列表
- name: string
spec: #必選,Pod中容器的詳細定義
containers: #必選,Pod中容器列表
- name: string #必選,容器名稱
image: string #必選,容器的鏡像名稱
imagePullPolicy: [Always | Never | IfNotPresent] #獲取鏡像的策略 Alawys表示下載鏡像 IfnotPresent表示優先使用本地鏡像,否則下載鏡像,Nerver表示僅使用本地鏡像
command: [string] #容器的啟動命令列表,如不指定,使用打包時使用的啟動命令
args: [string] #容器的啟動命令參數列表
workingDir: string #容器的工作目錄
volumeMounts: #掛載到容器內部的存儲卷配置
- name: string #引用pod定義的共享存儲卷的名稱,需用volumes[]部分定義的的卷名
mountPath: string #存儲卷在容器內mount的絕對路徑,應少於512字符
readOnly: boolean #是否為只讀模式
ports: #需要暴露的端口庫號列表
- name: string #端口號名稱
containerPort: int #容器需要監聽的端口號
hostPort: int #容器所在主機需要監聽的端口號,默認與Container相同
protocol: string #端口協議,支持TCP和UDP,默認TCP
env: #容器運行前需設置的環境變量列表
- name: string #環境變量名稱
value: string #環境變量的值
resources: #資源限制和請求的設置
limits: #資源限制的設置
cpu: string #Cpu的限制,單位為core數,將用於docker run --cpu-shares參數
memory: string #內存限制,單位可以為Mib/Gib,將用於docker run --memory參數
requests: #資源請求的設置
cpu: string #Cpu請求,容器啟動的初始可用數量
memory: string #內存清楚,容器啟動的初始可用數量
livenessProbe: #對Pod內個容器健康檢查的設置,當探測無響應幾次后將自動重啟該容器,檢查方法有exec、httpGet和tcpSocket,對一個容器只需設置其中一種方法即可
exec: #對Pod容器內檢查方式設置為exec方式
command: [string] #exec方式需要制定的命令或腳本
httpGet: #對Pod內個容器健康檢查方法設置為HttpGet,需要制定Path、port
path: string
port: number
host: string
scheme: string
HttpHeaders:
- name: string
value: string
tcpSocket: #對Pod內個容器健康檢查方式設置為tcpSocket方式
port: number
initialDelaySeconds: 0 #容器啟動完成后首次探測的時間,單位為秒
timeoutSeconds: 0 #對容器健康檢查探測等待響應的超時時間,單位秒,默認1秒
periodSeconds: 0 #對容器監控檢查的定期探測時間設置,單位秒,默認10秒一次
successThreshold: 0
failureThreshold: 0
securityContext:
privileged: false
restartPolicy: [Always | Never | OnFailure] #Pod的重啟策略,Always表示一旦不管以何種方式終止運行,kubelet都將重啟,OnFailure表示只有Pod以非0退出碼退出才重啟,Nerver表示不再重啟該Pod
nodeSelector: obeject #設置NodeSelector表示將該Pod調度到包含這個label的node上,以key:value的格式指定
imagePullSecrets: #Pull鏡像時使用的secret名稱,以key:secretkey格式指定
- name: string
hostNetwork: false #是否使用主機網絡模式,默認為false,如果設置為true,表示使用宿主機網絡
volumes: #在該pod上定義共享存儲卷列表
- name: string #共享存儲卷名稱 (volumes類型有很多種)
emptyDir: {} #類型為emtyDir的存儲卷,與Pod同生命周期的一個臨時目錄。為空值
hostPath: string #類型為hostPath的存儲卷,表示掛載Pod所在宿主機的目錄
path: string #Pod所在宿主機的目錄,將被用於同期中mount的目錄
secret: #類型為secret的存儲卷,掛載集群與定義的secre對象到容器內部
scretname: string
items:
- key: string
path: string
configMap: #類型為configMap的存儲卷,掛載預定義的configMap對象到容器內部
name: string
items:
- key: string
path: string
2.YAML格式查找幫助方法
查看目前使用的api版本
kubectl api-versions
3.查看yaml幫助
kubectl explain namespace
kubectl explain pod
kubectl explain pod.spec
kubectl explain pod.spec.containers
因為yaml文件是分層級的,所以查看pod下的spec定義就需要使用pod.spec來查看
四、pod調度
我們為了實現容器主機資源平衡使用, 可以使用約束把pod調度到指定的node節點上。
這里支持兩種調度方式,nodeName 跟nodeSelector
-
nodeName:用於將pod調度到指定的node名稱上
-
nodeSelector:用於將pod調度到匹配Label的node上
3.1 案例1: nodeName
1.編寫YAML文件
編輯名為pod_nginx.yaml的文件,添加如下內容
apiVersion: v1 # api版本(不同版本語法有少量差異),這里為v1
kind: Pod # 資源類型為Pod
metadata: #定義該pod的元數據,即屬性
name: nginx-pod #pod的名稱
spec: #定義規則
nodeName: k8s-node01 #將該pod調度到k8s-node01節點上
containers:
- name: nginx #容器名
image: nginx:1.15-alpine #鏡像名
imagePullPolicy: IfNotPresent #拉取鏡像規則,本地沒有就從網絡上拉取
2.應用ymal文件
kubectl apply -f pod_nginx.yaml
3.驗證
kubectl get pod -o wide
4.刪除
kubectl delete -f pod_nginx.yaml
kubectl delete pod nginx-pod
3.2 案例2: nodeSelector
1.給節點打標簽
kubectl label nodes k8s-node01 bussiness=ad
kubectl get nodes -L bussiness
2.編寫yaml文件
編輯名為pod_nginx.yaml的文件,添加如下內容
apiVersion: v1 # api版本(不同版本語法有少量差異),這里為v1
kind: Pod # 資源類型為Pod
metadata: #定義該pod的元數據,即屬性
name: nginx-pod #pod的名稱
spec: #定義規則
nodeSelector:
bussiness: ad #將該pod調度到標簽為bussiness: ad的節點上
containers:
- name: nginx #容器名
image: nginx:1.15-alpine #鏡像名
imagePullPolicy: IfNotPresent #拉取鏡像規則,本地沒有就從網絡上拉取
3.應用ymal文件
kubectl apply -f pod_nginx.yaml
3.驗證
kubectl get pod -o wide
4.刪除
kubectl delete -f pod_nginx.yaml
kubectl delete pod nginx-pod
五、pod的標簽
為pod設置label,pod的label用於controller關聯控制pod
kubectl get pods --show-labels
打標簽
kubectl label pod memory-demo region=huanai zone=A env=test bussiness=game
搜索標簽
kubectl get pods -l zone=A
kubectl get pods -l "zone in (A,B,C)"
刪除標簽
kubectl label pod memory-demo region- zone- env- bussiness-
kubectl get pods --show-labels
使用標簽的key后面接-就能刪除標簽
六、pod資源限制
這里創建兩個pod來對比觀察限制效果
1.創建第一個pod的yaml文件
$ vim pod_stress01.yml
apiVersion: v1
kind: Namespace
metadata:
name: memory-test
---
apiVersion: v1
kind: Pod
metadata:
name: memory-demo-01
namespace: memory-test
spec:
containers:
- name: memory-demo-ctr
image: polinux/stress
imagePullPolicy: IfNotPresent
resources:
limits: #限制使用內存200M
memory: "200Mi"
requests: #請求內存100M
memory: "100Mi"
command: ["stress"]
args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"] # 該命令作用為產生1個進程分配150M內存1秒后釋放
-
這里創建了一個memory-test的命名空間,多個yaml寫在一個文件中使用
---
分隔。 -
該pod限制最大使用內存200M,實際請求內存150M,該Pod是不會被殺死的
2.創建第二個pod的yaml文件
$ vim pod_stress02.yml
apiVersion: v1
kind: Pod
metadata:
name: memory-demo-02
namespace: memory-test
spec:
containers:
- name: memory-demo-ctr
image: polinux/stress
imagePullPolicy: IfNotPresent
resources:
limits: #限制使用內存200M
memory: "200Mi"
requests: #請求內存100M
memory: "100Mi"
command: ["stress"]
args: ["--vm", "1", "--vm-bytes", "250M", "--vm-hang", "1"]
限制使用最大內存200M,實際請求使用內存是250M,該Pod會被殺死。
3.應用yaml清單
kubectl apply -f pod_stress01.yml
kubectl apply -f pod_stress02.yml
4.驗證
kubectl get pod -n memory-test -w
kubectl describe pod memory-demo-02 -n memory-test |tail -6
-
查看會發現memory-demo-02這個pod狀態變為OOMKilled,因為它是內存不足所以顯示Container被殺死;
-
這次創建pod使用了memory-test命名空間,查看pod跟刪除pod都要指定memory-test命名空間
5.刪除
刪除命名空間,該命名空間里的pod都會被刪除。
kubectl delete ns memory-test
kubectl get pod --all-namespaces #查看所有命名空間的pod,可以發現刪除memory-test命名空間,該命名空間里的pod也被刪除了
七、對pod里的容器進行操作
7.1 使用docker命令進入容器
1.先查看Pod在哪個節點上
kubectl get pods -o wide
2.查看容器名
docker ps
3.進入容器
docker exec -it k8s_xxxxx /bin/bash
- 使用docker進入容器較為繁瑣。
7.2 使用kubectl進入容器
1.查看幫助
kubectl exec -h
2.不進入容器執行命令
#先查看pod名
kubectl get pods
#不進入容器執行命令,執行的命令跟pod名之間使用--隔開
kubectl exec pod1 -- date
#如果pod有多個容器,需要-c指定要操作的容器,否則默認找第一個容器
kubectl exec -it pod名 -c 容器名 -- touch /111
- 如果pod中有多個容器,不指定容器名默認為第1個容器
3.進入容器交互操作
格式為kubectl exec -it pod名 -c 容器名 -- /bin/bash
#進入容器,有些容器沒有bash,就用sh
kubectl exec -it pod-multiple -- /bin/bash
#如果pod中有多個容器,-c指定進入容器的名字
kubectl exec -it pod-multiple -c memory-demo-ctr-2 -- /bin/bash
八、pod重啟
1.有yaml文件的pod重啟方式
kubectl replace --force -f xxx.yaml
2.沒有yaml文件但使用Deployment 創建的pod重啟方式
kubectl scale deployment esb-admin --replicas=0 -n {namespace}
kubectl scale deployment esb-admin --replicas=1 -n {namespace}
這里使用的是擴容縮容副本數的方式
參考資料:pod的重啟
九、pod刪除
kubectl delete pod pod{1..4} #如果pod命名為pod1,pod2,pod3,pod4則可使用該方法批量刪除pod
kubectl delete pod xxx xxx xxx #刪除多個pod用空格隔開
kubectl delete -f xxx.yaml #使用yaml文件刪除
十、pod的生命周期
pod從創建到終止的過程就是pod的生命周期。
容器啟動
-
pod中的容器在創建前,有初始化容器(init container)來進行初始化環境
-
初化完后,主容器(main container)開始啟動
-
主容器啟動后,有一個post start的操作(啟動后的觸發型操作,或者叫啟動后鈎子)
-
post start后,就開始做健康檢查
- 第一個健康檢查叫存活狀態檢查(liveness probe ),用來檢查主容器存活狀態的
- 第二個健康檢查叫准備就緒檢查(readyness probe),用來檢查主容器是否啟動就緒
容器終止
-
可以在容器終止前設置pre stop操作(終止前的觸發型操作,或者叫終止前鈎子)
-
當出現特殊情況不能正常銷毀pod時,大概等待30秒會強制終止
-
終止容器后還可能會重啟容器(視容器重啟策略而定)
9.1 案例1:post-start
1, 編寫YAML文件
主要用於定義環境變量時使用
$ vim pod-poststart.yml
apiVersion: v1
kind: Pod
metadata:
name: poststart
namespace: default
spec:
containers:
- name: poststart
image: nginx:1.15-alpine
imagePullPolicy: IfNotPresent
lifecycle: # 生命周期事件
postStart: # 在容器啟動后就創建一個tz.html文件
exec:
command: ["mkdir","-p","/usr/share/nginx/html/tz.html"]
2, 應用YMAL文件
kubectl apply -f pod-poststart.yml
3, 驗證
kubectl get pods -w
kubectl exec -it poststart -- ls /usr/share/nginx/html -l
9.2 案例2:pre-stop
容器終止前執行的命令
1, 編寫YAML文件
$ vim pre-stop.yml
apiVersion: v1
kind: Pod
metadata:
name: prestop
namespace: default
spec:
containers:
- name: prestop
image: nginx:1.15-alpine
imagePullPolicy: IfNotPresent
lifecycle: # 生命周期事件
preStop: # 讓容器終止前sleep 60000000秒
exec:
command: ["/bin/sh","-c","sleep 60000000"]
2, 應用YAML文件創建pod
kubectl apply -f pre-stop.yml
3, 刪除pod驗證
kubectl delete -f pre-stop.yml
會在刪除這一步等待30s,此時驗證是成功的,因為當出現特殊情況不能正常銷毀pod時,大概等待30秒會強制終止。
十一、健康檢查
健康檢查用於當Pod啟動時,檢查容器是否啟動,服務是否正常運行;
健康檢查有兩種方式,存活狀態探測跟就緒型狀態探測。
健康檢查方式
健康檢查方式 | 說明 |
---|---|
Liveness Probe | 存活狀態探測,如檢查未通過,則重啟pod |
Readiness Probe | 就緒型探測,如檢查未通過,會將容器STATUS設置為Notready;如果使用service來訪問,流量不會轉發給此種狀態的pod(也就是處於Notready的容器運行的服務是訪問不了的,不會將客戶端請求發給該容器) |
探測方式
探測方式 | 說明 |
---|---|
Exec | 執行命令 |
HTTPGet | http請求某一個URL路徑 |
TCP | tcp連接某一個端口 |
案例1: liveness-exec
使用命令探測容器是否正常。
1, 准備YAML文件
$ vim pod-liveness-exec.yml
apiVersion: v1
kind: Namespace
metadata:
name: test
--- #多個yaml文件使用---分隔
apiVersion: v1
kind: Pod
metadata:
name: liveness-exec
namespace: test
spec:
containers:
- name: liveness
image: busybox
imagePullPolicy: IfNotPresent
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600 #創建healthy文件,等30秒后刪除它
livenessProbe:
exec:
command:
- cat
- /tmp/healthy #檢查是否有/tmp/healthy文件
initialDelaySeconds: 5 # pod啟動后等5秒開始探測
periodSeconds: 5 #每5秒探測一次
這里創建了一個名為test的命名空間,多個yaml文件寫成一個使用
---
分隔
2, 應用YAML文件
kubectl apply -f pod-liveness-exec.yml
3, 通過下面的命令觀察
kubectl get pods -n test
kubectl describe pod liveness-exec -n test | tail -6
可以看到該容器重啟了1次
容器重啟策略
Always:表示容器掛了總是重啟,這是默認策略
OnFailures:表容器狀態為錯誤時才重啟,也就是容器正常終止時才重啟
Never:表示容器掛了不予重啟
對於Always這種策略,容器只要掛了,就會立即重啟,這樣是很耗費資源的。所以Always重啟策略是第一次容器掛了立即重啟,如果再掛了就要延時10s重啟,第三次掛了就等20s重啟...... 依次類推,時間間隔會越來越長。
案例2: liveness-httpget
請求容器web服務檢測容器是否正常。
1, 編寫YMAL文件
$ vim pod-liveness-httpget.yml
apiVersion: v1
kind: Pod
metadata:
name: liveness-httpget
namespace: test
spec:
containers:
- name: liveness
image: nginx:1.15-alpine
imagePullPolicy: IfNotPresent
ports: # 指定容器端口,這一段不寫也行,端口由鏡像決定
- name: http # 自定義名稱,不需要與下面的port: http對應
containerPort: 80 # 類似dockerfile里的expose 80
livenessProbe:
httpGet: # 使用httpGet方式
port: http # http協議,也可以直接寫80端口
path: /index.html # 探測家目錄下的index.html
initialDelaySeconds: 3 # 延遲3秒開始探測
periodSeconds: 5 # 每隔5s鍾探測一次
2, 應用YAML文件
kubectl apply -f pod-liveness-httpget.yml
3, 驗證查看
kubectl get pods -n test
kubectl describe pod livness-httpget -n test
4, 刪除nginx里的主頁文件
kubectl exec -it liveness-httpget -n test -- rm -rf /usr/share/nginx/html/index.html
#或者進入pod中的容器將html重命名,效果是一樣的
kubectl exec -it liveness-httpget -n test -- /bin/sh
cd /usr/share/nginx/html/
mv index.html index.html.bak
5, 驗證查看會發現,找不到主頁,就重啟了
kubectl describe pod liveness-httpget -n test | tail -6
kubectl get pods -n test #可以看到重啟了
案例3: liveness-tcp
檢查容器tcp端口是否正常。
1, 編寫YAML文件
$ vim pod-liveness-tcp.yml
apiVersion: v1
kind: Pod
metadata:
name: liveness-tcp
namespace: default
spec:
containers:
- name: liveness
image: nginx:1.15-alpine
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
livenessProbe:
tcpSocket: # 使用tcp連接方式
port: 80 # 連接80端口進行探測
initialDelaySeconds: 3
periodSeconds: 5
2, 應用YAML文件創建pod
kubectl apply -f pod-liveness-tcp.yml
3, 查看驗證
kubectl get pod
kubectl describe pod liveness-tcp
4, 交互關閉nginx
kubectl exec -it liveness-tcp -- /usr/sbin/nginx -s stop
5, 再次驗證查看,發現pod開始重啟
kubectl describe pod liveness-tcp
案例4: readiness-httpget
檢查容器是否就緒,如果容器觸發條件,就會從READY變為0/1,但不會重啟容器,同時也不會走流量給該容器。
1, 編寫YAML文件
$ vim pod-readiness-httpget.yml
apiVersion: v1
kind: Pod
metadata:
name: readiness-httpget
namespace: default
spec:
containers:
- name: readiness
image: nginx:1.15-alpine
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
readinessProbe: # 這里由liveness換成了readiness
httpGet:
port: http
path: /index.html
initialDelaySeconds: 3
periodSeconds: 5
2, 應用YAML文件
kubectl apply -f pod-readiness-httpget.yml
3, 驗證查看
kubectl get pod -n default
4, 刪除nginx主頁
kubectl exec -it readiness-httpget -- rm -rf /usr/share/nginx/html/index.html
#進入容器刪除,效果是一樣的
kubectl exec -it readiness-httpget -n default -- /bin/sh
rm -rf /usr/share/nginx/html/index.html
5, 再次驗證
kubectl get pod -n default
發現pod並沒有重啟容器,而是READY變為了0/1
6, 創建nginx主頁文件再驗證
kubectl exec -it readiness-httpget -- touch /usr/share/nginx/html/index.html
kubectl get pod
READY狀態又為1/1了
案例5: readiness+liveness綜合
1, 編寫YAML文件
$ vim pod-readiness-liveiness.yml
apiVersion: v1
kind: Pod
metadata:
name: readiness-liveness-httpget
namespace: default
spec:
containers:
- name: readiness-liveness
image: nginx:1.15-alpine
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
livenessProbe:
httpGet:
port: http
path: /index.html
initialDelaySeconds: 5 #容器啟動后5秒檢測請求頁面
periodSeconds: 5 #每隔5秒檢測一次
readinessProbe:
tcpSocket:
port: 80
initialDelaySeconds: 1 #容器啟動1秒后開始檢測80端口
periodSeconds: 3 #每個3秒檢測一次
此時會先查看80端口是否通暢,然后再檢查是否能請求到/index.html文件
2, 應用YAML文件
kubectl apply -f pod-readiness-liveiness.yml
3, 驗證
kubectl get pod
#刪除容器的index.html文件
kubectl exec -it readiness-liveness-httpget -- rm -rf /usr/share/nginx/html/index.html
#進入容器刪除,效果一樣
kubectl exec -it readiness-liveness-httpget -n default -- /bin/sh
rm -rf /usr/share/nginx/html/index.html
#發現容器已經重啟了
kubectl get pod -w
#停止容器的nginx服務,pod變為未就緒狀態,不會走流量,這樣也訪問不到index.html,觸發livenessProbe,pod就會重啟
kubectl exec -it readiness-liveness-httpget -- /usr/sbin/nginx -s stop
十二、參考資料
黑馬Linux-k8s第二天視頻