1. master节点上的组件:
etcd:
API Server:
Scheduler:
Controller Manager:
为了保证高可用,master节点的组件可以多实例运行,但是只有etcd和API Server可以同时并行工作,Scheduler和Controller Manager在同一时间内只能有一个实例处于运行状态,其他实例处于待命模式。
1.1 etcd
1.1.1
k8s里的所有对象:pod,ReplicationContorller,service,secret等等的元数据都需要以持久化的方式存储到某个地方,这样组件重启了元数据才不会丢失。
1.1.2
唯一能和etcd通信的组件是API server,其他组件要和etcd通信都要通过API Server。这样也保证了API Server能通过乐观锁的方式更新etcd。
1.1.3 etcd存储资源的方式:
etcd v2: 类似于文件系统,每个key要么是一个目录(包含其他key),要么是一个常规key,对应一个value。例子:
/registry/pods //pods是一个目录
/registry/namespace
...
etcd v3: 不支持目录,但是key可以包含斜杠,其实就跟目录差不多。例子(etcd v3不支持 ls命令):
/registry/pods/default/kubia-159041347-xk0vc //直接列出key,没有目录
...
获取key对应的value:
{"kind":"Pod","apiVersion":"v1"....} //可以看出其实它就是我们创建pod时用的那个yml文件
1.1.4 HA
etcd是可以通过运行多个etcd实例来达到HA的。通常对于大集群,etcd有5个或者7个就够了,可以允许2-3个宕机(因为必须保证超过半数的机器还活着)
由于必须保证超过半数的机器还活着,所以etcd集群的实力个数通常都是奇数个。
1.2 API Server
其他组或者客户端(如kubectl)都会去调用它。以RESTful API的形式提供了可以查询,修改集群状态的接口(CRUD)。并把最终状态存到etcd。它是唯一一个能与etcd交互的组件。所有其他组件要与etcd通信来改变资源的配置时都需要通过apiServer。
提供三个功能:
- 作为统一的接口取访问etcd。
- 将资源描述文件(yml)存入etcd之前,对文件做校验。这样客户端kubectl就无法存入非法对象了
- 提供了乐观锁机制,这样多个客户端kubectl并发更新的情况下,不会出现先更新的覆盖后更新的。
1.2.1 一个请求从客户端kubectl发出来之后,在api server中的流程
- API Server上会被配置一个或者多个认证插件(Authentication plugin), 轮流调用这些插件对客户端kubectl发过来的请求做认证,以确认是哪个用户发送的该请求。
- 同上,会配置多个授权插件(Authorization plugin),轮流调用这些插件,判断是否授权客户端执行相应的请求。
- 同上,多个准入控制插件(Admission control plugin),对创建,修改,删除资源的操作,进行校验,其实就是看看你的yml文件写的对不对,是不是有语法错误(有语法错误就拒绝请求),给你漏配的字段填写默认值等。注意如果只是读数据,则不会做准入控制的验证。
1.2.2 API Server提供了监听的功能,以通知各个组件,当前资源发生了改变。
比如说客户端kubectl创建一个pod,api server收到请求后把它存入etcd。那controller manager是怎么知道现在它需要去创建一个pod的呢?答案是controller manager注册了对api server的监听。一旦有资源的变化,api server都会回调controller manager。
//这个命令就可以创建kubectl对api server的监听,一旦有新的pod创建,
//api server就会回调到这里
kubectl get pods --watch
1.3 Scheduler
利用API Server的监听机制,等待新创建的pod,然后给每个新的pod分配Node。
注意:Scheduler不会去命令某个node运行pod。
- 它只是通过API Server更新pod的定义(也就是yml文件),然后存入etcd,更新的内容肯定就是pod应该被调度到哪个Node上。
- 然后运行在node上的kubelet同样也会监听API Server,pod更新后,对应Node上运行的kubelet收到回调,发现pod是被调度到本节点,就会去创建并运行pod。
1.3.1 Scheduler最核心的其实就是调度算法了,调度算法分2步:
过滤所有node,找出可用的node列表。
在可用的node列表中,按优先级排序。如果多个node都有最高优先级分数,则循环分配。
具体的调度算法,亲缘性规则以及各种因子这里不展开了。
1.3.2 Scheduler也是可以有多个的
在给pod定义的时候就可以指定SchedulerName来指定这个pod被哪个Scheduler调度。没配的话就会用k8s默认的调度器,default-scheduler。
1.4 Controller Manager控制器管理器
包括:
ReplicationController Controller
ReplicaSet/DaemonSet/Job controller
Deployment Controller
StatefulSet Controller
Node Controller
等等...
它们的主要的作用就是确保集群里的资源的真实状态,朝着跟yml中定义的期望状态收敛。
1.4.1 ReplicationController
比如说某个ReplicationController中定义了pod的个数是3个,当前只有2个pod的话,ReplicationController Controller就需要通过API Server再创建一个pod。如果有4个,就需要删除一个。
需要注意的是,ReplicationController并不会去轮询所有pod,而是通过API Server的监听机制订阅可能影响期望值的replica数量或者符合pod数量变化的事件。ReplicationController收到这些事件的通知后就会去检测期望的replica的数量和实际pod的数量,然后作出相应操作(创建/删除pod)。
大概流程:
- 通过kubectl apply创建一个replicationController资源。
- API Server收到请求,并将yml文件写入etcd。
- ReplicationController组件收到回调,然后查看当前pod个数(此时当前pod个数肯定是0了),然后通过API Server创建pod。
- API Server把创建pod的 yml文件写入etcd.
- scheduler收到监听,给pod找匹配的Node。
- scheduler找到匹配的node后,通过API Server更新pod的yml,写入etcd。
- node上的kubelet收到监听消息,开始创建pod。
其他的控制器跟replicationController差不多,都是确保集群里的资源的真实状态,朝着跟yml中定义的期望状态收敛。
1.4.2 DeploymentController
每次Deployment对象修改后,如果修改会影响到部署的pod,DeploymentController都会创建一个新的replicaSet,然后按照Deployment中定义的策略同时伸缩新,旧的replicaSet。
2. 工作节点上的组件:
kube-proxy:
kubelet:
容器;
2.1 kubelet
功能:
- 首先它需要想API server创建一个Node资源,来注册改节点。这样API Server中有事件来的话就会通知到Kubelet。
- kubelet要持续监听API Server的事件,如果API Server通知有pod被调度到了本节点,它就要去创建pod
- 创建pod,并在pod中运行容器
- 监控pod的状态,并行API Server报告这些状态
- 运行容器的存活探针,当探针报错,则重启容器
- 当API server通知pod要被删除的时候,kubectl会干掉pod,并告知Api Server pod已经被干掉了。
2.2 kube-proxy
kube-proxy的作用是用来确保客户端的请求(客户端通过service的IP+端口)可以顺利到达对应的pod。
之前说过,service创建后,对应会创建endpoint。客户端的请求过来后,kube-proxy会根据endpoint中的ip+port列表选择一个,然后转发请求。
kube-proxy有2种模式:
userspace代理模式
iptables代理模式(性能更好)