1. Pod概念熱身
Pod是一個(gè)邏輯抽象概念,K8s創(chuàng)建和管理的最小單元,一個(gè)Pod由一個(gè)容器或多個(gè)容器組成。 特點(diǎn):
- 一個(gè)Pod可以理解為是一個(gè)應(yīng)用實(shí)例
- Pod中容器始終部署在一個(gè)Node上
- Pod中容器共享網(wǎng)絡(luò)、存儲(chǔ)資源
Pod主要用法:
- 運(yùn)行單個(gè)容器:最常見(jiàn)的用法,在這種情況下,可以將Pod看作是單個(gè)容器的抽象封裝
- 運(yùn)行多個(gè)容器:邊車模式(Sidecar),通過(guò)在Pod中定義專門容器,來(lái)執(zhí)行主業(yè)務(wù)容器需要的輔助工作,這樣好處是將輔助功能同主業(yè)務(wù)容器解耦,實(shí)現(xiàn)獨(dú)立發(fā)布和能力重用。 例如:
- 日志收集
- 應(yīng)用監(jiān)控
擴(kuò)展:READY字段的意義:
tantianran@test-b-k8s-master:~$ kubectl get pods -n test-a
NAME READY STATUS RESTARTS AGE
goweb-demo-b98869456-25sj9 1/1 Running 1 (3m49s ago) 5d10h
在READY字段中,1/1的意義為在這個(gè)pod里,已準(zhǔn)備的容器/一共有多少個(gè)容器。
在pod中,它可以有3種類型的容器,分別是:
- 基礎(chǔ)容器(pause container)
- 初始化容器(init container)
- 普通容器(業(yè)務(wù)容器/應(yīng)用容器)
2. POD內(nèi)容器間資源共享實(shí)現(xiàn)機(jī)制
2.1 共享數(shù)據(jù)的機(jī)制
- emptyDir:會(huì)在 Pod 被刪除的同時(shí)也會(huì)被刪除,當(dāng) Pod 分派到某個(gè)節(jié)點(diǎn)上時(shí),emptyDir 卷會(huì)被創(chuàng)建,并且在 Pod 在該節(jié)點(diǎn)上運(yùn)行期間,卷一直存在。 就像其名稱表示的那樣,卷最初是空的。 盡管 Pod 中的容器掛載 emptyDir 卷的路徑可能相同也可能不同,這些容器都可以讀寫 emptyDir 卷中相同的文件。 當(dāng) Pod 因?yàn)槟承┰虮粡墓?jié)點(diǎn)上刪除時(shí),emptyDir 卷中的數(shù)據(jù)也會(huì)被永久刪除。
-
例子
apiVersion: v1 kind: Pod metadata: name: test-pod1 spec: containers: - image: nginx name: nginx1 volumeMounts: - mountPath: /cache name: cache-volume - image: busybox name: bs1 command: ["/bin/sh", "-c", "sleep 12h"] volumeMounts: - mountPath: /cache name: cache-volume volumes: - name: cache-volume emptyDir: sizeLimit: 500Mi
-
- cephfs:cephfs 卷允許你將現(xiàn)存的 CephFS 卷掛載到 Pod 中,cephfs 卷的內(nèi)容在 Pod 被刪除時(shí)會(huì)被保留,只是卷被卸載了。 這意味著 cephfs 卷可以被預(yù)先填充數(shù)據(jù),且這些數(shù)據(jù)可以在 Pod 之間共享。同一 cephfs 卷可同時(shí)被多個(gè)寫者掛載。
2.2 共享網(wǎng)絡(luò)的機(jī)制
共享網(wǎng)絡(luò)的機(jī)制是由Pause容器實(shí)現(xiàn),下面慢慢分析一下,啥是pause,了解一下它的作用等等。
- 先準(zhǔn)備一個(gè)yaml文件(pod1.yaml ),創(chuàng)建一個(gè)pod,pod里包含兩個(gè)容器,一個(gè)是名為nginx1的容器,還有一個(gè)是名為bs1的容器
apiVersion: v1
kind: Pod
metadata:
name: test-pod1
spec:
containers:
- image: nginx
name: nginx1
volumeMounts:
- mountPath: /cache
name: cache-volume
- image: busybox
name: bs1
command: ["/bin/sh", "-c", "sleep 12h"]
volumeMounts:
- mountPath: /cache
name: cache-volume
volumes:
- name: cache-volume
emptyDir:
sizeLimit: 500Mi
- 開(kāi)始創(chuàng)建
tantianran@test-b-k8s-master:~$ kubectl create -f pod1.yaml
pod/test-pod1 created
- 創(chuàng)建完后看看在哪個(gè)節(jié)點(diǎn)
tantianran@test-b-k8s-master:~$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test-pod1 2/2 Running 0 9m21s 10.244.222.44 test-b-k8s-node02 <none> <none>
- 去到對(duì)應(yīng)的節(jié)點(diǎn)查看容器
tantianran@test-b-k8s-node02:~$ sudo docker ps | grep test-pod1
0db01653bdac busybox "/bin/sh -c 'sleep 1…" 9 minutes ago Up 9 minutes k8s_bs1_test-pod1_default_c3a15f70-3ae2-4a73-8a84-d630c047d827_0
296972c29efe nginx "/docker-entrypoint.…" 9 minutes ago Up 9 minutes k8s_nginx1_test-pod1_default_c3a15f70-3ae2-4a73-8a84-d630c047d827_0
a5331fba7f11 registry.aliyuncs.com/google_containers/pause:latest "/pause" 10 minutes ago Up 10 minutes k8s_POD_test-pod1_default_c3a15f70-3ae2-4a73-8a84-d630c047d827_0
tantianran@test-b-k8s-node02:~$
通過(guò)查看容器,名為test-pod1的pod里,除了兩個(gè)業(yè)務(wù)容器外(k8s_bs1_test-pod1、nginx1_test-pod1),還有一個(gè)pause容器。這個(gè)到底是什么鬼呢?
「對(duì)pause容器的理解」
pause容器又叫Infra container,就是基礎(chǔ)設(shè)施容器的意思,Infra container只是pause容器的一個(gè)叫法而已
上面看到paus容器,是從registry.aliyuncs.com/google_containers/pause:latest這個(gè)鏡像拉起的
-
在其中一臺(tái)node節(jié)點(diǎn)上查看docker鏡像,可看到該鏡像的大小是240KB
registry.aliyuncs.com/google_containers/pause latest 350b164e7ae1 8 years ago 240kB 根據(jù)理解,畫了圖:
nginx1容器里的nginx組件默認(rèn)監(jiān)聽(tīng)的端口是80,在bs1容器里去curl http://127.0.0.1 就可以放到nginx1容器的80端口。
# step1:查看test-pod1里的容器
kubectl get pods test-pod1 -o jsonpath={.spec.containers[*].name}
# step2:進(jìn)入指定容器
kubectl exec -it test-pod1 -c bs1 -- sh
# 訪問(wèn)nginx(因沒(méi)有curl命令,此處用wget)
/ # wget http://127.0.0.1
Connecting to 127.0.0.1 (127.0.0.1:80)
saving to 'index.html'
index.html 100% |*************************************************************************************************************| 615 0:00:00 ETA
'index.html' saved
/ #
上面看到,使用wget命令下載到了index.html文件,說(shuō)明訪問(wèn)成功。
3. Pod常用管理命令
- 查看pod里所有容器的名稱
kubectl get pods test-pod1 -o jsonpath={.spec.containers[*].name}
- 進(jìn)入pod里的指定容器的終端,如下進(jìn)入pod為test-pod1里的容器nginx1和bs1
kubectl exec -it test-pod1 -c nginx1 -- bash
kubectl exec -it test-pod1 -c bs1 -- sh
- 查看pod里指定容器的log
kubectl logs test-pod1 -c nginx1
4. Pod的重啟策略+應(yīng)用健康檢查(應(yīng)用自修復(fù))
「重啟策略」
- Always:當(dāng)容器終止退出,總是重啟容器,默認(rèn)策略
- OnFailure:當(dāng)容器異常退出(退出狀態(tài)碼非0)時(shí),才重啟容器
- Never:當(dāng)容器終止退出,從不重啟容器
查看pod的重啟策略
# 查看pod,以yaml格式輸出
kubectl get pods test-pod1 -o yaml
# 找到restartPolicy字段,就是重啟策略
restartPolicy: Always
「健康檢查有以下3種類型:」
健康檢查是檢查容器里面的服務(wù)是否正常
- livenessProbe(存活探測(cè)):如果檢查失敗,將殺死容器,根據(jù)pod的restartPolicy來(lái)操作。
- readinessProbe(就緒探測(cè)):如果檢查失敗,k8s會(huì)把Pod從service endpoints中剔除
- startupProbe(啟動(dòng)探測(cè)):檢查成功才由存活檢查接手,用于保護(hù)慢啟動(dòng)容器
「支持以下三種檢查方法:」
- httpGet:發(fā)起HTTP請(qǐng)求,返回200-400范圍狀態(tài)碼為成功。
- exec:執(zhí)行Shell命令返回狀態(tài)碼是0為成功。
- tcpSocket:發(fā)起TCP Socket建立成功。
「案例實(shí)戰(zhàn)」
- livenessProbe(存活探針):使用exec的方式(執(zhí)行Shell命令返回狀態(tài)碼是0則為成功)
apiVersion: v1
kind: Namespace
metadata:
name: test-a
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: goweb-demo
namespace: test-a
spec:
replicas: 10
selector:
matchLabels:
app: goweb-demo
template:
metadata:
labels:
app: goweb-demo
spec:
containers:
- name: goweb-demo
image: 192.168.11.247/web-demo/goweb-demo:20221229v3
livenessProbe:
exec:
command:
- ls
- /opt/goweb-demo/runserver
initialDelaySeconds: 5
periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
name: goweb-demo
namespace: test-a
spec:
ports:
- port: 80
protocol: TCP
targetPort: 8090
selector:
app: goweb-demo
type: NodePort
periodSeconds 字段指定了 kubelet 應(yīng)該每 5 秒執(zhí)行一次存活探測(cè),initialDelaySeconds 字段告訴 kubelet 在執(zhí)行第一次探測(cè)前應(yīng)該等待 5 秒,kubelet 在容器內(nèi)執(zhí)行命令 ls /opt/goweb-demo/runserver 來(lái)進(jìn)行探測(cè)。 如果命令執(zhí)行成功并且返回值為 0,kubelet 就會(huì)認(rèn)為這個(gè)容器是健康存活的。 如果這個(gè)命令返回非 0 值,kubelet 會(huì)殺死這個(gè)容器并重新啟動(dòng)它。
驗(yàn)證存活檢查的效果
# 查看某個(gè)pod的里的容器,
kubectl get pods goweb-demo-686967fd56-556m9 -n test-a -o jsonpath={.spec.containers[*].name}
# 進(jìn)入某個(gè)pod里的容器
kubectl exec -it goweb-demo-686967fd56-556m9 -c goweb-demo -n test-a -- bash
# 進(jìn)入容器后,手動(dòng)刪除掉runserver可執(zhí)行文件,模擬故障
rm -rf /opt/goweb-demo/runserver
# 查看Pod詳情(在輸出結(jié)果的最下面,有信息顯示存活探針失敗了,這個(gè)失敗的容器被殺死并且被重建了。)
kubectl describe pod goweb-demo-686967fd56-556m9 -n test-a
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning Unhealthy 177m (x6 over 3h59m) kubelet Liveness probe failed: ls: cannot access '/opt/goweb-demo/runserver': No such file or directory
# 一旦失敗的容器恢復(fù)為運(yùn)行狀態(tài),RESTARTS 計(jì)數(shù)器就會(huì)增加 1
tantianran@test-b-k8s-master:~$ kubectl get pods -n test-a
NAME READY STATUS RESTARTS AGE
goweb-demo-686967fd56-556m9 1/1 Running 1 (22s ago) 13m # RESTARTS字段加1,
goweb-demo-686967fd56-8hzjb 1/1 Running 0 13m
...
- livenessProbe(存活探針):使用 httpGet 請(qǐng)求的方式檢查uri path是否正常
apiVersion: v1
kind: Namespace
metadata:
name: test-a
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: goweb-demo
namespace: test-a
spec:
replicas: 10
selector:
matchLabels:
app: goweb-demo
template:
metadata:
labels:
app: goweb-demo
spec:
containers:
- name: goweb-demo
image: 192.168.11.247/web-demo/goweb-demo:20221229v3
livenessProbe:
httpGet:
path: /login
port: 8090
httpHeaders:
- name: Custom-Header
value: Awesome
initialDelaySeconds: 3
periodSeconds: 3
---
apiVersion: v1
kind: Service
metadata:
name: goweb-demo
namespace: test-a
spec:
ports:
- port: 80
protocol: TCP
targetPort: 8090
selector:
app: goweb-demo
type: NodePort
在這個(gè)配置文件中,你可以看到 Pod 也只有一個(gè)容器。 periodSeconds 字段指定了 kubelet 每隔 3 秒執(zhí)行一次存活探測(cè)。 initialDelaySeconds 字段告訴 kubelet 在執(zhí)行第一次探測(cè)前應(yīng)該等待 3 秒。 kubelet 會(huì)向容器內(nèi)運(yùn)行的服務(wù)(服務(wù)在監(jiān)聽(tīng) 8090 端口)發(fā)送一個(gè) HTTP GET 請(qǐng)求來(lái)執(zhí)行探測(cè)。 如果服務(wù)器上 /login 路徑下的處理程序返回成功代碼,則 kubelet 認(rèn)為容器是健康存活的。 如果處理程序返回失敗代碼,則 kubelet 會(huì)殺死這個(gè)容器并將其重啟。返回大于或等于 200 并且小于 400 的任何代碼都表示成功,其它返回代碼都表示失敗。
驗(yàn)證效果
# 進(jìn)入容器刪除靜態(tài)文件,模擬故障
kubectl exec -it goweb-demo-586ff85ddb-4646k -c goweb-demo -n test-a -- bash
rm -rf login.html
# 查看pod的log
kubectl logs goweb-demo-586ff85ddb-4646k -n test-a
2023/01/12 06:45:19 [Recovery] 2023/01/12 - 06:45:19 panic recovered:
GET /login HTTP/1.1
Host: 10.244.222.5:8090
Connection: close
Accept: */*
Connection: close
Custom-Header: Awesome
User-Agent: kube-probe/1.25
html/template: "login.html" is undefined
/root/my-work-space/pkg/mod/github.com/gin-gonic/gin@v1.8.2/context.go:911 (0x8836d1)
/root/my-work-space/pkg/mod/github.com/gin-gonic/gin@v1.8.2/context.go:920 (0x88378c)
/root/my-work-space/src/goweb-demo/main.go:10 (0x89584e)
# 查看pod詳情
kubectl describe pod goweb-demo-586ff85ddb-4646k -n test-a
Warning Unhealthy 34s (x3 over 40s) kubelet Liveness probe failed: HTTP probe failed with statuscode: 500 # 狀態(tài)碼為500
# 恢復(fù)后查看Pod,RESTARTS計(jì)數(shù)器已經(jīng)增1
kubectl get pod goweb-demo-586ff85ddb-4646k -n test-a
NAME READY STATUS RESTARTS AGE
goweb-demo-586ff85ddb-4646k 1/1 Running 1 (80s ago) 5m39s
- readinessProbe(就緒探針)結(jié)合livenessProbe(存活探針)探測(cè)tcp端口:
第三種類型的存活探測(cè)是使用 TCP 套接字。 使用這種配置時(shí),kubelet 會(huì)嘗試在指定端口和容器建立套接字鏈接。 如果能建立連接,這個(gè)容器就被看作是健康的,如果不能則這個(gè)容器就被看作是有問(wèn)題的。
apiVersion: v1
kind: Namespace
metadata:
name: test-a
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: goweb-demo
namespace: test-a
spec:
replicas: 10
selector:
matchLabels:
app: goweb-demo
template:
metadata:
labels:
app: goweb-demo
spec:
containers:
- name: goweb-demo
image: 192.168.11.247/web-demo/goweb-demo:20221229v3
readinessProbe:
tcpSocket:
port: 8090
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
tcpSocket:
port: 8090
initialDelaySeconds: 15
periodSeconds: 20
---
apiVersion: v1
kind: Service
metadata:
name: goweb-demo
namespace: test-a
spec:
ports:
- port: 80
protocol: TCP
targetPort: 8090
selector:
app: goweb-demo
type: NodePort
TCP 檢測(cè)的配置和 HTTP 檢測(cè)非常相似。 這個(gè)例子同時(shí)使用就緒和存活探針。kubelet 會(huì)在容器啟動(dòng) 5 秒后發(fā)送第一個(gè)就緒探針。 探針會(huì)嘗試連接 goweb-demo 容器的 8090 端口。 如果探測(cè)成功,這個(gè) Pod 會(huì)被標(biāo)記為就緒狀態(tài),kubelet 將繼續(xù)每隔 10 秒運(yùn)行一次探測(cè)。除了就緒探針,這個(gè)配置包括了一個(gè)存活探針。 kubelet 會(huì)在容器啟動(dòng) 15 秒后進(jìn)行第一次存活探測(cè)。 與就緒探針類似,存活探針會(huì)嘗試連接 goweb-demo 容器的 8090 端口。 如果存活探測(cè)失敗,容器會(huì)被重新啟動(dòng)。
驗(yàn)證效果
# 進(jìn)入容器后,殺掉goweb-demo的進(jìn)程
kubectl exec -it goweb-demo-5d7d55f846-vm2kc -c goweb-demo -n test-a -- bash
root@goweb-demo-5d7d55f846-vm2kc:/opt/goweb-demo# ps -aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 2476 576 ? Ss 07:23 0:00 /bin/sh -c /opt/goweb-demo/runserver
root@goweb-demo-5d7d55f846-vm2kc:/opt/goweb-demo# kill -9 1
# 查看pod詳情,已經(jīng)發(fā)出警告
kubectl describe pod goweb-demo-5d7d55f846-vm2kc -n test-a
Warning Unhealthy 16s kubelet Readiness probe failed: dial tcp 10.244.240.48:8090: connect: connection refused
Warning BackOff 16s kubelet Back-off restarting failed container
# 查看pod,RESTARTS計(jì)數(shù)器已經(jīng)增加為2,因?yàn)橛袃蓚€(gè)探針
tantianran@test-b-k8s-master:~$ kubectl get pod -n test-a
NAME READY STATUS RESTARTS AGE
goweb-demo-5d7d55f846-vm2kc 1/1 Running 2 (2m55s ago) 12m
- 使用startupProbe(啟動(dòng)探針)保護(hù)慢啟動(dòng)容器
有一種情景是這樣的,某些應(yīng)用在啟動(dòng)時(shí)需要較長(zhǎng)的初始化時(shí)間。要這種情況下,若要不影響對(duì)死鎖作出快速響應(yīng)的探測(cè),設(shè)置存活探測(cè)參數(shù)是要技巧的。 技巧就是使用相同的命令來(lái)設(shè)置啟動(dòng)探測(cè),針對(duì) HTTP 或 TCP 檢測(cè),可以通過(guò)將 failureThreshold * periodSeconds 參數(shù)設(shè)置為足夠長(zhǎng)的時(shí)間來(lái)應(yīng)對(duì)糟糕情況下的啟動(dòng)時(shí)間。
apiVersion: v1
kind: Namespace
metadata:
name: test-a
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: goweb-demo
namespace: test-a
spec:
replicas: 10
selector:
matchLabels:
app: goweb-demo
template:
metadata:
labels:
app: goweb-demo
spec:
containers:
- name: goweb-demo
image: 192.168.11.247/web-demo/goweb-demo:20221229v3
livenessProbe:
httpGet:
path: /login
port: 8090
failureThreshold: 1
periodSeconds: 10
startupProbe:
httpGet:
path: /login
port: 8090
failureThreshold: 30
periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
name: goweb-demo
namespace: test-a
spec:
ports:
- port: 80
protocol: TCP
targetPort: 8090
selector:
app: goweb-demo
type: NodePort
上面的例子,應(yīng)用程序?qū)?huì)有最多 5 分鐘(30 * 10 = 300s)的時(shí)間來(lái)完成其啟動(dòng)過(guò)程。 一旦啟動(dòng)探測(cè)成功一次,存活探測(cè)任務(wù)就會(huì)接管對(duì)容器的探測(cè),對(duì)容器死鎖作出快速響應(yīng)。 如果啟動(dòng)探測(cè)一直沒(méi)有成功,容器會(huì)在 300 秒后被殺死,并且根據(jù) restartPolicy 來(lái)執(zhí)行進(jìn)一步處置。
5. 環(huán)境變量
創(chuàng)建 Pod 時(shí),可以為其下的容器設(shè)置環(huán)境變量。通過(guò)配置文件的 env 或者 envFrom 字段來(lái)設(shè)置環(huán)境變量。
應(yīng)用場(chǎng)景:
- 容器內(nèi)應(yīng)用程序獲取pod信息
- 容器內(nèi)應(yīng)用程序通過(guò)用戶定義的變量改變默認(rèn)行為
變量值定義的方式:
- 自定義變量值
- 變量值從Pod屬性獲取
- 變量值從Secret、ConfigMap獲取
下面來(lái)個(gè)小例子,設(shè)置自定義變量,使用env給pod里的容器設(shè)置環(huán)境變量,本例子中,設(shè)置了環(huán)境變量有SAVE_TIME、MAX_CONN、DNS_ADDR。
apiVersion: v1
kind: Pod
metadata:
name: test-env-demo
spec:
containers:
- name: test-env-demo-container
image: 192.168.11.247/web-demo/goweb-demo:20221229v3
env:
- name: SAVE_TIME
value: "60"
- name: MAX_CONN
value: "1024"
- name: DNS_ADDR
value: "8.8.8.8"
開(kāi)始創(chuàng)建pod
tantianran@test-b-k8s-master:~$ kubectl create -f test-env.yaml
pod/test-env-demo created
tantianran@test-b-k8s-master:~$
創(chuàng)建后,驗(yàn)證環(huán)境變量是否能獲取到
# 使用printenv打印環(huán)境變量
tantianran@test-b-k8s-master:~/goweb-demo$ kubectl exec test-env-demo -- printenv
PATH=/go/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=test-env-demo
SAVE_TIME=60 # 這個(gè)是
MAX_CONN=1024 # 這個(gè)是
DNS_ADDR=8.8.8.8 # 這個(gè)是
KUBERNETES_SERVICE_HOST=10.96.0.1
KUBERNETES_SERVICE_PORT=443
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
GOLANG_VERSION=1.19.4
GOPATH=/go
HOME=/root
tantianran@test-b-k8s-master:~/goweb-demo$
# 進(jìn)入容器打印環(huán)境變量
tantianran@test-b-k8s-master:~/goweb-demo$ kubectl exec -it test-env-demo -c test-env-demo-container -- bash
root@test-env-demo:/opt/goweb-demo# echo $SAVE_TIME # 單獨(dú)打印一個(gè)
60
root@test-env-demo:/opt/goweb-demo# env # 執(zhí)行env命令查看
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_SERVICE_PORT=443
HOSTNAME=test-env-demo
PWD=/opt/goweb-demo
DNS_ADDR=8.8.8.8
HOME=/root
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
MAX_CONN=1024
GOLANG_VERSION=1.19.4
TERM=xterm
SHLVL=1
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
SAVE_TIME=60
KUBERNETES_SERVICE_HOST=10.96.0.1
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP_PORT=443
PATH=/go/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
GOPATH=/go
_=/usr/bin/env
root@test-env-demo:/opt/goweb-demo#
再來(lái)個(gè)小例子,直接取pod的屬性作為變量的值,下面的例子是拿到pod所處的節(jié)點(diǎn)名稱
apiVersion: v1
kind: Pod
metadata:
name: test-env-demo
spec:
containers:
- name: test-env-demo-container
image: 192.168.11.247/web-demo/goweb-demo:20221229v3
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
打印變量
tantianran@test-b-k8s-master:~$ kubectl exec test-env-demo -- printenv
PATH=/go/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=test-env-demo
NODE_NAME=test-b-k8s-node02 # NODE_NAME變量,值為test-b-k8s-node02
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
KUBERNETES_SERVICE_HOST=10.96.0.1
KUBERNETES_SERVICE_PORT=443
KUBERNETES_SERVICE_PORT_HTTPS=443
GOLANG_VERSION=1.19.4
GOPATH=/go
HOME=/root
再來(lái)最后一個(gè)例子,使用容器字段作為環(huán)境變量的值,這個(gè)例子設(shè)置了資源限制的字段requests和limits,在設(shè)置環(huán)境變量中,使用資源限制的值作為了變量的值。
apiVersion: v1
kind: Pod
metadata:
name: test-env-demo
spec:
containers:
- name: test-env-demo-container
image: 192.168.11.247/web-demo/goweb-demo:20221229v3
resources:
requests:
memory: "32Mi"
cpu: "125m"
limits:
memory: "64Mi"
cpu: "250m"
env:
- name: CPU_REQUEST
valueFrom:
resourceFieldRef:
containerName: test-env-demo-container
resource: requests.cpu
- name: CPU_LIMIT
valueFrom:
resourceFieldRef:
containerName: test-env-demo-container
resource: limits.cpu
- name: MEM_REQUEST
valueFrom:
resourceFieldRef:
containerName: test-env-demo-container
resource: requests.memory
- name: MEM_LIMIT
valueFrom:
resourceFieldRef:
containerName: test-env-demo-container
resource: limits.memory
打印變量
tantianran@test-b-k8s-master:~$ kubectl exec test-env-demo -- printenv
PATH=/go/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=test-env-demo
MEM_REQUEST=33554432
MEM_LIMIT=67108864
CPU_REQUEST=1
CPU_LIMIT=1
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
KUBERNETES_SERVICE_HOST=10.96.0.1
KUBERNETES_SERVICE_PORT=443
GOLANG_VERSION=1.19.4
GOPATH=/go
HOME=/root
6. init container(初始化容器)
初始化容器的特點(diǎn):
- Init容器是一種特殊容器,在Pod內(nèi),會(huì)在應(yīng)用容器啟動(dòng)之前運(yùn)行。
- 如果Pod的Init容器失敗,kubelet會(huì)不斷地重啟該Init容器,直到該容器成功為止。
- 如果 Pod 對(duì)應(yīng)的 restartPolicy 值為 "Never",并且 Pod 的 Init 容器失敗, 則 Kubernetes 會(huì)將整個(gè) Pod 狀態(tài)設(shè)置為失敗。
- 如果為一個(gè) Pod 指定了多個(gè) Init 容器,這些容器會(huì)按順序逐個(gè)運(yùn)行。 每個(gè) Init 容器必須運(yùn)行成功,下一個(gè)才能夠運(yùn)行。
- Init 容器不支持探針,包括 lifecycle、livenessProbe、readinessProbe 和 startupProbe
在實(shí)際工作中,可利用它的這種工作機(jī)制應(yīng)對(duì)某些場(chǎng)景,比如在應(yīng)用容器啟動(dòng)之前,需要做一些初始化相關(guān)的工作,比如初始化配置文件,測(cè)試IP或端口的連通性等等場(chǎng)景。
下面來(lái)個(gè)小例子,場(chǎng)景是這樣的,我的應(yīng)用容器是goweb-demo,初始化容器是init-check-mysql-ip,假設(shè)應(yīng)用容器是依賴數(shù)據(jù)庫(kù)的,如果數(shù)據(jù)庫(kù)沒(méi)起來(lái),那么應(yīng)用容器就算起來(lái)了也是服務(wù)不可用。所以,現(xiàn)在的主要目的是想在應(yīng)用容器啟動(dòng)之前檢查mysql服務(wù)器的IP地址是否可ping通,如果是通的才啟動(dòng)應(yīng)用容器。這個(gè)例子應(yīng)該是比較貼近實(shí)際場(chǎng)景了。下面,看我寫好的yaml:
apiVersion: v1
kind: Namespace
metadata:
name: test-a
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: goweb-demo
namespace: test-a
spec:
replicas: 3
selector:
matchLabels:
app: goweb-demo
template:
metadata:
labels:
app: goweb-demo
spec:
containers:
- name: goweb-demo
image: 192.168.11.247/web-demo/goweb-demo:20221229v3
initContainers:
- name: init-check-mysql-ip
image: 192.168.11.247/os/busybox:latest
command: ['sh', '-c', "ping 192.168.11.248 -c 5"]
---
apiVersion: v1
kind: Service
metadata:
name: goweb-demo
namespace: test-a
spec:
ports:
- port: 80
protocol: TCP
targetPort: 8090
selector:
app: goweb-demo
type: NodePort
mysql服務(wù)器故意沒(méi)拉起,看看效果:
tantianran@test-b-k8s-master:~/goweb-demo$ kubectl get pods -n test-a
NAME READY STATUS RESTARTS AGE
goweb-demo-859cc77bd5-jpcfs 0/1 Init:0/1 2 (18s ago) 48s
goweb-demo-859cc77bd5-n8hqd 0/1 Init:0/1 2 (17s ago) 48s
goweb-demo-859cc77bd5-sns67 0/1 Init:0/1 2 (17s ago) 48s
tantianran@test-b-k8s-master:~/goweb-demo$
tantianran@test-b-k8s-master:~/goweb-demo$ kubectl get pods -n test-a
NAME READY STATUS RESTARTS AGE
goweb-demo-859cc77bd5-jpcfs 0/1 Init:Error 4 (67s ago) 2m44s
goweb-demo-859cc77bd5-n8hqd 0/1 Init:Error 4 (66s ago) 2m44s
goweb-demo-859cc77bd5-sns67 0/1 Init:Error 4 (67s ago) 2m44s
tantianran@test-b-k8s-master:~/goweb-demo$
tantianran@test-b-k8s-master:~/goweb-demo$ kubectl get pods -n test-a
NAME READY STATUS RESTARTS AGE
goweb-demo-859cc77bd5-jpcfs 0/1 Init:CrashLoopBackOff 3 (34s ago) 2m11s
goweb-demo-859cc77bd5-n8hqd 0/1 Init:CrashLoopBackOff 3 (33s ago) 2m11s
goweb-demo-859cc77bd5-sns67 0/1 Init:CrashLoopBackOff 3 (34s ago) 2m11s
tantianran@test-b-k8s-master:~/goweb-demo$
觀察STATUS字段發(fā)現(xiàn),它經(jīng)歷了3個(gè)階段,第一階段是正常的運(yùn)行,也就是執(zhí)行ping檢查的操作,因?yàn)樗阑頟ing不同,所以進(jìn)入了第二階段,狀態(tài)為Error。緊接著是第三階段,狀態(tài)變成了CrashLoopBackOff,對(duì)于這個(gè)狀態(tài),我的理解是,初始化容器運(yùn)行失敗了,準(zhǔn)備再次運(yùn)行??偠灾?,如果Mysql服務(wù)器的IP死活ping不通,它就會(huì)的狀態(tài)就會(huì)一直這樣:運(yùn)行->Error->CrashLoopBackOff。當(dāng)然這種情況是當(dāng)Pod對(duì)應(yīng)的restartPolicy為"Always"(這是默認(rèn)策略)才會(huì)這樣不斷的循環(huán)檢查,如果Pod對(duì)應(yīng)的restartPolicy值為"Never",并且Pod的 Init容器失敗,則Kubernetes會(huì)將整個(gè)Pod狀態(tài)設(shè)置為失敗。
當(dāng)我把mysql服務(wù)器啟動(dòng)后,初始化容器執(zhí)行成功,那么應(yīng)用容器也就成功起來(lái)了:
tantianran@test-b-k8s-master:~/goweb-demo$ kubectl get pods -n test-a
NAME READY STATUS RESTARTS AGE
goweb-demo-859cc77bd5-jpcfs 1/1 Running 0 30m
goweb-demo-859cc77bd5-n8hqd 1/1 Running 0 30m
goweb-demo-859cc77bd5-sns67 1/1 Running 0 30m
tantianran@test-b-k8s-master:~/goweb-demo$
7. 靜態(tài)pod
在實(shí)際工作中,靜態(tài)Pod的應(yīng)用場(chǎng)景是畢竟少的,幾乎沒(méi)有。不過(guò)也還是得對(duì)它做一個(gè)簡(jiǎn)單的了解。靜態(tài)Pod在指定的節(jié)點(diǎn)上由 kubelet 守護(hù)進(jìn)程直接管理,不需要 API 服務(wù)器監(jiān)管。 與由控制面管理的 Pod(例如,Deployment) 不同;kubelet 監(jiān)視每個(gè)靜態(tài) Pod(在它失敗之后重新啟動(dòng)),靜態(tài) Pod 始終都會(huì)綁定到特定節(jié)點(diǎn)的 Kubelet上。
在每個(gè)node節(jié)點(diǎn)上,kubelet的守護(hù)進(jìn)程會(huì)自動(dòng)在/etc/kubernetes/manifests/路徑下發(fā)現(xiàn)yaml,因此,如果想要?jiǎng)?chuàng)建靜態(tài)Pod,就得把yaml放到該目錄,下面我們直接實(shí)戰(zhàn)一下。
隨便登錄到某臺(tái)node節(jié)點(diǎn),然后創(chuàng)建/etc/kubernetes/manifests/static_pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: test-static-pod
spec:
containers:
- name: test-container
image: 192.168.11.247/web-demo/goweb-demo:20221229v3
創(chuàng)建后,回到master節(jié)點(diǎn)上查看pod
tantianran@test-b-k8s-master:~$ kubectl get pod
NAME READY STATUS RESTARTS AGE
test-static-pod-test-b-k8s-node01 1/1 Running 0 11s
通過(guò)上面的輸出結(jié)果可以看到,該靜態(tài)pod已經(jīng)在節(jié)點(diǎn)test-b-k8s-node01上面正常運(yùn)行了,說(shuō)明kubelet守護(hù)進(jìn)程已經(jīng)自動(dòng)發(fā)現(xiàn)并創(chuàng)建了它。你可能會(huì)問(wèn),它不是不需要API服務(wù)器監(jiān)管嗎?為啥在master節(jié)點(diǎn)能看到它?因?yàn)閗ubelet 會(huì)嘗試通過(guò) Kubernetes API服務(wù)器為每個(gè)靜態(tài)Pod自動(dòng)創(chuàng)建一個(gè)鏡像Pod,這意味著節(jié)點(diǎn)上運(yùn)行的靜態(tài)Pod對(duì)API服務(wù)來(lái)說(shuō)是可見(jiàn)的,但是不能通過(guò)API服務(wù)器來(lái)控制。 且Pod名稱將把以連字符開(kāi)頭的節(jié)點(diǎn)主機(jī)名作為后綴。
本文轉(zhuǎn)載于(喜歡的盆友關(guān)注我們):https://mp.weixin.qq.com/s/5Kv7DU34_Ae5y17MAQVO-Q