Kubernetes
- 如何编排、管理、调度用户的作业?
- 在大规模集群中存在各种各样的任务,任务之间又有着各样的关系。对于这些关系要如何处理优雅得体才是作业编排与系统管理的痛点所在。
主要设计思想
以更宏观的角度,整齐划一的方式 对系统中的任务
进行定义。并能给以后支持更多种类的关系而留有余地。
全局架构
image上层master控制与etcd存储
-
Controller manager
负责容器编排 -
Api server
api服务 -
Shceduler
任务调度 -
etcd
整个集群的持久化存储
下层各个不同的node节点
- 核心:kubelet,负责与容器运行时(Docker)交互。
- kubelet依赖CRI(Container Runtime Interface),远程调用接口,其定义了容器运行时核心操作(比如:启动容器所需的参数)。
- 这里通过CRI层,来实现k8s与容器层的解耦,我并不关心你使用的是什么容器技术,只要能运行标准镜像,就可以接入到Kubernetes中。
- 除此之外,kubelet通过gRPC与Device Plugin交互。其主要用于管理宿主机的物理设备。帮助K8s进行机器学习,高性能作业。
- CNI(Container Networking)与CSI(Container Storage Interface)用于调用网络插件配置容器网络与存储插件提供容器的持久化存储。
声明式API
- 如何让Pod之间进行交互,伴随着一系列功能模块的衍生
- 通过申明不同的API对象(如图不管是编排对象Pod、Job还是服务对象Service、Secret等)来实现需要的功能
什么是Pod
其实它就是一组共享了某些资源的容器
- 那么问题出现了:
- 如果Pod只是共享了资源的容器的话,那只需要直接使用docker run --net --volumes-from 让两个容器共享一个网络和卷就好。为什么还需要Pod呢
- 如果真这么做的话,先不说麻烦,就拿两个容器的启动顺序来说,两个容器必定会有依赖性,某个容器肯定要先于另一个启动,这样就导致了众多容器的顺序启动问题,形成一个拓扑关系,它们之间的关系并不平等。
- 如何解决:
- 在kubernetes中,使用了一个中间容器(infra容器:它使用的镜像是k8s.gcr.io/pause,这个容器永远处于暂停状态)。infra会比Pod中的任何容器都优先初始化,然后其他容器就通过加入到这个容器的网络namespace形成关联。
- Pod生命周期只与Infra容器关联,和其他容器没有关系
- 一个Pod里面的进出流量都是通过infra的,所以 =>
如果要开发一个网络插件什么的,只需要考虑Pod的network namespace就行
应该如何构建Pod
举个典型例子,war包与服务器:
- 以前可以怎么做呢?
- 将war包放到服务器下,然后整体打包成一个镜像运行,但是每次有修改就需要重新做镜像
- 将服务器做成容器,然后共享它的挂载目录,将war包放到挂载目录。这样的问题是我需要让每个宿主机都预留一个这样的目录才能将war包放进去
- Pod
- 将war包和服务器分别做成image,然后使用Pod组合两个容器
- 在Pod的配置文件中能使用 initContainers标签指明优先执行war包容器,将war拷贝到服务器的文件夹下
- 从而使这两个容器对外表现为同一应用
- 这种容器的组合设计模式就叫做
sidecar
-
sidecar
指的是 在Pod中启动辅助容器来完成主容器之外的工作 - 这里使用initContainers标签的war包容器就是一个
sidecar
传统应用如何向微服务过渡
在我们一些应用使用kubernetes微服务化、容器化的上云过程中,需要考虑的还是要深入理解容器的本质(进程),其实我们可以将虚拟机想象成一个Pod,而容器就是运行在虚拟机的各个进程。
- Pod是一个编排思想而不是具体的技术方案
如何将Pod部署到某一个node中
- 使用nodeSelector相互绑定,一旦Pod被调度过了,其NodeName就会被赋值(可通过此字段来骗过调度器)
容器生命周期钩子
- lifecycle:(PostStart、PreStop可以执行一系列操作)。比如:
spec:
containers:
- name: xxx
image: xxx
lifecycle:
postStart:
exec:
commond:["/bin/sh", "-c", "echo test"]
特殊的Volume - project Volume
-
Secret: 把Pod中想要访问的加密数据,存放到Etcd中。访问的时候只需要通过挂载Pod的Volume方式访问这些信息就好了。通过这样挂载的Secret只要对应的Etcd里的数据被更新,那么这些Volume的内容就会同步更新。(kubelet在定时维护这些Volume)
-
ConfigMap: 用法完全与Secret相同,只是它的内容不需要加密
-
DownloadApi: 暴露Pod本身信息给容。给容器挂载卷的时候指定如下,就能指定此Pod容器的volumes来源,他暴露了此Pod的labels给容器。挂载路径是
/etc/test/labels
。
volums:
- name: test
projected:
sources:
- downwardAPI:
items:
- path: "labels"
fileRef:
filedPath: metadata.labels
- Service Account: 一种特殊的
Secret
,主要能让用户能合法访问API Server -- 相当于访问的token(其实每个Pod创建时都会自动挂载Secret Account,也可以设置不自动挂载)。通过将K8s客户端以容器的方式运行在集群中,然后使用default Service Account 自动授权叫做InClusterConfig
,这也是最常用的授权方式。
如何进行Pod容器的健康检测 -- livenessProbe
拿Spring boot acturator举例
spec:
containers:
- name: liveness
image: xxx
livenessProbe:
exec:
command:
- curl
- https://xxx/acturator/health
initailaDelaySeconds: 5
periodSeconds: 10
- ps: 容器启动后5s开始健康检查,每10s执行一次
- 只要检测到容器是不健康的就会restart一次,但它的恢复过程永远都是发生在当前节点上,不会移动到其他node上。
- 如果想让这个Pod重启到其他node上,就需要deployment调度它到其他node上。
- 这里容器的重启策略有三种:Always,OnFailure,Never。
- 这里只要Pod的重启策略不是Never,那么这个Pod就会一直保持Running状态(一直在尝试重启)。
- 如果一个Pod里包含多个容器,不管重启策略是什么,只有它里面所有容器都异常,Pod才是Failed状态
网友评论