一. 簡(jiǎn)介
Kubernetes 里“最小”的 API 對(duì)象是 Pod淘衙。Pod 可以等價(jià)為一個(gè)應(yīng)用蚓让,所以,Pod 可以由多個(gè)緊密協(xié)作的容器組成限匣。在 Kubernetes 中抖苦,我們經(jīng)常會(huì)看到它通過(guò)一種 API 對(duì)象來(lái)管理另一種 API 對(duì)象,比如 Deployment 和 Pod 之間的關(guān)系,而由于 Pod 是“最小”的對(duì)象锌历,所以它往往都是被其他對(duì)象控制的贮庞。
這種組合方式,正是 Kubernetes 進(jìn)行容器編排的重要模式究西。
二. 流程
關(guān)于如何演示kubectl apply 如何使用窗慎,下面講創(chuàng)造一個(gè)這樣的場(chǎng)景:
運(yùn)行一個(gè)3個(gè)副本的nginx應(yīng)用,并且nginx指定版本為1.7.9卤材,同時(shí)對(duì)外暴露80端口遮斥。
本篇文章相關(guān)代碼,已在GitHub此鏈接:demo-deployment.yaml
2.1 編寫(xiě)YAML
Kubernetes 跟 Docker 等很多項(xiàng)目最大的不同扇丛,就在于它不推薦我們使用命令行的方式直接運(yùn)行容器(雖然 Kubernetes 項(xiàng)目也支持這種方式伏伐,比如:kubectl run
),而是希望用 YAML
文件的方式晕拆,即:把容器的定義藐翎、參數(shù)、配置实幕,統(tǒng)統(tǒng)記錄在一個(gè)YAML
文件中吝镣。
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
如上的一個(gè) YAML 文件,對(duì)應(yīng)到 Kubernetes 中昆庇,就是一個(gè) API Object(API 對(duì)象)末贾。當(dāng)你為這個(gè)對(duì)象的各個(gè)字段填好值并提交給 Kubernetes 之后,Kubernetes 就會(huì)負(fù)責(zé)創(chuàng)建出這些對(duì)象所定義的容器或者其他類(lèi)型的 API 資源整吆。
2.2 分析YAML
針對(duì)如上的yaml拱撵,細(xì)節(jié)參數(shù)含義如下:
- apiVersion:Api版本
- kind:指定當(dāng)前Api type為Deployment
- spec.selector.mathcLabels:標(biāo)簽,作為過(guò)濾篩選使用
- spec.replicas:當(dāng)前定義的Pod的數(shù)量表蝙,也就是期望值拴测,Kubernetes會(huì)一直保證期望值=實(shí)際值
- spec.containers.image:容器的具體鏡像名稱(chēng)+版本號(hào)
- spec.containers:容器相關(guān)配置
Labels這個(gè)字段也是上面的重點(diǎn)。這樣的每一個(gè) API 對(duì)象都有一個(gè)叫作 Metadata 的字段府蛇,這個(gè)字段就是 API 對(duì)象的“標(biāo)識(shí)”集索,即元數(shù)據(jù),它也是我們從 Kubernetes 里找到這個(gè)對(duì)象的主要依據(jù)汇跨。這其中最主要使用到的字段是 Labels务荆。換句話說(shuō),Labels 就是一組 key-value 格式的標(biāo)簽穷遂。
而像 Deployment 這樣的控制器對(duì)象函匕,就可以通過(guò)這個(gè) Labels 字段從 Kubernetes 中過(guò)濾出它所關(guān)心的被控制對(duì)象。
比如蚪黑,在上面這個(gè)YAML文件中盅惜,Deployment 會(huì)把所有正在運(yùn)行的中剩、攜帶“app: nginx”標(biāo)簽的 Pod 識(shí)別為被管理的對(duì)象,并確保這些 Pod 的總數(shù)嚴(yán)格等于三個(gè)酷窥。而這個(gè)過(guò)濾規(guī)則的定義咽安,是在 Deployment 的“spec.selector.matchLabels”字段。我們一般稱(chēng)之為:Label Selector蓬推。
一個(gè) Kubernetes 的 API 對(duì)象的定義妆棒,大多可以分為 Metadata 和 Spec 兩個(gè)部分。
- Metadata
Metadata存放的是這個(gè)對(duì)象的元數(shù)據(jù)沸伏,對(duì)所有 API 對(duì)象來(lái)說(shuō)糕珊,這部分的字段和格式基本上是一樣的。 - Spec
Spec存放的是屬于這個(gè)對(duì)象獨(dú)有的定義毅糟,用來(lái)描述它所要表達(dá)的功能红选。
2.3 運(yùn)行YAML
指令如下:
kubectl apply -f demo-deployment.yaml (推薦)
# kubectl create -f demo-deployment.yaml
成功后,如下圖:
2.4 檢查Pods
通過(guò)kubectl get
命令檢查這個(gè)YAML
運(yùn)行的運(yùn)行結(jié)果是否與期望一致:
kubectl get pods -l app=nginx
NAME READY STATUS RESTARTS AGE
demo-deployment-5d59d67564-6dxnv 1/1 Running 0 2m23s
demo-deployment-5d59d67564-lgxzx 1/1 Running 0 2m23s
demo-deployment-5d59d67564-pcdk5 1/1 Running 0 2m23s
看到如下的狀態(tài)姆另,我們可以看到現(xiàn)在有3個(gè) Pod 處于 Running 狀態(tài)喇肋,也就意味著我們這個(gè) Deployment 所管理的 Pod 都處于預(yù)期的狀態(tài)。
kubectl get
指令的作用迹辐,就是從 Kubernetes 里面獲鹊馈(GET)指定的 API 對(duì)象∶鞣裕可以看到间学,在這里還加上了一個(gè)-l
參數(shù),即獲取所有匹配 app: nginx
標(biāo)簽的 Pod印荔。
一個(gè)細(xì)節(jié)問(wèn)題:在命令行中低葫,所有 key-value
格式的參數(shù),都使用“=”而非“:”表示仍律。
2.5 kubectl describe
我們從上面的Pod Name中挑選一個(gè)Pod嘿悬,使用kubectl describe
進(jìn)入查看。
kubectl describe pod demo-deployment-5d59d67564-6dxnv
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 8m default-scheduler Successfully assigned default/demo-deployment-5d59d67564-6dxnv to docker-desktop
Normal Pulled 7m59s kubelet Container image "nginx:1.7.9" already present on machine
Normal Created 7m59s kubelet Created container nginx
Normal Started 7m58s kubelet Started container nginx
在kubectl describe
命令返回的結(jié)果中染苛,可以清楚地看到這個(gè) Pod 的詳細(xì)信息鹊漠,比如它的 IP 地址等等。
在整個(gè)pod內(nèi)容體里面茶行,我們可以關(guān)注一下Events的內(nèi)容。在 Kubernetes 執(zhí)行的過(guò)程中登钥,對(duì) API 對(duì)象的所有重要操作畔师,都會(huì)被記錄在這個(gè)對(duì)象的 Events 里,并且顯示在kubectl describe
指令返回的結(jié)果中牧牢。
這個(gè)Events從上向下看即可看锉,對(duì)于當(dāng)前這個(gè) Pod姿锭,我們可以看到它被創(chuàng)建之后,被調(diào)度器調(diào)度(Successfully assigned)
到了 docker-desktop
伯铣,拉取了指定的鏡像(本地)(Container image)
呻此,然后啟動(dòng)了 Pod 里定義的容器(Started container)
。
這個(gè)正是我們將來(lái)進(jìn)行 Debug 的重要依據(jù)腔寡。如果有異常發(fā)生焚鲜,我們就可以第一時(shí)間查看這些 Events,往往可以看到非常詳細(xì)的錯(cuò)誤信息放前。
2.6 更新YAML(patch功能)
如果我們要對(duì)這個(gè) Nginx 服務(wù)進(jìn)行升級(jí)忿磅,把它的鏡像版本從 1.7.9 升級(jí)為 1.8,那么操作還是很簡(jiǎn)單凭语。
- 只需要變動(dòng)YAML的nginx版本即可
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.8.0 # 這里被從1.7.9修改為1.8
ports:
- containerPort: 80
- 執(zhí)行
kubectl apply
指令
kubectl apply -f demo-deployment.yaml (推薦)
# kubectl replace -f demo-deployment.yaml(不推薦)
- 查看Pods狀態(tài)
kubectl get pods -l app=nginx
NAME READY STATUS RESTARTS AGE
demo-deployment-64c9d67564-9m64m 1/1 Running 0 39s
demo-deployment-64c9d67564-m7l8w 1/1 Running 0 37s
demo-deployment-64c9d67564-rv5vs 1/1 Running 0 82s
是否覺(jué)得同一條指令kubectl apply
可以進(jìn)行增改操作很神奇葱她?這就是 Kubernetes“聲明式 API”所推薦的使用方法。
執(zhí)行的命令始終是 kubectl apply
似扔,而 Kubernetes 則會(huì)根據(jù) YAML 文件的內(nèi)容變化吨些,自動(dòng)進(jìn)行具體的處理。而這個(gè)流程的好處是,它有助于幫助開(kāi)發(fā)和運(yùn)維人員稽揭,圍繞著可以版本化管理的 YAML 文件丁稀,而不是“行蹤不定”的命令行進(jìn)行協(xié)作,從而大大降低開(kāi)發(fā)人員和運(yùn)維人員之間的溝通成本但校。
2.7 刪除demo-deployment
Kubernetes會(huì)自動(dòng)刪除YAML所相關(guān)的所有程序,這也是自動(dòng)化與自描述帶來(lái)的好處啡氢。
執(zhí)行如下指令即可:
kubectl delete -f demo-deployment.yaml
三. Volume
3.1 Volume基礎(chǔ)類(lèi)型
這兒的Volume是Kubernetes里面状囱,而非docker,但是本質(zhì)上出別不大倘是。具體為如下倆種:
emptyDir
其實(shí)就等同于我們之前講過(guò)的 Docker 的隱式 Volume 參數(shù)亭枷,即:不顯式聲明宿主機(jī)目錄的 Volume。所以搀崭,Kubernetes 也會(huì)在宿主機(jī)上創(chuàng)建一個(gè)臨時(shí)目錄叨粘,這個(gè)目錄將來(lái)就會(huì)被綁定掛載到容器所聲明的 Volume 目錄上。hostPath
與上面相反瘤睹,就是顯式的 Volume 定義升敲。
3.2 案例
- emptyDir類(lèi)型
參考項(xiàng)目項(xiàng)目中的V2版本,使用的是emptyDir
類(lèi)型轰传。
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
volumeMounts:
- mountPath: "/usr/share/nginx/html"
name: nginx-volume
volumes:
- name: nginx-volume
emptyDir: {}
我們?cè)?Deployment 的 Pod 模板部分添加了一個(gè)volumes
字段驴党,定義了這個(gè) Pod 聲明的所有 Volume。它的名字叫作 nginx-volume
获茬,類(lèi)型是 emptyDir
港庄。
Pod 中的容器倔既,使用的是 volumeMounts
字段來(lái)聲明自己要掛載哪個(gè)Volume
,并通過(guò) mountPath
字段來(lái)定義容器內(nèi)的 Volume 目錄鹏氧,比如:/usr/share/nginx/html
渤涌。
- hostPath類(lèi)型
參考項(xiàng)目項(xiàng)目中的V3版本,使用的是hostPath
類(lèi)型把还。
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
volumeMounts:
- mountPath: "/usr/share/nginx/html"
name: nginx-volume
volumes:
- name: nginx-volume
hostPath:
path: "/var/tmp"
這個(gè)和上面類(lèi)型原理同等实蓬,只是容器 Volume 掛載的宿主機(jī)目錄,就變成了 /var/tmp
笨篷。
3.4 kubectl exec
可以使用 kubectl exec
指令瞳秽,進(jìn)入到這個(gè) Pod 當(dāng)中(即容器的 Namespace 中)查看這個(gè) Volume 目錄:
kubectl exec -it demo-deployment-5846465d4d-vpkb2 -- /bin/bash
# ls /usr/share/nginx/html/
四. 總結(jié)
關(guān)于Kubernetes與Docker的組合,我們已經(jīng)可以按照如下步驟進(jìn)行落地編寫(xiě)了:
- 在本地通過(guò) Docker 測(cè)試代碼率翅,制作鏡像
- 選擇合適的 Kubernetes API 對(duì)象练俐,編寫(xiě)對(duì)應(yīng) YAML 文件(比如,Pod冕臭,Deployment)
- 在 Kubernetes 上部署這個(gè) YAML 文件腺晾。
我們會(huì)發(fā)現(xiàn)Kubernetes與Docker很多指令很相同,但是以后我們還是少用Docker指令辜贵,畢竟Docker只是整個(gè)云原生中很小的一個(gè)實(shí)現(xiàn)類(lèi)而已悯蝉,Kubernetes才是中樞系統(tǒng)。
本篇文章托慨,我講了一個(gè)最常見(jiàn)的Deployment落地的全生命周期操作流程鼻由,關(guān)于每個(gè)細(xì)節(jié)其實(shí)還有很多其他內(nèi)容,這也是后面細(xì)分方向文章的重點(diǎn)厚棵。
最后蕉世,歡迎關(guān)注我的博客:https://blog.wyatt.plus
Reference
https://kubernetes.io/docs/setup/
https://medium.com/google-cloud/kubernetes-101-pods-nodes-containers-and-clusters-c1509e409e16
https://time.geekbang.org/column/article/40008?utm_campaign=guanwang&utm_source=baidu-ad&utm_medium=ppzq-pc&utm_content=title&utm_term=baidu-ad-ppzq-title