Kubernetes编排原理

Kubernetes编排原理

为什么我们需要Pod

PodKubernetes项目中最小的API对象. 更专业的表述是: PodKubernetes项目的原子调度单位.

容器的”单进程模型”并不是指容器里只能运行”一个”进程, 而是指容器无法管理多个进程. 这是因为容器里PID=1的进程就是应用本身, 其他进程都是这个PID=1进程的子进程. 可是, 用户编写的应用并不像正常操作系统里的init进程或者systemd那样拥有进程管理的功能.

Kubernetes项目里, Pod的实现需要使用一个中间容器, 这个容器叫作Infra容器. 在这个Pod中, Infra容器永远是第一个被创建的容器, 用户定义的其他容器则通过Join Network Namespace的方式与Infra容器关联在一起.

Pod对象使用进阶

Kubernetes中有几种特殊的Volume, 它们存在的意义不是为了存放容器里的数据, 也不是用于容器和宿主机之间的数据交换, 而是为容器提供预先定义好的数据.

Secret

Secret的作用是帮你把Pod想要访问的加密数据存放在etcd中, 你就可以通过在Pod的容器里挂载Volume的方式访问这些Secret里保存的信息了.

像这样通过挂载方式进入容器里的Secret, 一旦其对应的etcd里的数据更新, 这些Volume里的文件内容也会更新. 其实, 这是kubelet组件在定时维护这些Volume.

需要注意的是, 这个更新可能会有一定的延时. 所以在编写应用程序时, 在发起数据库连接的代码处写好重试和超时的逻辑, 绝对是个好习惯.

ConfigMap

ConfigMapSecret类似, 区别在于ConfigMap保存的是无需加密的, 应用所需要的配置信息.

DownwardAPI

DownwardAPI的作用是让Pod里的容器能够直接获取这个PodAPI对象本身的信息.

不过, 需要注意的是, DownwardAPI能够获取的信息一定是Pod里的容器进程启动之前就能确定下来的信息. 如果你想要获得Pod容器运行后才会出现的信息, 比如容器进程的PID, 就肯定不能使用DownwardAPI了, 而应该考虑在Pod里定义一个sidecar容器.

ServiceAccountToken

Service Account对象的作用就是Kubernetes系统内置的一种”服务账户”, 它是Kubernetes进行权限分配的对象. 比如, Service Account A可以只被允许对Kubernetes进行GET操作, 而Service Account B可以有Kubernetes API的所有操作的权限.

像这样的Service Account的授权信息和文件, 实际上保存在它所绑定的一个特殊的Secret对象里. 这个特殊的Secret对象叫作ServiceAccountToken. 任何在Kubernetes集群上运行的应用, 都必须使用ServiceAccountToken里保存的授权信息(也就是token), 才可以合法访问API Server.

容器健康检查和恢复机制

Kubernetes中的重启, 实际上却是重新创建了容器. 这个功能就是Kubernetes里的Pod恢复机制, 也叫restartPolicy.

一定要强调的是, Pod的恢复过程永远发生在当前节点上, 而不会跑到别的节点上. 事实上, 一旦一个Pod与一个节点绑定, 除非这个绑定关系发生了变化pod.spec.node字段被修改, 否则它永远不会离开这个节点.

如果你想让Pod出现在其他的可用节点上, 就必须使用Deployment这样的”控制器”来管理Pod, 哪怕你只需要一个Pod副本.

如果你关心这个容器退出后的上下文环境, 比如容器退出后的日志, 文件和目录, 就需要将restartPolicy设置为Never. 这是因为一旦容器被自动重新创建, 这些内容就有可能丢失(被垃圾回收了).

只要PodrestartPolicy指定的策略允许重启异常的容器, 那么这个Pod就会保持Running状态并重启容器, 否则Pod会进入Failed状态.

对于包含多个容器的Pod, 只有其中所有的容器都进入异常状态后, Pod才会进入Failed状态.

PodPreset

PodPreset里定义的内容只会在Pod API对象被创建之前追加在这个对象上, 而不会影响任何Pod的控制器的定义. 比如, 现在提交的是一个nginx-deployment, 那么这个Deployment对象永远不会被PodPreset改变, 被修改的只是这个Deployment创建出来的所有Pod.

如果你定义了同时作用于一个Pod对象的多个PodPreset, 会发生什么呢?

实际上, Kubernetes项目会帮你合并这两个PodPreset要做的修改, 而如果它们要做的有冲突的话, 这些冲突字段就不会被修改.

