一 . Pod概述

Pod是K8S系统中可以创建和管理的最小单元,是资源对象模型中由用户创建或部署的最小资源对象模型,也是在K8S上运行容器化应用的资源对象,其它的资源对象都是用来支撑或者扩展Pod对象功能的

比如控制器对象是用来管控Pod对象的, Service或者Ingress资源对象是用来暴露Pod引用对象的, PersistentVolume资源对象是用来为Pod提供存储等等, K8S不会直接处理容器,而是Pod,Pod是由一个或多个container组成。

  • tip: Pod 就是最小并且最简单的 Kubernetes 对象!

    Pod是Kubernetes的最重要概念,每一个Pod都有一个特殊的被称为 “根容器”的Pause容器。Pause容器对应的镜像属于Kubernetes平台的一部分,除了Pause容器,每个Pod还包含一个或多个紧密相关的用户业务容器。

Kubernetes核心技术Pod - 图1

1.1 Pod基本概念

  • 最小部署的单元
  • Pod里面是由一个或多个容器组成【一组容器的集合】
  • 一个pod中的容器是共享网络命名空间
  • Pod是短暂的
  • 每个Pod包含一个或多个紧密相关的用户业务容器

    1.2 Pod存在的意义

    • 创建容器使用docker,一个docker对应一个容器,一个容器运行一个应用进程
    • Pod是多进程设计,运用多个应用程序
    • 一个Pod里面有多个容器,而一个容器里面运行一个应用程序
  • [x] tip:绕来绕去,意思就是pod时多个容器的集合,而docker只能运行一个容器!

Kubernetes核心技术Pod - 图2

  • Pod的存在是为了亲密性应用

    • 两个应用之间进行交互
    • 网络之间的调用【通过127.0.0.1 或 socket】
    • 两个应用之间需要频繁调用

      1. Pod是在K8S集群中运行部署应用或服务的最小单元,它是可以支持多容器的。Pod的设计理念是支持多个容器在一个Pod中共享网络地址和文件系统,可以通过进程间通信和文件共享这种简单高效的方式组合完成服务。同时Pod对多容器的支持是K8S中最基础的设计理念。在生产环境中,通常是由不同的团队各自开发构建自己的容器镜像,在部署的时候组合成一个微服务对外提供服务。

      Pod是K8S集群中所有业务类型的基础,可以把Pod看作运行在K8S集群上的小机器人,不同类型的业务就需要不同类型的小机器人去执行。目前K8S的业务主要可以分为以下几种

  • 长期伺服型:long-running

  • 批处理型:batch
  • 节点后台支撑型:node-daemon
  • 有状态应用型:stateful application

上述的几种类型,分别对应的小机器人控制器为:Deployment、Job、DaemonSet 和 StatefulSet (后面将介绍控制器)

二 . Pod实现机制

主要有以下两大机制

  • 共享网络
  • 共享存储

    2.1 共享网络

    容器本身之间相互隔离的,一般是通过 namespacegroup 进行隔离,那么Pod里面的容器如何实现通信?
  1. 首先需要满足前提条件,也就是容器都在同一个namespace之间
  2. 关于Pod实现原理,首先会在Pod会创建一个根容器: pause容器,然后我们在创建业务容器 【nginx,redis 等】,在我们创建业务容器的时候,会把它添加到 info容器
  3. 而在 info容器 中会独立出 ip地址,mac地址,port 等信息,然后实现网络的共享

完整步骤如下

  • 通过 Pause 容器,把其它业务容器加入到Pause容器里,让所有业务容器在同一个名称空间中,可以实现网络共享

Kubernetes核心技术Pod - 图3
简单来说,也可以画成这样!注意是在同一个namespace中!共用IP地址等!

2.2 共享存储

Pod持久化数据,专门存储到某个地方中,和上面那张图可以结合理解!
Kubernetes核心技术Pod - 图4
使用 Volumn数据卷进行共享存储,案例如下所示
Kubernetes核心技术Pod - 图5

三 . Pod镜像拉取策略

