1 概述
Pod是K8S系统中可以创建和管理的最小单元,是资源对象模型中由用户创建或部署的最小资源对象模型
有许多组件围绕Pod进行扩展和支持,比如控制器对象是用来管控Pod对象的,Service或者Ingress资源对象是用来暴露Pod引用对象的,PersistentVolume资源对象是用来为Pod提供存储等。
1.1 Pod结构
Pod是多进程设计,一个Pod里面包含多个容器,而一个容器里面运行一个应用程序。
每个Pod都有一个特殊的被称为 “根容器”的Pause容器。Pause容器对应的镜像属于Kubernetes平台的一部分,为其他的业务容器作支撑。一般把业务相关联的容器放到一个pod里,从而方便相关容器之间网络互通和文件共享。
1.2 实现机制
Pod实现主要依赖于共享网络和共享存储两大机制
- 共享网络:docker创建的容器由于namespace和group而相互隔离的,在创建业务容器时会注册到
pause容器
中从而共享其 ip地址,mac地址,port 等信息,这样便处于同一个网络中实现网络的共享。 - 共享存储:如下所示,每个容器会挂载到公共的
数据卷Volume
上,然后其数据都持久化存储到其中,当一个容器挂掉后,新的容器也能从Volume读取到之前的数据
apiversion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
-name: write
image: centos
command: ["bash", "-u","for i in {1..100};do echo $i » /data/hello;sleep 1;done"]
# 挂载数据卷
volumeMounts:
-name: data
mountPath: /data
-name: read
image: centos
command: [“bash",”-c","tail -f /data/hello"]
# 挂载数据卷
volumeMounts:
-name: data
mountPath: /data
# 定义数据卷
volumes:
-name: data
emptyDir: {}
2 Pod机制
2.1 镜像拉取策略
Pod的拉取策略主要分为了以下几种
- IfNotPresent:默认值,镜像在宿主机上不存在才拉取
- Always:每次创建Pod都会重新拉取一次镜像
- Never:Pod永远不会主动拉取这个镜像
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
-name: nginx
image: nginx:1.14
# 拉取策略
imagePullPolicy: Always
2.2 Pod资源限制
Pod在进行调度时,可以在调度器对资源的分配进行设置。例如限制使用的资源是 2C4G,那么在调度到对应的node节点时,只会占用对应的资源,对于不满足资源的节点则会跳过。
有两种资源配置的方式:
- request:表示调度所需最少的资源
- limits:表示最多允许使用的资源
apiVersion: v1
kind: Pod
metadata:
name: frontend
spec:
containers:
- name: db
image: mysql
env:
- name: MYSQL__ROOT_PASSWORD
value: "password"
resources:
# 资源限制
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
2.3 Pod重启机制
当Pod中的容器出现问题时就会触发重启机制,重启策略主要分为以下三种
- Always:当容器终止退出后,总是重启容器,默认策略 【nginx等,需要不断提供服务】
- OnFailure:当容器异常退出(退出状态码非0)时,才重启容器。
- Never:当容器终止退出,从不重启容器
apiVersion: v1
kind: Pod
metadata:
name: dns-test
spec:
containers:
- name: busybox
image: busybox:1.28
args:
- /bin/sh
- -c
- sleep 33000
# 重启策略
restartPolicy: Never
2.4 Pod健康检查
通过容器检查来判断服务是否可用,共有两种检查方式:存活检查livenessProbe,如果检查失败,将杀死容器,根据Pod的restartPolicy来操作;就绪检查readinessProbe,如果检查失败,Kubernetes会把Pod从Service endpoints中剔除
Probe支持以下三种检查方式
- http Get:发送HTTP请求,返回200 - 400 范围状态码为成功
- exec:执行Shell命令返回状态码是0为成功
- tcpSocket:发起TCP Socket建立成功
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-exec
spec:
containers:
- name: liveness
image: busybox
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30;
# 通过exec来执行存活检查
livenessProbe:
exec:
command:
-cat
-/tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
3 调度策略
创建Pod流程如下:
- 首先创建一个pod,然后创建一个API Server 和 Etcd,把创建出来的信息存储在etcd中
- 然后创建 Scheduler,监控API Server是否有新的Pod,如果有的话,会通过调度算法把pod调度具体node上
- 在node节点,会通过
kubelet -- apiserver
读取etcd 拿到分配在当前node节点pod信息,然后通过docker创建容器
影响Pod调度的属性
在Pod调度时会有多个条件影响调度结果。
首先调度器会考虑Pod的资源限制,根据request找到满足条件的node节点进行调度
3.1 节点选择器NodeSelector
调度器会根据节点的标签将任务调度到符合条件的节点上,例如下面将任务调度到标签为dev的节点上
apiVersion: v1
kind: Pod
metadata:
name: pod-example
spec:
# 根据节点选择器标签进行调度
nodeSelector:
env role: dev
containers:
-name: nginx
image: nginx:1.15
可以通过以下命令为节点新增标签,然后节点选择器就会进行调度了
kubectl label node node1 env_role=prod
3.2 节点亲和性NodeAffinity
节点亲和性和之前nodeSelector 基本一样的,根据节约束条件来决定Pod调度到哪些节点上
- 硬亲和性:约束条件必须满足,不满足则不分配
- 软亲和性:尝试满足,不保证
apiVersion: v1
kind: Pod
metadata:
name: with-node-affinity
spec:
affinity:
nodeAffinitv:
# 硬亲和性
requiredDuringSchedulinglgnoredDuringExecution:
nodeSelectorTerms:
- matuhExpEessions:
- key: env sle
operator: In
values:
- dev
- test
# 软亲和性
preferredDuringSchedulinglgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: group
operator: In
values:
- otherprod
支持常用操作符:in、NotIn、Exists、Gt、Lt、DoesNotExists
反亲和性:就是和亲和性刚刚相反,如 NotIn、DoesNotExists等
3.3 污点Taint
通过Taint 将节点添加污点,从而使本节点不做普通分配调度。nodeSelector 和 NodeAffinity,都是Pod的属性,而污点是节点的属性。
可以通过污点
- 专用节点【限制ip】
- 配置特定硬件的节点【固态硬盘】
- 基于Taint驱逐【在node1不放,在node2放】
通过如下命令查看污点情况
kubectl describe node k8smaster | grep Taint
污点值有三个
- NoSchedule:一定不被调度
- PreferNoSchedule:尽量不被调度【也有被调度的几率】
- NoExecute:不会调度,并且还会驱逐Node已有Pod
通过如下命令为节点添加污点
kubectl taint node [node] key=value:污点的三个值
举例:
kubectl taint node k8snode1 env_role=yes:NoSchedule
# 删除污点
kubectl taint node k8snode1 env_role:NoSchedule-