Kubernetes 核心概念之1 pod
官方文档:https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/
Pod 概述
Pod 是 Kubernetes 系统中可以创建和管理的最小单元,是资源对象模型中由用户创建或部署的最小资源对象模型,也是在 Kubernetes 上运行容器化应用的资源对象,其它的资源对象都是用来支撑或者扩展 Pod 对象功能的,比如控制器对象 RC 是用来管控 Pod 对象的,Service 或者 Ingress 资源对象是用来暴露 Pod 引用对象的,PersistentVolume 资源对象是用来为 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 的设计理念是支持多个容器在一个 Pod 中共享网络地址和文件系统,可以通过进程间通信和文件共享这种简单高效的方式组合完成服务。
同时 Pod 对多容器的支持是 K8S 中最基础的设计理念。在生产环境中,通常是由不同的团队各自开发构建自己的容器镜像,在部署的时候组合成一个微服务对外提供服务。
Pod 是 K8S 集群中所有业务类型的基础,可以把 Pod 看作运行在 K8S 集群上的小机器人,不同类型的业务就需要不同类型的小机器人去执行。目前 K8S 的业务主要可以分为以下几种
- 长期伺服型:long-running
- 批处理型:batch
- 节点后台支撑型:node-daemon
- 有状态应用型:stateful application
上述的几种类型,分别对应的小机器人控制器为:Deployment、Job、DaemonSet 和 StatefulSet (后面将介绍控制器)
Pod 实现机制
Pod 主要有以下两大机制
- 共享网络
- 共享存储
共享网络
容器本身之间相互隔离的,一般是通过 NameSpace 和 Cgroups 进行隔离,那么 Pod 里面的容器如何实现通信?
- 首先需要满足前提条件,也就是容器都在同一个 namespace 之间。
Pod 实现原理:首先会在 Pod 会创建一个根容器 pause 容器
,然后我们在创建业务容器 nginx,redis 等,在我们创建业务容器的时候,会把它添加到 pause 容器
中,而在 pause 容器
中会独立出 ip地址,mac地址,port 等信息,然后让所有容器共享。
共享存储
Pod 持久化数据,专门存储到某个地方中
使用 Volumn 数据卷进行共享存储,案例如下所示
Pod 的定义
在一个 yaml 文件中,Pod 是这样定义的(完整):
1 |
|
Pod 分类
Pod 分为 普通Pod
和 静态Pod
两类。
普通 Pod 一旦被创建,就会放入 etcd 中存储,随后会被 k8s Master 调度到某个具体的 node 上并进行绑定,随后该 Pod 所对应的 Node 上的 kubelet 进程实例化成一组相关的 Docker 容器并启动。在默认情况下,当 Pod 里某个容器停止时,K8s 会自动检测到这个问题并且重新启动这个 Pod 里的所有容器,如果 Pod 所在的 node 宕机,则会将这个 node 上的所有 Pod 重新调度到其它节点。
静态 Pod 是由 kubelet 进行管理的仅存在于特定 node 上的 Pod,它们不能通过 API Server 进行管理,无法与 ReplicationController、Deployment 或 DaemonSet 进行关联,并且 kubelet 也无法对它们进行健康检查。
Pod 生命周期和重启策略
Pod 的几个状态(生命周期)
Pod 生命周期包含 Pending
、Running
、Compeleted
、Failed
、Unknown
五个状态。
状态 | 说明 |
---|---|
Pending | API Server 已经创建了该 Pod,但 Pod 中的一个或多个容器的镜像还没有创建,包括镜像下载过程 |
Running | Pod 内所有容器已创建,且至少一个容器处于运行、正在启动或正在重启状态 |
Compeleted | Pod 内所有容器均成功执行退出,且不会再重启 |
Failed | Pod 内所有容器均已退出,但至少—个容器退出失败 |
Unknown | 由于某种原因无法获取 Pod 状态,例如网络通信不畅等 |
Pod 镜像拉取策略 imagePullPolicy
拉取策略主要分为了以下几种
IfNotPresent
:默认值,镜像在宿主机上不存在才拉取。Always
:每次创建 Pod 都会重新拉取一次镜像。Never
:Pod 永远不会主动拉取这个镜像。
示例
1 |
|
Pod 重启机制 restartPolicy
因为 Pod 中包含了很多个容器,假设某个容器出现问题了,那么就会触发 Pod 重启机制。
重启策略主要分为以下三种
Always
:当容器终止退出后,总是重启容器,默认策略 【nginx等,需要不断提供服务】OnFailure
:当容器异常退出(退出状态码非0)时,才重启容器。Never
:当容器终止退出,从不重启容器 【批量任务】
示例
1 |
|
Pod 健康检查 livenessProbe
通过容器检查,原来我们使用下面的命令来检查
1 |
|
但是有的时候,程序可能出现了 Java 堆内存溢出,程序还在运行,但是不能对外提供服务了,这个时候就不能通过容器检查来判断服务是否可用了。
这个时候就可以使用应用层面的检查
livenessProbe
存活检查。如果检查失败,将杀死容器,根据 Pod 的 restartPolicy【重启策略】来操作readinessProbe
就绪检查。如果检查失败,Kubernetes 会把 Pod 从 Service endpoints 中剔除
Probe 支持以下三种检查方式:
- http Get:发送 HTTP 请求,返回 200-400 范围状态码为成功。
- exec:执行 Shell 命令返回状态码是 0 为成功。
- tcpSocket:发起 TCP Socket 建立成功。
示例
1 |
|
Pod 资源限制 resources
也就是我们 Pod 在进行调度的时候,可以对调度的资源进行限制,例如我们限制 Pod 调度是使用的资源是 2C4G,那么在调度对应的 node 节点时,只会占用对应的资源,对于不满足资源的节点,将不会进行调度。
示例
1 |
|
Pod 节点选择器 nodeSelector
1 |
|
节点选择器选择过程
我们可以通过以下命令,给我们的节点新增标签,然后节点选择器就会进行调度了
1 |
|
节点亲和性 nodeAffinity
节点亲和性 nodeAffinity 和之前 nodeSelector 基本一样的,根据节点上标签约束来决定 Pod 调度到哪些节点上
- 硬亲和性:约束条件必须满足
- 软亲和性:尝试满足,不保证
支持常用操作符:in、NotIn、Exists、Gt、Lt、DoesNotExists
反亲和性:就是和亲和性刚刚相反,如 NotIn、DoesNotExists等
示例
1 |
|
创建 Pod 流程
- 首先创建一个 pod,然后创建一个 API Server 和 etcd【把创建出来的信息存储在 etcd 中】。
- 然后创建 Scheduler,监控 API Server 是否有新的 Pod,如果有的话,会通过调度算法,把 pod 调度某个 node 上。
- 在 node 节点,会通过
kubelet --apiserver
读取 etcd 拿到分配在当前 node 节点上的 pod,然后通过 docker 创建容器。
污点和污点容忍 Taint
和 tolerations
污点 Taint
nodeSelector 和 NodeAffinity 都是 Pod 想要调度到某些节点上,属于 Pod 的属性,是在调度的时候实现的。
Taint 污点:节点不做普通分配调度,是节点属性,是 node 觉得是否将 Pod 调度到本节点。
场景
- 专用节点【限制ip】
- 配置特定硬件的节点【固态硬盘】
- 基于 Taint 驱逐【在 node1 不放,在 node2 放】
查看污点情况
1 |
|
污点值有三个
- NoSchedule:一定不被调度
- PreferNoSchedule:尽量不被调度【也有被调度的几率】
- NoExecute:不会调度,并且还会驱逐 Node 已有 Pod
节点添加污点语法
1 |
|
举例
1 |
|
删除污点
1 |
|
演示
我们现在创建多个Pod,查看最后分配到Node上的情况
首先我们创建一个 nginx 的pod
1
kubectl create deployment web --image=nginx
然后使用命令查看
1
kubectl get pods -o wide
我们可以非常明显的看到,这个 Pod 已经被分配到 k8snode1 节点上了
下面我们把 pod 复制5份,在查看情况pod情况
1
kubectl scale deployment web --replicas=5
我们可以发现,因为 master 节点存在污点的情况,所以节点都被分配到了 node1 和 node2 节点上
我们可以使用下面命令,把刚刚我们创建的 pod 都删除
1
kubectl delete deployment web
现在给了更好的演示污点的用法,我们现在给 node1 节点打上污点
1
kubectl taint node k8snode1 env_role=yes:NoSchedule
然后我们查看污点是否成功添加
1
kubectl describe node k8snode1 | grep Taint
然后我们在创建一个 pod
1
2
3
4# 创建nginx pod
kubectl create deployment web --image=nginx
# 复制五次
kubectl scale deployment web --replicas=5然后我们在进行查看
1
kubectl get pods -o wide
我们能够看到现在所有的 pod 都被分配到了 k8snode2上,因为刚刚我们给 node1 节点设置了污点
最后我们可以删除刚刚添加的污点
1
kubectl taint node k8snode1 env_role:NoSchedule-
污点容忍 tolerations
污点容忍就是某个节点可能被调度,也可能不被调度