K8S architecture

K8S architecture

Control Plane 控制平面

kube-apiserver

负责API服务

etcd

整个集群的持久化数据,都是由kube-apiserver经过处理后保存在etcd中。

kube-scheduler

负责调度功能,负责为Pod分配最合适的节点。

kube-controller-manager

负责容器编排,包含很多不同功能的控制器。

Node Components 节点组件

kublet

  • 运行在每个节点上;由于需要直接操作宿主机,一般直接安装在每台宿主机上,不像别的组件一般以容器方式部署;
  • 通过CRI(Container Runtime Interface)同容器运行时交互;
  • 通过CNI(Container Network Interface)调用网络插件为容器配置网络;
  • 通过CSI(Container Storage Interface)调用存储插件为容器配置持久化存储;
  • 通过gRPC协议同一个叫做Device Plugin的插件进行交互,这个插件,是kubernetes用来管理GPU等宿主机物理设备的主要组件。

kube-proxy

通过操作iptables实现集群内网络路由相关功能(比如Service)。

Container runtime 容器运行时

管理容器的执行和生命周期。 只要你的容器运行时能够运行标准的容器镜像,它就可以通过实现CRI接入Kubernetes。 而具体的容器运行时,比如Docker,一般通过OCI这个容器运行时规范同底层的Linux进行交互,即把CRI请求转化成对操作系统的调用(操作Linux namespace和Cgroups等)

部署工具kubeadm

kubeadm的工作原理是直接在宿主机上运行kubelet, 然后使用容器部署其他kubernetes组件。

实际上,kubeadm几乎完全是一位高中生的作品。他叫Lucas Kaldstrom, 芬兰人。kubeadm是他17岁时用业余时间完成的一个社区项目。

并且kubeadm是可以用于生产环境的,在kubernetes v1.14发布后,kubeadm项目已经正式宣布GA(General availability, 生产可用)了。

部署步骤

  • 安装kubeadm和docker
$ apt-get install -y docker.io kubeadm

上述安装kubeadm的过程中,会自动安装kubeadm, kubelet, kubectl和kubernetes-cni这几个二进制文件。

  • 部署Master节点
$ kubeadm init --config kubeadm.yaml

kubeadm.yaml是自定义的部署配置。 部署完成后,会生成一行kubeadm join命令,把它复制保存好,后面部署worker节点时需要用到。 kubeadm还会提示配置kube config等,复制命令执行即可。

  • 部署网络插件

部署选型的网络插件,下面是weave的情况。

$ kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"
  • 部署worker节点

执行kubeadm init步骤时提示的kubeadm join命令。

$ kubeadm join xxxx:6443 --token xxxx --discovery-token-ca-cert-hash xxxx

kubernetes编排原理

Pod

  • Pod是kubernetes项目的原子调度单位;
  • Pod的实现需要使用一个中间容器,这个容器叫做Infra容器,Infra容器永远是第一个被创建的容器,用户定义的其他容器通过Join Network Namespace的方式与Infra容器关联在一起。Infra容器占用极少的资源,使用的是一个非常特殊的镜像,叫做k8s.gcr.io/pause。这个镜像是一个用汇编语言编写的,永远处于“暂停”状态的容器,解压后的大小也只有100~200KB

Deployment

  • Deployment控制ReplicaSet(版本),ReplicaSet控制Pod(副本数),这个两层控制关系一定要牢记。
  • Deployment通过创建一个新的RelicaSet,不断新增新ReplicaSet的Pod数量,同时减少旧ReplicaSet的Pod数量的方式实现滚动更新应用版本。

StatefulSet

  • StatefulSet的控制器直接管理的是Pod,每个Pod的hostname,名字等都不同,都携带了编号。
  • k8s通过Headless Service为这些有编号的Pod,在DNS服务器中生成带有相同编号的DNS记录。
  • StatefulSet还为每一个Pod分配并创建一个相同编号的PVC。即使Pod被删除,它所对应的PVC和PV依然会保存下来,当这个Pod被重建后,由于编号相同,它还可以获取以前保存在Volume里的数据。
  • 同样,只要修改了StatefulSet的Pod模版,即可自动触发滚动更新。StatefulSet Controller会按照与Pod编号相反的顺序,从最后一个Pod开始,逐一更新这个StatefulSet管理的每个Pod。

DaemonSet

  • DaemonSet的Pod在Kubernetes集群的每一个节点运行
  • 每个节点上只有一个这样的Pod实例。
  • 当有新节点加入kubernetes集群后,该Pod会自动地在新节点上被创建出来。节点被删除后,上面的Pod也会相应地被回收。

使用场景:

  • 各种网络插件的Agent组件都必须在每一个节点运行;
  • 各种存储插件的Agent组件都必须在每一个节点运行;
  • 各种监控组件和日志组件都必须在每一个节点运行。

离线业务:Job与CronJob

对于CronJob,笔者在实践中踩过坑,对于需要频繁执行的定时任务来说,比如每5秒执行一次的定时任务,使用CronJob将不是一个好主意,这会导致每5秒就要创建1个新Pod,会给整个Kubernetes集群带来很大的负载压力。