谈谈”控制器”思想

Deployment定义的template字段, 在Kubernetes项目中有一个专属的名字, 叫作PodTemplate(Pod模版).

作业副本与水平扩展

如果你更新了DeploymentPod模版, 那么Deployment就需要遵循一种叫作滚动更新的方式, 来升级现有容器.

创建Deployment时建议指定--record参数, 因此创建回滚版本的时候执行的kubectl命令都会被记录下来, 否则通过kubectl rollout history命令查看历史版本时, CHANGE-CAUSE这一栏会是空.

深入理解StatefulSet(一): 拓扑状态

这种实例之间有不对等关系, 以及实例对外部是数据有依赖关系的应用, 就称为有状态应用.

StatefulSet的设计其实非常容易理解, 它把现实世界里的应用状态抽象为了两种情况.

拓扑状态

应用的多个实例之间不是完全对等的. 这些应用实例必须按照某种顺序启动, 比如应用的主节点A要先于从节点B启动. 而如果删除A和B两个Pod, 它们再次被创建出来时也必须严格按照这个顺序运行. 并且, 新创建出来的Pod必须和原来Pod的网络标识一样, 这丫原先的访问者才能使用同样的方法访问到这个新的Pod.

存储状态

应用的多个实际分别绑定了不同的存储数据. 对于这些应用实例来说, Pod A第一次读取到的数据和隔了10分钟之后再此读取到数据应该是同一份, 哪怕在此期间Pod A被创建过.

StatefulSet的核心功能, 就是通过某种方式记录这些状态, 然后在Pod被重新创建时, 能够为新的Pod恢复这些状态.

Service如何被访问的

第一种是以ServiceVIP(virtual IP, 虚拟IP)方式.

第二种是以ServiceDNS方式.

在第二种Service DNS的方式下, 具体又可以分为两种处理方法.

第一种处理方法是Normal Service.

第二种处理方法是Headless Service. Headless Servicecluster IP字段是的值是None, 即这个Service没有一个VIP作为”头”. 这个Service被创建后并不会被分配一个VIP, 而是会以DNS记录的方式暴露出它所代理的Pod.

通过这种方法, Kubernetes就成功地将Pod的拓扑状态(比如哪个节点先启动, 哪个节点后启动), 按照Pod的”名字+编号”的方式固定下来. 此外, Kubernetes还为每个Pod提供了一个固定且唯一的访问入口, 即这个Pod对应的DNS记录. 这些状态在StatefulSet的整个生命周期里都保持不变, 绝不会因为对应Pod的删除或者重新创建而失败.

DNS记录本身不会变, 但它解析到的PodIP地址并不是固定的. 这就意味着, 对于有状态应用实例的访问, 必须使用DNS记录或者hostname的方式, 而绝不应该直接访问这些PodIP地址.

深入理解StatefulSet(二): 存储状态

StatefulSet的控制器直接管理的是Pod. Kubernetes通过Headless Service为这些有编号的Pod, 在DNS服务器中生成带有相同编号的DNS编号. StatefulSet还为每一个Pod分配并创建了一个相同编号的PVC.

容器化守护进程: DaemonSet

跟其他编排对象不同, DaemonSet开始运行的时候很多时候要比整个Kubernetes集群出现的时机要早.

Kubernetes项目中, 当一个节点的网络插件尚未安装时, 该节点就会被自动加上名为node.kubernetes.io/network-unavailable的”污点”. 而通过这样一个Toleration, 调度器在调度这个Pod时就会忽略当前节点上的”污点”, 从而成功地将网络插件的Agent组件调度到这台机器上启动起来.

撬动离线业务: JobCronJob

事实上, restartPolicyJob对象里只允许设置为NeverOnFailure; 而在Deployment对象里, restartPolicy只允许设置为Always.

如果restartPolicy=Never, 那么离线业务失败后Job Controller就会不断尝试创建一个新Pod. 如果restartPolicy=OnFailure, 那么离线业务失败后, Job Controller就不会尝试创建新的Pod, 而是不断尝试重启Pod里的容器.

CronJob是一个专门用来管理Job对象的控制器.

基于角色的权限控制: RBAC

我们知道, Kubernetes中所有API对象都保存在etcd里. 可是, 对这些API对象的操作一定都是通过访问kube-apiserver实现的. 其中一个非常重要的原因是, 需要API Server来帮忙做授权工作. 而在Kubernetes项目中, 负责完成授权工作的机制是RBAC.

-------------本文结束感谢您的阅读-------------