我们以具体实例来说,拉取策略就是 imagePullPolicy
Kubernetes核心技术Pod - 图6
拉取策略主要分为了以下几种

  • IfNotPresent:默认值,镜像在宿主机上不存在才拉取
  • Always:每次创建Pod都会重新拉取一次镜像
  • Never:Pod永远不会主动拉取这个镜像

    四 . Pod资源限制

    也就是我们Pod在进行调度的时候,可以对调度的资源进行限制,例如我们限制 Pod调度是使用的资源是 2C4G,那么在调度对应的node节点时,只会占用对应的资源,对于不满足资源的节点,将不会进行调度
    Kubernetes核心技术Pod - 图7

    示例

    我们在下面的地方进行资源的限制
    Kubernetes核心技术Pod - 图8
    这里分了两个部分

  • request:表示调度所需的资源

  • limits:表示最大所占用的资源

    五 . Pod重启机制

    因为Pod中包含了很多个容器,假设某个容器出现问题了,那么就会触发Pod重启机制
    Kubernetes核心技术Pod - 图9
    重启策略主要分为以下三种

  • Always:当容器终止退出后,总是重启容器,默认策略 【nginx等,需要不断提供服务】

  • OnFailure:当容器异常退出(退出状态码非0)时,才重启容器。
  • Never:当容器终止退出,从不重启容器 【批量任务】

    六 . Pod健康检查

    通过容器检查,原来我们使用下面的命令来检查

    1. kubectl get pod

    但是有的时候,程序可能出现了 Java 堆内存溢出,程序还在运行,但是不能对外提供服务了,这个时候就不能通过 容器检查来判断服务是否可用了
    这个时候就可以使用应用层面的检查

    1. # 存活检查,如果检查失败,将杀死容器,根据Pod的restartPolicy【重启策略】来操作
    2. livenessProbe
    3. # 就绪检查,如果检查失败,Kubernetes会把Pod从Service endpoints中剔除
    4. readinessProbe

    Kubernetes核心技术Pod - 图10
    Probe支持以下三种检查方式

  • http Get:发送HTTP请求,返回200 - 400 范围状态码为成功

  • exec:执行Shell命令返回状态码是0为成功
  • tcpSocket:发起TCP Socket建立成功

    七 . Pod调度策略

    7.1 创建Pod流程

  • 首先创建一个pod,然后创建一个API Server 和 Etcd【把创建出来的信息存储在etcd中】

  • 然后创建 Scheduler,监控API Server是否有新的Pod,如果有的话,会通过调度算法,把pod调度某个node上
  • 在node节点,会通过 kubelet -- apiserver 读取etcd 拿到分配在当前node节点上的pod,然后通过docker创建容器

Kubernetes核心技术Pod - 图11

7.2 影响Pod调度的属性

Pod资源限制对Pod的调度会有影响

7.2.1 根据request找到足够node节点进行调度

Kubernetes核心技术Pod - 图12

7.2.2 节点选择器标签影响Pod调度

Kubernetes核心技术Pod - 图13
关于节点选择器,其实就是有两个环境,然后环境之间所用的资源配置不同
Kubernetes核心技术Pod - 图14
我们可以通过以下命令,给我们的节点新增标签,然后节点选择器就会进行调度了

  1. kubectl label node node1 env_role=prod

7.2.3 节点亲和性

节点亲和性 nodeAffinity 和 之前nodeSelector 基本一样的,根据节点上标签约束来决定Pod调度到哪些节点上

  • 硬亲和性:约束条件必须满足
  • 软亲和性:尝试满足,不保证

Kubernetes核心技术Pod - 图15
支持常用操作符:in、NotIn、Exists、Gt、Lt、DoesNotExists
反亲和性:就是和亲和性刚刚相反,如 NotIn、DoesNotExists等

八 . 污点和污点容忍

8.1 概述

nodeSelector 和 NodeAffinity,都是Pod调度到某些节点上,属于Pod的属性,是在调度的时候实现的。
Taint 污点:节点不做普通分配调度,是节点属性

