k8s 主要由以下核心组件组成:

  • API Server:提供了资源操作的唯一入口,并提供认证、授权、访问控制、API 注册和发行等机制,该服务运行在Master节点上。
  • etcd:保存了整个集群的状态,该服务运行在Master节点上。
  • Controller Manager:负责维护集群的状态,比如故障检测、自动扩展、滚动更新等,该服务运行在Master节点上。
  • Scheduler:负责资源的调度,按照预定的调度策略将 Pod 调度到相应的机器上,该服务运行在Master节点上。
  • Kubelet:负责维护容器的生命周期,同时也负责Volume(CVI)和网络(CNI)的管理。该服务运行在所有的Master和node节点上。
  • Container Runtime:负责镜像管理以及 Pod 和容器的真正运行(CRI)。该服务运行在所有的Master和node节点上。
  • Kube-proxy:负责为 Service 提供 Cluster 内部的服务发现和负载均衡。该服务运行在所有的Master和node节点上。

以下是 K8s 架构图。

Master控制节点

    Master节点是Kubernetes集群的控制节点,每个Kubernetes集群里至少有一个Master节点,它负责整个集群的决策(如调度),发现和响应集群的事件。一个集群通常运行多个Master控制节点,提供容错性和高可用性。Master节点可以运行在集群中的任意一个节点上,但是最好将Master节点作为一个独立节点,不在该节点上创建容器,因为如果该节点出现问题导致宕机或不可用,整个集群的管理就会失效。

    在Master节点上,会运行以下服务:

  • kube-apiserver
  • etcd
  • kube-scheduler
  • kube-controller-manager


在Master节点上,还会运行以下服务:

  • kubelet
  • kube-proxy
  • Container Runtime:在集群内每个节点上都会安装Container Runtime容器运行时环境,以使Pod可以在上运行。可以是Docker或者其他容器平台如container。

kube-apiserver

    此服务负责公开K8s API并处理请求,可以通过K8s API查询和操纵K8s中对象的状态。

etcd

    一致且高度可用的Key-Value键值存储,用作Kubernetes的所有群集数据的后备存储,在K8s中有两个服务需要用到etcd来协同和配置,分别如下

网络插件 flannel、对于其它网络插件也需要用到 etcd 存储网络的配置信息

    Kubernetes 本身,包括各种对象的状态和元信息配置

    注意:flannel 操作 etcd 使用的是 v2 的 API,而 Kubernetes 操作 etcd 使用的 v3 的 API,所以在下面我们执行 etcdctl 的时候需要设置 ETCDCTL_API 环境变量,该变量默认值为 2。

  etcd实现原理:http://jolestar.com/etcd-architecture/

kube-scheduler

    调度器,运行在Master上,用于监控节点中的容器运行情况,并挑选节点来创建新的容器。调度决策所考虑的因素包括资源需求,硬件/软件/策略约束,亲和性和排斥性规范,数据位置,工作负载间干扰和最后期限。

kube-controller-manager

    控制和管理器,运行在Master上,每个控制器都是独立的进程,但为了降低复杂性,这些控制器都被编译成单一的二进制文件,并以单独的进程运行。

Node工作节点

    Node 节点是 Kubernetes 集群的工作节点,每个集群中至少需要一台Node节点,它负责真正的运行Pod,当某个Node节点出现问题而导致宕机时,Master会自动将该节点上的Pod调度到其他节点。Node节点可以运行在物理机上,也可以运行在虚拟机中。

    Node节点可以在集群运行期间动态增加,只要整个节点已经正确安装配置和启动了上面的进程。在默认情况下,kubelet会向Master自动注册。一旦Node被接入到集群管理中,kubelet会定时向Master节点汇报自身的情况(操作系统,Docker版本,CPU内存使用情况等),这样Master便可以在知道每个节点的详细情况的同时,还能知道该节点是否是正常运行。当Node节点心跳超时时,Master节点会自动判断该节点处于不可用状态,并会对该Node节点上的Pod进行迁移。

    在Node节点上,通常会运行以下服务:

  • kubelet: 此服务会在集群中每个master和Node节点运行,负责K8s Master控制节点和Node工作节点之间的通信,还负责Pod对应的容器创建,启动和停止等任务,以实现集群管理的基本功能。
  • kube-proxy: 此服务会在集群中每个master和Node节点运行,是集群中每个Node节点上运行的网络代理,是实现K8s服务概念的一部分。它维护节点上的一些网络规则,这些网络规则会允许从集群内部或外部的网络会话与Pod进行网络通信。
  • Container Runtime: 在集群内每个节点上都会安装Container Runtime容器运行时环境,以使Pod可以在上运行。可以是Docker或者其他容器平台如container。


