自己的筆記,沒(méi)有整理,慎看。。
章節(jié)目錄
1. 容器
1.1 容器的本質(zhì)
1.2 容器鏡像
1.3 容器編排
2. k8s集群搭建
2.1 kubeadm工作流程介紹
2.2 搭建完整的k8s集群
2.3 編寫(xiě)yaml文件
3. K8s容器編排和作業(yè)管理
3.1 Pod
3.2 Deployment
3.3 StatfulSet
3.4 DeamonSet
3.5 Job
1. 容器
1.1 容器的本質(zhì)
容器的本質(zhì)是一種特殊的進(jìn)程
啟動(dòng)進(jìn)程的時(shí)候指定namespace,在/proc/pid/ns查看
/sys/fs/cgroup/下面限制進(jìn)程的資源使用
1.2 容器鏡像
容器鏡像rootfs打包了所有的程序依賴(lài)的操作系統(tǒng)文件和目錄(但不包含內(nèi)核),解決了一致性的問(wèn)題
docker鏡像的創(chuàng)新:層。多個(gè)增量rootfs聯(lián)合掛載成為一個(gè)rootfs
層都放置在 /var/lib/docker/aufs/diff 目錄下
每個(gè)層是一個(gè)增量rootfs,層們疊加起來(lái)是一個(gè)完整的操作系統(tǒng)環(huán)境,被聯(lián)合掛載在/var/lib/docker/aufs/mnt/
一個(gè)鏡像由哪些層組成:/sys/fs/aufs
對(duì)容器鏡像rootfs來(lái)說(shuō),層分三部分:
第一部分只讀層:掛載方式都是只讀的ro+wh,即 readonly+whiteout
第二部分可讀寫(xiě)層:掛載方式為:rw即read write。存放對(duì)rootfs的增刪改
第三部分init層:docker內(nèi)部層,專(zhuān)門(mén)存放/etc/hosts, /etc/resolv.conf。
分三類(lèi)層的原因是可以分開(kāi)使用,docker commit時(shí),實(shí)際上就是在容器運(yùn)行起來(lái)后,把可讀寫(xiě)層,加上原先容器鏡像的只讀層,打包組成了一個(gè)新的鏡像,而init層的文件故意不打包了,因?yàn)槟鞘悄阕约涵h(huán)境的修改
1.3 Volume
解決的問(wèn)題:如何讓容器里的進(jìn)程訪問(wèn)到宿主機(jī)上的文件?
在docker run的時(shí)候聲明一個(gè)volume,實(shí)現(xiàn)原理:
在rootfs準(zhǔn)備好后,在chroot執(zhí)行之前,執(zhí)行bind mount掛載,這個(gè)掛載只有容器內(nèi)部可見(jiàn),宿主機(jī)不可見(jiàn),由于是綁定掛載,在容器目錄進(jìn)行的所有操作實(shí)際發(fā)生在宿主機(jī),而由于宿主機(jī)看不到掛載點(diǎn)的存在,容器中可讀寫(xiě)層的目錄也是空的,不會(huì)被打到鏡像里
1.4 k8s里的容器編排
k8s不僅僅提供一個(gè)給定的集群能夠?qū)⑷萜饕匀萜麋R像為基礎(chǔ)運(yùn)行起來(lái),并提供路由、監(jiān)控、災(zāi)備、可擴(kuò)展等運(yùn)維能力,
他的設(shè)計(jì)思想在于普適性,以宏觀的角度,以統(tǒng)一的方式能適配各種任務(wù)與任務(wù)之間的關(guān)系,并對(duì)將來(lái)可能出現(xiàn)的新的關(guān)系支持自定義
例如,兩個(gè)任務(wù)需要非常頻繁的交互,通過(guò)本地文件進(jìn)行信息交互,在常規(guī)情況下,他們會(huì)部署在同一臺(tái)機(jī)器,在k8s中,他們做為兩個(gè)容器被劃分為一個(gè)pod,pod里的他們共享同一個(gè)network ns,同一個(gè)volume
又例如,web應(yīng)用和db的關(guān)系,如果他們是兩個(gè)容器,當(dāng)他們的ip變化,將無(wú)法找到服務(wù),而k8s里,給數(shù)據(jù)庫(kù)pod綁定service,service的ip終生不變,作為pod的入口暴露一個(gè)穩(wěn)定ip
再例如,web應(yīng)用需要訪問(wèn)db,k8s提供secret對(duì)象,保存在etcd里的數(shù)據(jù),啟動(dòng)pod時(shí),以volume的方式掛載到容器,就有權(quán)限了
本章命令總結(jié)
docker build -t helloworld .
docker image ls
docker run -p 4000:80 helloworld????啟動(dòng)容器
docker tag helloworld geektime/helloworld:v1????起名字
docker push geektime/helloworld:v1????push到docker倉(cāng)庫(kù)
docker exec -it 4ddf4638572d /bin/sh????進(jìn)入容器,使用setns()系統(tǒng)調(diào)用
docker commit 4ddf4638572d geektime/helloworld:v2????提交修改到鏡像中保存
2. K8s集群搭建
2.1 使用kubeadm,kubeadm工作流程:
0. 安裝kubeadm,kubeadm 和 kubelet、kubectl、kubernetes-cni會(huì)一起安裝好
1. 前置檢查
2. 生成證書(shū)和目錄
3. 為其他組件生成訪問(wèn)kube-apiserver所需的配置文件/etc/kubernetes/xxx.conf
4. 為master組件(kube-apiserver、kube-controller-manager、kube-scheduler)生成pod配置文件
5. 為集群生成一個(gè) bootstrap token, 安全認(rèn)證用到,用來(lái)讓安裝了 kubelet 和 kubadm 的節(jié)點(diǎn)通過(guò)kubeadm join加入到集群中
6. kubeadm 會(huì)將 ca.crt 等 Master 節(jié)點(diǎn)的重要信息,通過(guò) ConfigMap 的方式保存在 Etcd 當(dāng)中,供后續(xù)部署 Node 節(jié)點(diǎn)使用
7. 最后一步, 安裝默認(rèn)插件kube-proxy 和 DNS,提供服務(wù)發(fā)現(xiàn)和DNS功能,也是通過(guò)yaml創(chuàng)建pod
2.2 部署完整的k8s集群的過(guò)程
1. 在所有節(jié)點(diǎn)上安裝 Docker 和 kubeadm;
2. 部署 Kubernetes Master;
3. 部署容器網(wǎng)絡(luò)插件;
4. 部署 Kubernetes Worker;
5. 部署 Dashboard 可視化插件;
6. 部署容器存儲(chǔ)插件。
2.3 yaml配置文件說(shuō)明
示例:
apiVersion: apps/v1
kind: Deployment
metadata:
? name: nginx-deployment
spec:
? selector:
? ? matchLabels:
? ? ? app: nginx
? replicas: 2
? template:
? ? metadata:
? ? ? labels:
? ? ? ? app: nginx
? ? spec:
? ? ? containers:
? ? ? - name: nginx
? ? ? ? image: nginx:1.8
? ? ? ? ports:
? ? ? ? - containerPort: 80
? ? ? ? volumeMounts:
? ? ? ? - mountPath: "/usr/share/nginx/html"
? ? ? ? ? name: nginx-vol
? ? ? volumes:
? ? ? - name: nginx-vol
? ? ? ? emptyDir: {}
總體分為兩部分:metadata存放元數(shù)據(jù);spec存放對(duì)象定義和功能的描述
apiVersion: apps/v1 --- 表示這是一個(gè)api對(duì)象,這里是Deployment api對(duì)象管理Pod api對(duì)象??刂破髂J?/p>
metadata --- 元數(shù)據(jù),api對(duì)象的標(biāo)識(shí),包含name, Annotations, labels等, labels用來(lái)給spec.selector.matchLabels過(guò)濾
kind: Deployment --- 類(lèi)型是Deployment
spec.replicas --- Pod副本數(shù)是2
spec.template --- Pod長(zhǎng)什么樣
spec.containers.image --- Pod的鏡像
volume:emptyDir 不顯示聲明宿主機(jī)目錄;對(duì)應(yīng)的有hostPath,顯示聲明
spec.volumeMounts 要掛載哪個(gè)volume
3. k8s容器編排基礎(chǔ)
3.1 pod
是k8s里最小調(diào)度單位,可看做一個(gè)進(jìn)程組或者像虛擬機(jī),容器則是進(jìn)程,如果多個(gè)進(jìn)程(容器)因?yàn)闀?huì)有直接的文件交換/本地通信/頻繁調(diào)用/共享資源必須放在一起部署
本質(zhì)上Pod是邏輯概念,他們只是一組共享了同一個(gè) Network Namespace,并且可以聲明共享同一個(gè) Volume的容器
Pod中,會(huì)有一個(gè)infra容器被第一個(gè)創(chuàng)建,他很小用的是k8s.gcr.io/pause鏡像,其他的容器通過(guò)join network ns的方式,與infra關(guān)聯(lián),作用是讓容器們是平等關(guān)系。
三個(gè)例子幫助理解pod
例子一:考慮一個(gè)war包和web服務(wù)器的關(guān)系
方式1. 把WAR包和web服務(wù)器打進(jìn)一個(gè)鏡像
方式2. 只把web服務(wù)器打成鏡像,掛載一個(gè)volume保存war包
POD方式:把war包和web服務(wù)器分別做成鏡像,然后作為同一個(gè)Pod,volume被兩個(gè)容器共享。是sidecar的方式,意識(shí)是啟動(dòng)一個(gè)輔助容器,完成主容器之外的工作
例子二,容器日志收集
主容器將日志輸出到/var/log,volume掛載
sidecar容器同樣的volume掛載,只做一件事,把日志拿出來(lái)處理
例子三,sidercar和主容器共享network ns,所以可以用sidecar來(lái)管理網(wǎng)絡(luò),不用影響主容器
3.1.1 pod和容器
pod實(shí)際上是對(duì)容器的進(jìn)一步抽象和封裝
如何判斷哪些屬性是屬于pod哪些是屬于容器的呢?
原則:凡是調(diào)度、網(wǎng)絡(luò)、存儲(chǔ),以及安全相關(guān)的屬性,跟容器的namespace相關(guān)的屬性 ,共享宿主機(jī)的ns屬性,這些都是 Pod 級(jí)別的。他們都是描述機(jī)器的
一些pod屬性:
NodeSelector將POD與node綁定
NodeName一旦賦值,會(huì)被k8s認(rèn)為已經(jīng)調(diào)度過(guò)
HostAliases定義pod里的hosts文件
一些容器屬性:
ImagePullPolicy(always,Never 或者 IfNotPresentAlways每次都拉取鏡像
LifecyclepostStart,preStop 容器啟動(dòng)/退出時(shí)做的事
3.1.2 Pod聲明周期
Pending這個(gè)狀態(tài)意味著,Pod 的 YAML 文件已經(jīng)提交給了 Kubernetes,API 對(duì)象已經(jīng)被創(chuàng)建并保存在 Etcd 當(dāng)中。但是,這個(gè) Pod 里有些容器因?yàn)槟撤N原因而不能被順利創(chuàng)建。比如,調(diào)度不成功。
Running這個(gè)狀態(tài)下,Pod 已經(jīng)調(diào)度成功,跟一個(gè)具體的節(jié)點(diǎn)綁定。它包含的容器都已經(jīng)創(chuàng)建成功,并且至少有一個(gè)正在運(yùn)行中。
Succeeded這個(gè)狀態(tài)意味著,Pod 里的所有容器都正常運(yùn)行完畢,并且已經(jīng)退出了。這種情況在運(yùn)行一次性任務(wù)時(shí)最為常見(jiàn)。
Failed這個(gè)狀態(tài)下,Pod 里至少有一個(gè)容器以不正常的狀態(tài)(非 0 的返回碼)退出。這個(gè)狀態(tài)的出現(xiàn),意味著你得想辦法 Debug 這個(gè)容器的應(yīng)用,比如查看 Pod 的 Events 和日志。
Unknown這是一個(gè)異常狀態(tài),意味著 Pod 的狀態(tài)不能持續(xù)地被 kubelet 匯報(bào)給 kube-apiserver,這很有可能是主從節(jié)點(diǎn)(Master 和 Kubelet)間的通信出現(xiàn)了問(wèn)題。
3.1.3 Project Volume
Project Volume存在的意義不是為了存放容器里的數(shù)據(jù),也不是用來(lái)進(jìn)行容器和宿主機(jī)之間的數(shù)據(jù)交換。這些特殊 Volume 的作用,是為容器提供預(yù)先定義好的數(shù)據(jù)。所以,從容器的角度來(lái)看,這些 Volume 里的信息就是仿佛是被 Kubernetes“投射”(Project)進(jìn)入容器當(dāng)中的。
相比環(huán)境變量重要的優(yōu)點(diǎn):可以被自動(dòng)更新
有以下4種:
1. Secret;需要加密的,生產(chǎn)環(huán)境使用加密插件,例如數(shù)據(jù)庫(kù)連接
2. ConfigMap;不需要加密的配置信息,例如普通配置文件
3. Downward API;讓 Pod 里的容器能夠直接獲取到這個(gè) Pod API 對(duì)象本身的靜態(tài)信息,例如打印pod信息到日志
4. ServiceAccountToken訪問(wèn)api的授權(quán),默認(rèn)會(huì)有默認(rèn)的volume
3.1.4 容器健康檢查和恢復(fù)
這個(gè)探針通過(guò)靜態(tài)文件和http url兩種方式:
1. cat /tmp/healthy判斷容器健康,返回0就正常
2. 配置一個(gè)url
initialDelaySeconds: 5 pod啟動(dòng)5秒后執(zhí)行
pod狀態(tài)不是running會(huì)重新創(chuàng)建,在同個(gè)node,不想同node用deployment,合理設(shè)置restartPolicy
還有個(gè)readinessProbe 的字段
readinessProbe 檢查結(jié)果的成功與否,決定的這個(gè) Pod 是不是能被通過(guò) Service 的方式訪問(wèn)到
關(guān)于pod和容器的狀態(tài),兩個(gè)原理:
1. 只要 Pod 的 restartPolicy 指定的策略允許重啟異常的容器(比如:Always),那么這個(gè) Pod 就會(huì)保持 Running 狀態(tài),并進(jìn)行容器重啟。否則,2. Pod 就會(huì)進(jìn)入 Failed 狀態(tài) 。對(duì)于包含多個(gè)容器的 Pod,只有它里面所有的容器都進(jìn)入異常狀態(tài)后,Pod 才會(huì)進(jìn)入 Failed 狀態(tài)。在此之前,Pod 都是 Running 狀態(tài)。
示例:
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: test-liveness-exec
spec:
containers:
- name: liveness
image: busybox
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
3.2 控制器Deployment
其他控制器:
$ cd kubernetes/pkg/controller/
$ ls -d */? ? ? ? ? ? ?
deployment/? ? ? ? ? ? job/? ? ? ? ? ? ? ? ? ? podautoscaler/? ? ? ? ?
cloud/? ? ? ? ? ? ? ? ? disruption/? ? ? ? ? ? namespace/? ? ? ? ? ? ?
replicaset/? ? ? ? ? ? serviceaccount/? ? ? ? volume/
cronjob/? ? ? ? ? ? ? ? garbagecollector/? ? ? nodelifecycle/? ? ? ? ? replication/? ? ? ? ? ? statefulset/? ? ? ? ? ? daemon/
...
控制器們都遵循 Kubernetes 項(xiàng)目中的一個(gè)通用編排模式,即:控制循環(huán)(control loop)
意思是會(huì)對(duì)比實(shí)際狀態(tài)和期望狀態(tài),并且循環(huán)的調(diào)整直到達(dá)到期望狀態(tài)。
deployment操縱是replicaSet 而不是pod
deployment創(chuàng)建會(huì)同時(shí)創(chuàng)建rs,rs名字里有一個(gè)hash字符串,被作為受它管理的pod的標(biāo)簽,不與其他pod混淆
deployment的狀態(tài):
DESIRED用戶期望的
CURRENT當(dāng)前處于running狀態(tài)的pod
UP-TO-DATE(deployment有而rs沒(méi)有)當(dāng)前處于最新版本的POD,所謂最新版本指的是 Pod 的 Spec 部分與 Deployment 里 Pod 模板里定義的完全一致;
AVAILABLE當(dāng)前可用的,即既是Running狀態(tài),又是最新版本,并且處于Ready(健康檢查正確)的個(gè)數(shù)
滾動(dòng)更新的實(shí)現(xiàn):把原rs里的副本一個(gè)個(gè)減少,把新rs里的副本一個(gè)個(gè)增加
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
...
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
maxSurge 指定的是除了 DESIRED 數(shù)量之外,在一次“滾動(dòng)”中,Deployment 控制器還可以創(chuàng)建多少個(gè)新 Pod;而 maxUnavailable 指的是,在一次“滾動(dòng)”中,Deployment 控制器可以刪除多少個(gè)舊 Pod。