[toc]
k8s必会知识点梳理
kube-apiserver
对外暴露了Kubernetes API。它是的 Kubernetes 核心控制层。它被设计为水平扩展,即通过部署更多实例来横向扩展。API Server 负责和 etcd 交互(其他组件不会直接操作 etcd,只有 API Server 这么做),是整个 kubernetes 集群的数据中心,所有的交互都是以 API Server 为核心的。API Server 提供了以下的功能:
- 整个集群管理的 API 接口:所有对集群进行的查询和管理都要通过 API 来进行。
- 集群内部各个模块之间通信的枢纽:所有模块之间并不会互相调用,而是通过和 API Server 打交道来完成各自的工作。
- 集群安全控制:API Server 提供的验证和授权保证了整 个集群的安全。
kube-controller-manager和kube-scheduler的高可用选主机制
在k8s的组件中,其中有kube-scheduler和kube-controller-manager两个组件是有leader选举的,这个选举机制是k8s对于这两个组件的高可用保障。需要--leader-elect=true启动参数。即正常情况下kube-scheduler或kube-manager-controller组件的多个副本只有一个是处于业务逻辑运行状态,其它副本则不断的尝试去获取锁,去竞争leader,直到自己成为leader。如果正在运行的leader因某种原因导致当前进程退出,或者锁丢失,则由其它副本去竞争新的leader,获取leader继而执行业务逻辑。
在K8s中, 通过创建资源对象(当前的实现中实现了 ConfigMap 和 Endpoint 两种类型的资源)来维护锁的状态。这两种资源对象存在etcd里,也可以说是用etcd来实现的。
分布式锁一般实现原理就是大家先去抢锁,抢到的成为 leader ,然后 leader 会定期更新锁的状态,声明自己的活动状态,不让其他人把锁抢走。K8s 的资源锁也类似,抢到锁的节点会将自己的标记。设为锁的持有者,其他人则需要通过对比锁的更新时间和持有者来判断自己 是否能成为新的 leader ,而 leader 则可以通过更新RenewTime来确保持续保有该锁。
主要调用client-go包中的:
k8s.io/client-go/tools/leaderelection
总共有7个leader选举参数:
- lock-object-namespace和lock-object-name是锁对象的命名空间和名称。
- leader-elect表示该组件运行时是否需要leader选举(如果集群中运行多副本,需要设置该选项为true,否则每个副本都将参与实际工作)。
- leader-elect-lease-duration为资源锁租约观察时间,如果其它竞争者在该时间间隔过后发现leader没更新获取锁时间,则其它副本可以认为leader已经挂掉不参与工作了,将重新选举leader。
- leader-elect-renew-deadline leader在该时间内没有更新则失去leader身份。
- leader-elect-retry-period为其它副本获取锁的时间间隔(竞争leader)和leader更新间隔。
- leader-elect-resource-lock是k8s分布式资源锁的资源对象,目前只支持endpoints和configmaps。
etcd
Etcd使用的是raft一致性算法来实现的,是一款分布式的一致性KV存储,主要用于共享配置和服务发现。用于 Kubernetes 的后端存储。所有集群数据都存储在此处,ETCD在k8s技术栈的地位,就仿佛数据库(Mysql、Postgresql或oracle等)在Web应用中的地位,它存储了k8s集群中所有的元数据(以key-value的方式)。整个kubernetes系统需要用到etcd用来协同和存储配置的有:
- 网络插件flannel、calico等网络插件也需要用到etcd 存储网络的配置信息
- kubernetes本身,包括各种对象的状态和元信息配置
**注意:**flannel操作etcd使用的是v2的API,而kubernetes操作etcd使用的v3的API,所以在下面我们执行etcdctl的时候需要设置ETCDCTL_API环境变量,该变量默认值为2。
K8s中所有元数据的增删改查都是由kube-apiserver来执行的。ETCD中key值通过观察可以简单得出下面几个规律:
k8s主要把自己的数据注册在/registry/前缀下面(在ETCD-v3版本后没有了目录的概念,只能一切皆前缀了)。通过观察k8s中deployment、namespace、pod等在ETCD中的表示,可以知道这部分资源的key的格式为 /registry/{k8s对象}/{命名空间}/{具体实例名}
。
kube-controller-manager
kube-controller-manager运行控制器,它们是处理集群中常规任务的后台线程。逻辑上,每个控制器是一个单独的协程。用于监视 apiserver 暴露的集群状态,并且不断地尝试把当前状态向集群的目标状态迁移。为了避免频繁查询 apiserver,apiserver 提供了 watch 接口用于监视资源的增加删除和更新,client-go 对此作了抽象,封装一层 informer 来表示本地 apiserver 状态的 cache 。
参考:
这些控制器包括:
节点控制器(node-controller): kubelet在启动时会通过API Server注册自身的节点信息,并定时向API Server汇报状态信息,API Server接收到信息后将信息更新到etcd中。Node Controller通过API Server实时获取Node的相关信息,实现管理和监控集群中的各个Node节点的相关控制功能。
副本控制器(Replication Controller): 负责维护系统中每个副本控制器对象正确数量的 Pod。副本控制器的作用即保证集群中一个RC所关联的Pod副本数始终保持预设值。只有当Pod的重启策略是Always的时候(RestartPolicy=Always),副本控制器才会管理该Pod的操作(创建、销毁、重启等)。
服务帐户和令牌控制器(ServiceAccount Controller ): 为新的命名空间创建默认帐户和 API 访问令牌。
**资源配额管理控制器ResourceQuota Controller:**资源配额管理确保指定的资源对象在任何时候都不会超量占用系统物理资源。支持三个层次的资源配置管理:
- 容器级别:对CPU和Memory进行限制;
- Pod级别:对一个Pod内所有容器的可用资源进行限制;
- Namespace级别:包括Pod数量、Replication Controller数量、Service数量、ResourceQuota数量、Secret数量、可持有的PV(Persistent Volume)数量
**Namespace Controller:**用户通过API Server可以创建新的Namespace并保存在etcd中,NamespaceController定时通过API Server读取这些Namespace信息。如果Namespace被API标记为优雅删除(即设置删除期限,DeletionTimestamp),则将该Namespace状态设置为“Terminating”,并保存到etcd中。同时Namespace Controller删除该Namespace下的ServiceAccount、RC、Pod等资源对象。
**Service Controller:**属于kubernetes集群与外部的云平台之间的一 个接口控制器。Service Controller监听Service变化,如果是一个LoadBalancer类型的Service,则确保外部的云平台上对该Service对应的LoadBalancer实例被相应地创建、删除及更新路由转发表。
**deployment controller:**用来替代以前的ReplicationController来方便的管理应用。只需要在 Deployment 中描述您想要的目标状态是什么,Deployment controller 就会帮您将 Pod 和ReplicaSet 的实际状态改变到您的目标状态。您可以定义一个全新的 Deployment 来创建 ReplicaSet 或者删除已有的 Deployment 并创建一个新的来替换。
- 定义Deployment来创建Pod和ReplicaSet
- 滚动升级和回滚应用
- 扩容和缩容
- 暂停和运行Deployment
**statefulset controller:**StatefulSet是为了解决有状态服务的问题(对应Deployments和ReplicaSets是为无状态服务而设计),其应用场景包括:
- 稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC来实现;
- 稳定的网络标志,即Pod重新调度后其PodName和HostName不变,基于Headless Service(即没有Cluster IP的Service)来实现。StatefulSet中每个Pod的DNS格式为:
statefulSetPodName-{0..N-1}.serviceName.namespace.svc.cluster.local
- 有序部署,有序扩展,即Pod是有顺序的,在部署或者扩展的时候要依据定义的顺序依次依次进行(即从0到N-1,在下一个Pod运行之前所有之前的Pod必须都是Running和Ready状态),基于init containers来实现;
- 有序收缩,有序删除(即从N-1到0)
**daemonset controller:**DaemonSet确保全部(或者一些)Node 上运行一个 Pod 的副本。当有 Node 加入集群时,也会为他们新增一个 Pod 。当有 Node 从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod。
**Horizontal Pod Autoscaling:**仅适用于Deployment和ReplicaSet,在V1版本中仅支持根据Pod的CPU利用率扩所容,在v1alpha版本中,支持根据内存和用户自定义的metric扩缩容。
persistentvolume-binder: 定期同步磁盘卷挂载信息,负责pv和pvc的绑定。
**Endpoints controller:**表示了一个Service对应的所有Pod副本的访问地址,而EndpointsController负责生成和维护所有Endpoints对象的控制器。它负责监听Service和对应的Pod副本的变化。
- 如果监测到Service被删除,则删除和该Service同名的Endpoints对象;
- 如果监测到新的Service被创建或修改,则根据该Service信息获得相关的Pod列表,然后创建或更新Service对应的Endpoints对象;
- 如果监测到Pod的事件,则更新它对应的Service的Endpoints对象。
kube-proxy进程获取每个Service的Endpoints,实现Service的负载均衡功能。
以上只是部分控制器,都是一个独立的协程,被controller-manager这个进程所管理。
Statefulset和Deployment的区别
Deployment用于部署无状态服务,StatefulSet用来部署有状态服务。
如果部署的应用满足以下一个或多个部署需求,则建议使用StatefulSet。
-
稳定的、唯一的网络标识;
-
稳定的、持久的存储;
-
有序的、优雅的部署和伸缩;
-
有序的、优雅的删除和停止;
-
有序的、自动的滚动更新;
-
实现固定的Pod IP方案, 可以优先考虑基于StatefulSet
**稳定的:**主要是针对Pod发生re-schedule后仍然要保持之前的网络标识和持久化存储。这里所说的网络标识包括hostname、集群内DNS中该Pod对应的A Record,并不能保证Pod re-schedule之后IP不变。要想保持Pod IP不变,我们可以借助稳定的Pod hostname定制IPAM获取固定的Pod IP。借助StatefulSet的稳定的唯一的网络标识特性,我们能比较轻松的实现Pod的固定IP需求,然后如果使用Deployment,那么将会复杂的多,你需要考虑滚动更新的过程中的参数控制(maxSurge、maxUnavailable)、每个应用的IP池预留造成的IP浪费等等问题。
**存储:**StatefulSet对应Pod的存储最好通过StorageClass来动态创建:每个Pod都会根据StatefulSet中定义的VolumeClaimTemplate来创建一个对应的PVC,然后PVS通过StorageClass自动创建对应的PV,并挂载给Pod。所以这种方式,需要事先创建好对应的StorageClass。当然,你也可以通过预先由管理员手动创建好对应的PV,只要能保证自动创建的PVC能和这些PV匹配上。