Pod

    Pod是K8s中最小的调度资源单位,是容器或容器的集合,一个Pod中可以有多个容器 ,彼此共享网络和存储等。Pod中的容器都是统一进行调度,并且运行在共享上下文中。一个Pod被定义为一个逻辑的host,它包括一个或多个相对耦合的容器。

    Pod的共享上下文,实际上是一组由namespace、cgroups和其他资源的隔离的集合,意味着Pod中的资源已经是被隔离过了的,而在Pod中的每一个独立的container又对Pod中的资源进行了二次隔离。

    一个 Pod 总是运行在工作节点。工作节点可以有多个 Pod 。控制节点会根据每个工作节点上可用资源的情况,自动调度 Pod(容器组)到最佳的工作节点上。如果运行实例的工作节点关机或被删除,则 Kubernetes Deployment Controller 将在群集中资源最优的另一个工作节点上重新创建一个新的实例。这提供了一种自我修复机制来解决机器故障或维护问题。

Replication Controller

    Replication Controller为Kubernetes的一个核心内容,应用托管到Kubernetes之后,需要保证应用能够持续的运行,Replication Controller就是这个保证的key,主要的功能如下:

  • 确保pod数量:它会确保Kubernetes中有指定数量的Pod在运行。如果少于指定数量的pod,Replication Controller会创建新的,反之则会删除掉多余的以保证Pod数量不变。
  • 确保pod健康:当pod不健康,运行出错或者无法提供服务时,Replication Controller也会杀死不健康的pod,重新创建新的。
  • 弹性伸缩 :在业务高峰或者低峰期的时候,可以通过Replication Controller动态的调整pod的数量来提高资源的利用率。同时,配置相应的监控功能(Hroizontal Pod Autoscaler),会定时自动从监控平台获取Replication Controller关联pod的整体资源使用情况,做到自动伸缩。
  • 滚动升级:滚动升级为一种平滑的升级方式,通过逐步替换的策略,保证整体系统的稳定,在初始化升级的时候就可以及时发现和解决问题,避免问题不断扩大。


Deploment

    在kubernetes中,Pod是最小的控制单元,但是kubernetes很少直接控制Pod,一般都是通过Pod控制器来完成的。Pod控制器用于Pod的管理,确保Pod资源符合预期的状态,当pod的资源出现故障时,会尝试进行重启或重建Pod。在kubernetes中Pod控制器的种类有很多,Deployment 是最常用的那种。Deployment是K8s用于管理Pod的资源对象,用来保证K8s中Pod的多实例、高可用与滚动更新、灰度部署等。可以说,Deployment是K8s中最常用最有用的一个对象,多用来发布无状态的应用。

    单独创建pod的时候就不会有deployment出现,但是创建deployment的时候一定会创建pod,因为pod是一个基础的单位。任何的控制器单位的具体实现必须落到pod去实现。

    Deployment是比Replication Controller更高级的一种资源,它不但可以控制Pod的副本数,同时还可以控制Pod的版本,所以这么高级的资源并不是时时刻刻都需要的,比如你就想暂时性的部署一个小程序,用完就不要了,那么你就没有必要使用RS或者RC,更没有必要去用Deploment。

    从开发者角度看,deployment顾明思意,既部署,对于完整的应用部署流程,除了运行代码(既pod)之外,需要考虑更新策略,副本数量,回滚,重启等步骤,而运行代码的方式有很多种,例如有一次性的也就是job,有定时执行的也就是crontabjob,有排号的也就是sts,为了复用运行代码的功能所以抽象为pod,从而进行复用。

    从用户角度看,我们操作时也会根据不同的代码副本进行查看,例如日志,资源占用都是实例级别的也需要这么一个抽象。 

    Deployment同样为Kubernetes的一个核心内容,主要职责同样是为了保证pod的数量和健康,90%的功能与Replication Controller完全一样,可以看做新一代的Replication Controller。但是,它又具备了Replication Controller之外的新特性:

  • Replication Controller全部功能:Deployment继承了上面描述的Replication Controller全部功能。
  • 事件和状态查看:可以查看Deployment的升级详细进度和状态。
  • 回滚:当升级pod镜像或者相关参数的时候发现问题,可以使用回滚操作回滚到上一个稳定的版本或者指定的版本。
  • 版本记录: 每一次对Deployment的操作,都能保存下来,给予后续可能的回滚使用。
  • 暂停和启动:对于每一次升级,都能够随时暂停和启动。
  • 多种升级方案:Recreate:删除所有已存在的pod,重新创建新的; RollingUpdate:滚动升级,逐步替换的策略,同时滚动升级时,支持更多的附加参数,例如设置最大不可用pod数量,最小升级间隔时间等等。