8.2 场景

  • 专用节点【限制ip】
  • 配置特定硬件的节点【固态硬盘】
  • 基于Taint驱逐【在node1不放,在node2放】

    8.3 查看污点情况

    1. kubectl describe node k8smaster | grep Taint

    Kubernetes核心技术Pod - 图16
    污点值有三个

  • NoSchedule:一定不被调度

  • PreferNoSchedule:尽量不被调度【也有被调度的几率】
  • NoExecute:不会调度,并且还会驱逐Node已有Pod

    8.4 未节点添加污点

    1. kubectl taint node [node] key=value:污点的三个值
    举例:
    1. kubectl taint node k8snode1 env_role=yes:NoSchedule

    8.5 删除污点

    1. kubectl taint node k8snode1 env_role:NoSchedule-
    Kubernetes核心技术Pod - 图17

    8.6 演示

    我们现在创建多个Pod,查看最后分配到Node上的情况
    首先我们创建一个 nginx 的pod
    1. kubectl create deployment web --image=nginx
    然后使用命令查看
    1. kubectl get pods -o wide
    Kubernetes核心技术Pod - 图18
    我们可以非常明显的看到,这个Pod已经被分配到 k8snode1 节点上了
    下面我们把pod复制5份,在查看情况pod情况
    1. kubectl scale deployment web --replicas=5
    我们可以发现,因为master节点存在污点的情况,所以节点都被分配到了 node1 和 node2节点上
    Kubernetes核心技术Pod - 图19
    我们可以使用下面命令,把刚刚我们创建的pod都删除
    1. kubectl delete deployment web
    现在给了更好的演示污点的用法,我们现在给 node1节点打上污点
    1. kubectl taint node k8snode1 env_role=yes:NoSchedule
    然后我们查看污点是否成功添加
    1. kubectl describe node k8snode1 | grep Taint
    Kubernetes核心技术Pod - 图20
    然后我们在创建一个 pod
    1. # 创建nginx pod
    2. kubectl create deployment web --image=nginx
    3. # 复制五次
    4. kubectl scale deployment web --replicas=5
    然后我们在进行查看
    1. kubectl get pods -o wide
    我们能够看到现在所有的pod都被分配到了 k8snode2上,因为刚刚我们给node1节点设置了污点
    Kubernetes核心技术Pod - 图21
    最后我们可以删除刚刚添加的污点
    1. kubectl taint node k8snode1 env_role:NoSchedule-

    8.7 污点容忍

    污点容忍就是某个节点可能被调度,也可能不被调度
    Kubernetes核心技术Pod - 图22

九 . Pod的多种类型

Pod 存在多种不同的创建类型来满足不一样的用途

ReplicationController

ReplicationController 用来确保容器应用的副本数量始终保持在用户定义的副本数,即如果有容器异常退出,会自动创建新的 Pod 来代替,而如果异常多出现的容器会自动回收。

ReplicaSet

在新版本(相对而言的较优方式)的 Kubernetes 中建议使用 ReplicaSet 来取代 ReplicationController 来管理 Pod。虽然 ReplicaSet 和 ReplicationController 并没有本质上的不同,只是名字不一样而已,唯一的区别就是 ReplicaSet 支持集合式的 selector,可供标签筛选。
虽然 ReplicaSet 可以独立使用,但一般还是建议使用 Deployment 来自动管理 ReplicaSet 创建的 Pod,这样就无需担心跟其他机制的不兼容问题。比如 ReplicaSet 自身并不支持滚动更新(rolling-update),但是使用 Deployment 来部署就原生支持。

Deployment

Deployment 为 Pod 和 ReplicaSet 提供了一个声明式定义方法,用来替代以前使用 ReplicationController 来方便且便捷的管理应用。主要的应用场景,包括:滚动升级和回滚应用、扩容和缩容、暂停和继续。

HPA

HPA 仅仅适用于 Deployment 和 ReplicaSet,在 V1 版本中仅支持根据 Pod 的 CPU 利用率扩缩容,在新版本中,支持根据内存和用户自定义的 metric 动态扩缩容。

StatefulSet

StatefulSet 是为了解决有状态服务的问题,相对于 Deployment 和 ReplicaSet 而已。其主要的使用场景,包括:稳定的持久化存储、稳定的网络标识、有序部署、有序收缩。

DaemonSet

DaemonSet 确保全部或者一些 Node 上面运行一个 Pod 副本。当有 Node 加入集群的时候,也会为它们新加一个 Pod。当有 Node 从集群中移除的时候,这些 Pod 也会被回收。删除 DaemonSet 将会删除它所创建的所有 Pod。
使用 DaemonSet 的典型场景就是,在每个节点运行日志收集、运行监控系统、运行集群存储等服务,只要新加进来的节点都需要运行该服务。

Job

Job 负责批处理任务,仅执行一次的任务,它保证批处理任务的一个或者多个 Pod 成功结束,才会返回成功。

Cront Job

Cront Job 管理是基于时间的 Job,即在给定时间点只运行一次,且周期行的在给定时间点运行特定任务。