kubernetes的核心技术--Pod
Pod概述
Pod是K8s系统中可以创建和管理的最小单元,是资源对象模型中由用户创建或者部署的最小资源对象模型,也是在K8s上运行容器化应用的资源对象,其他的资源对象都是用来支撑或者扩展Pod对象功能的,比如控制器对象是用来管控Pod对象的,Service或者Ingress资源对象是用来暴露Pod引用对象的,PV资源对象是用来为Pod提供存储等等,K8s不会直接处理容器,而是Pod,Pod是有一个或者多个container组成的。
Pod是Kubernetes的最重要概念,每个Pod都有一个特殊的被称为“根容器”的Pause容器。Pause容器对应的镜像属于Kubernetes平台的一部分,除了Pause容器,每个Pod还包含一个或者多个紧密相关的用户业务容器。
Pod基本概念
- 最小部署单元
- Pod是由一个或者多个容器组成(可以理解为一组容器的集合)
- 一个Pod的容器是共享网络命名空间
- Pod是断在的
- 每个Pod包含一个或多个紧密相关的用户业务容器
Pod存在的意义
- 创建容器使用docker,一个docker对应一个容器,一个容器运行一个应用进程
- Pod是多进程设计,运用多个应用程序,也就是一个Pod里面有多个容器,而一个容器里面运行一个应用程序
- Pod的存在是为了亲密性应用
- 两个应用之间进行交互
- 网络之间的调用(通过127.0.0.1或socket)
- 两个应用之间需要频繁调用
Pod是在K8s集群中运行部署应用或服务的最小单元,它是可以支持多容器的。Pod的设计理念是支持多个容器在Pod共享网络地址的文件系统,可以通过进程之间通信和文件共享这中简单高效的方式组合完成服务。同时Pod对多容器的支持是K8d中最基础的设计理念。在生产环境中,通常是由不同的团队各自开发构建自己的容器镜像,在部署的时候组成一个微服务对外提供服务。
Pod是K8s集群中所有业务类型的基础,可以吧Pod看作运行在K8s集群上的小机器人,不同类型的业务就需要不同类型的小机器人去执行。目前 K8s的业务最要可以分为以下几种:
- 长期伺服型:long-running
- 批处理型: batch
- 节点后台支撑型: node-daemon
- 有状态应用型:stateful application
上述几种类型,分别对应的控制器为:Deployment、Job、DaemonSet和StatefulSet
Pod实现机制
主要有一下两大机制
- 共享网络
- 共享存储
共享网络
同一个pod共享同一个网络命名空间,贡献同一个Linux协议栈。所以一般把互相调用频繁的应用放到同一个pod里。
容器本身是相互隔离的,一般是通过namesapce和group进行隔离,所以Pod里面的容器想要通信,首先需要满足前提条件,就是容器都在同一个namespace之间。
关于Pod实现原理,首先会在Pod创建一个根容器(pause容器),然后我们在创建业务容器(nginx、redis等),在我们创建业务容器的时候,会把它添加到info容器中。而info容器会独立出ip地址、mac地址、port等信息,然后实现网络的共享。
完整步骤:
- 通过pause容器,把其它业务容器加入到pause容器里,让所有的业务容器在同一个名称空间中,就可以实现网络共享
共享存储
Pod持久化数据,专门存储到某个地方
使用Volumn数据卷进行共享存储,案例如下
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: write
image: centos
command: ["bash","-c","for i in (1..100);do echo $i >> /data/hello;sleep 1s ;done]
volumeMounts:
- name: date
mountPath: /data
volumes:
- name: data
emptyDir: {
}
Pod镜像拉取策略
以具体实例来说,拉去策略就是imagePullPolicy
拉取策略主要分为以下几种:
- IfNotPresent:默认值,镜像在宿主机上不存在才拉取
- Always:每次创建Pod都会重新拉取一次镜像
- Never:Pod永远不会主动拉取这个镜像
Pod资源限制
也就是我们Pod在进行调度的时候,可以对调度的资源进行限制,例如我们限制Pod调度时使用的资源是2C4G,那么在调度对那个的node节点时,只会占用对应的资源,对于不满足资源的节点,将不会调度。
resource这里分为了两个部分:
- request:表示调度所需的i资源
- limits:表示最大所占用的资源 ## Pod重启机制
Pod重启机制
因为Pod中包含了很多个容器,假设某个容器出现问题,那么就会出发Pod重启机制restartPolicy
重启策略主要分为一下三种:
- Alwanys:当容器终止退出后,总是重启容器,默认策略(nginx等,需要不断提供服务)
- OnFailure:当容器异常退出(退出状态码非0)时,才重启容器
- Never:当容器终止退出,从不重启容器(批量任务)
Pod健康检查
通过容器检查,原来我们使用下面的命令来见检查
kubectl get pod
但是有时候,程序可能出现java堆内存溢出,程序还在运行,但是不能对外提供服务,这时候就不能通过容器检查来判断服务是否可用了
这时候就可以使用应用层面的检查
#存活探测,如果检查失败,将杀死容器,根据Pod的restartPolicy(重启策略)来操作
livenessProbe
#就绪探测,如果检查失败,Kubernetes会把Pod容Service endpoints中剔除
readinessProbe
Probe支持一下三种检查方式
- http Get:对指定端口和路径上的容器IP地址执行HTTP Get 请求。如果响应的状态码大于等于200且小于400,则诊断被认为时成功的
- TCPSocket:对指定端口上的容器的IP地址进行TCP检查。如果端口打开,则诊断被认为时成功的
- exec:在容器内执行命令,如果命令退出时返回码为0则任务诊断成功
每次探测都将获得以下三种结果之一:
成功:容器通过诊断
失败:容器未通过诊断
未知:诊断失败,因为不会采取任何行动
Pod调度策略
创建Pod流程
- 首先创建一个Pod,然后创建一个API Server和Etcd(把创建出来的信息存储在etcd)
- 然后创建Scheduler,监控API Server是否有新的Pod,如果有的话,会通过调度算法,把Pod调度到某个node节点上
- 在node节点,会通过 kubelet – apiserver 读取etcd拿到分配在当前node节点上的pod,然后通过docker创建容器
影响Pod调度的属性
Pod资源限制对Pod的调度会有影响
根据request找到足够node节点进行调度
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
scheduler会选择资源足够的节点创建pod
节点选择器标签
apiVersion: v1
kind: Pod
metadata:
name: pod-test
spec:
nodeSelector:
env_role: dev
containers:
- name: nginx
image: nginx:1.15
关于节点标签选择器,其实就是有两个环境,然后环境之间所用的资源配置不同
我们可以通过以下命令,给我们的节点新增标签,然后节点选择器就会进行调度了
kubectl label node node01 env_role=prod
亲和性
接待你亲和性nodeAffinity和之前nodeSelector基本一样,根据节点上标签约束来决定Pod调度到哪些节点上
- 硬亲和性:约束条件必须满足
- 软亲和性:尽量满足,不保证
支持常用操作符: in、NotIn、Exitsts、Gt、Lt、DoesNotExists
反亲和性: 和亲和性相反,如NotIn、DoesNotExitsts
污点和容忍
概述
nodeSelector和NodeAffinity,都是Prod调度到某些节点上,属于Pod的属性,实在调度的时候实现的。
Taint污点:节点不做普通分配调度,是节点属性。
场景
- 专用节点(限制ip)
- 配置特点硬件的节点(固态硬盘)
- 基于Taint驱逐(在node01不调度,在node02调度)
查看污点情况
kubuctl describe node k8s-node01 | grep Taint
污点值有三个
- NoScheduler:一定不被调度
- PreferNoScheduler:尽量不被调度(也有被调度的几率)
- NoExecute:不会被调度,并且还会驱逐Node已有的Pod
为节点添加污点
kubectl taint node [node] key=value:污点的三个值
举例:
kubectl taint node k8s-node01 env_role=test:NoSchedule
删除污点
kubectl taint node k8s-node01 env_role:NoSchedule-
污点容忍
tolerations,意思是设置了容忍的Pod将可以容忍污点的存在,可以将Pod调度到存在污点的Node上