Replication Set

    前面提到,Deployment是Pod的其中一个管理者,这其实也不准确,Deployment控制器也不直接操纵Pod。应用存在副本、版本,如果直接Deployment控制器直接管理Pod,对于版本管理、灰度部署、滚动更新等功能就比较麻烦,因此在Deployment和Pod直接还存在一个ReplicaSet的对象,它是对对应着不同不Pod版本,是Pod直接管理者。Deployment通过操纵ReplicaSet间接的管理Pod:

    如图所示描述了在 replicas=5 的设置下,灰度部署(滚动更新)2/5的时候,Deployment的状态。我们不用直接创建ReplicaSet,在创建Deployment的时候,K8s会默认创建ReplicaSet,并由Deployment控制器进行管理。K8s也不建议人工管理ReplicaSet。


创建deployment

执行如下命令输出一个yaml模板


kubectl create deploy nginx-deploy --image=nginx:alpine --dry-run=client -o yaml


  • spec下面的replicas参数代表的是副本数,用户描述希望创建多少个pod,默认为1。通过副本数字段,我们可以提高应用的可用性,减少因意外导致旧Pod被删除、新Pod未起引起可用性下降的问题。此外,K8s集群会监控Deployment的中Pod的状态,如果Pod因意外被删除,导致集群中的Pod数量低于期望的replicas,K8s会自动创建Pod,以达到yaml中对replicas的期望值。
  • spec下面的selector参数作用是“筛选”出要被 Deployment 管理的 Pod 对象,筛选的规则是通过下面的“matchLabels”字段,定义了 Pod 对象应该携带的 label。它必须和“template”里 Pod 定义的“labels”完全相同(指name相同的label值相同,不是要具有Pod所有的labels),否则 Deployment 就会找不到要控制的 Pod 对象,apiserver 也会告诉你 yaml 格式校验错误无法创建。
  • spec下面的template参数定义了pod应该是什么样的,它其实就是Pod资源对象中的内容。K8s会根据spec.replicas字段,创建出spec.replicas个Pod,每个Pod描述样子就是spec.template所描述的。

    我们将这个yaml模板spec下的replicas参数修改为3,然后保存为1.yml文件,执行如下命令在指定test命名空间下进行部署。


#使用yml文件在指定test命名空间下创建部署kubectl apply -f 1.yml -n test#查看部署kubectl get deploy nginx-deploy -n test#查看指定命名空间下的podkubectl get pods -n test#查看 Deployment 创建的 ReplicaSetkubectl get replicaSet -A#使用yam文件在指定test命名空间下删除部署kubectl delete -f 1.yml -n test
#在指定test命名空间下创建一个名为nginx的deployment部署kubectl create deployment nginx-deploy2 --image=nginx:alpine --port=8080 -n test#使用名字删除部署kubectl delete deployments.apps nginx-deploy2 -n test

    如图所示,因为spec下的replicas参数为3,所以创建了3个pod。

    此时删除指定的pod,可以看到,指定的pod确实删除了,但是又新生成了重新的pod。因为spec下的replicas参数值为3,所以这个deployment需要3个pod。


Namespace

    K8s使用命名空间实现集群内部的逻辑隔离,Namespace可实现容器隔离及一些权限控制等。Namespace用于对k8s中资源对象的分组。namespace之间没有嵌套或层级关系。一个资源对象只能属于一个namespace。不同组之间的对象是隔离的,互相不可见。

    以下是K8s安装完成后默认的一些namespace。

    注意:namespace无法保证网络的隔离性,比如说service可以跨namespace访问。

kube-system

    K8s系统自己运行所需的资源对象所在的namespace。

kube-public

    k8s自动创建的namespace,对所有用户可见。适合放置集群范围都可见的服务。kube-public 含有一个单一的 ConfigMap 对象 cluster-info,它有助于发现和安全引导。该命名空间默认不允许被删除。


kube-node-lease

    kube-node-lease 这个命名空间含有与每个节点关联的 Lease 对象。节点 lease 允许 kubelet 发送 heartbeat(心跳),以便控制平面(节点控制器)可以检测节点故障。那么,如果删除了 kube-node-lease,会发生什么?Kubernetes 通常会为每个节点创建另一个带有 Lease 对象的对象,但有时命名空间移除操作会在终止状态卡住。到那时我们会有一个节点 Lease,过时的 heartbeat 可能会告诉节点控制器:该节点访问不了,从而影响节点之间的整体通信。

default

    K8s默认的namespace,如果操作不指明namespace,默认会操作名为default的namespace。

kubernetes-dashboard

    如果安装了dashboard,那么该命名空间为dashboard所在的namespace。

    非常感谢您读到现在,由于作者的水平有限,编写时间仓促,文章中难免会出现一些错误或者描述不准确的地方,恳请各位师傅们批评指正。

    如果你想一起学习内网渗透、域渗透、云安全、红队攻防的话,可以加入下面的知识星球一起学习交流。