Dawn's Blogs

分享技术 记录成长

0%

Kubernetes学习 (9) 了解Kubernetes机理

架构

Components of Kubernetes

  • 控制平面(Control Plane)组件:控制平面组件会为集群做出全局决策,比如资源的调度、 以及检测和响应集群事件。

    • kube-apiserver:API 服务器,相当于控制平面的前端负责接受请求,可以水平扩容。

    • etcd:所有集群数据的后台数据库。

    • kube-scheduler:负责 Pod 的调度决策工作。

    • kube-controller-manager:负责运行控制器进程(控制器通过 API 服务器监控集群的公共状态,并致力于将当前的状态转换为期望的状态)。从逻辑上讲, 每个控制器都是一个单独的进程, 但是为了降低复杂性,它们都被编译到同一个可执行文件,并在同一个进程中运行。控制器包括但不限于:

      • 节点控制器:负责在节点出现故障时进行通知和响应。
      • 任务控制器:监测代表一次性任务的 Job 对象,然后创建 Pods 来运行这些任务直至完成。
      • 端点分片控制器:填充端点分片(EndpointSlice)对象(以提供 Service 和 Pod 之间的链接)。
      • 服务账号控制器:为新的命名空间创建默认的服务账号(ServiceAccount)。
    • cloud-controller-manager:仅运行特定于云平台的控制器。

  • Node 组件:节点组件会在每个节点上运行,负责维护运行的 Pod 并提供 Kubernetes 运行环境。

    • kubelet:在每一个节点上运行,用于管理运行在这个节点上的 Pod。

    • kube-proxy:是每一个节点上的网络代理,维护节点上的一些网络规则, 这些网络规则会允许从集群内部或外部的网络会话与 Pod 进行网络通信。

    • 容器运行时(Container Runtime):负责运行容器的软件。

组件间的分布式特性

组件之间的通信:在 Kubernetes 组件之间,只能通过 API 服务器进行通信,组件之间不会直接通信。

多实例保证可用性:为了保证高可用性,控制平面上的组件都是可以多实例运行的。其中,etcd 和 API 服务器都是可以多实例并行工作的。但是,同类型的调度器和控制器管理器只有一个实例起作用,其他实例均在待命。

组件运行方式:控制平面组件和 kube-proxy 都是直接在系统上运行或者作为 Pod 运行。kubelet 直接在系统上运行,把其他组件作为 Pod 运行。为了使得控制平面组件作为 Pod 运行,kubelet 也被部署在 master 上。

控制平面上的所有组件作为 Pod,在 master 节点上运行(master 节点上部署了 kubelet)。

Kubernetes 如何使用 Etcd

Etcd 是一个分布式、高可用的 kv 存储,唯一与 etcd 通信的就是 API 服务器,其他组件通过 API 服务器读写数据到 etcd 中,使用乐观锁机制进行并发写入控制。

Kubernetes API 服务器实现了乐观锁机制,所有资源都有一个 meta.resourceVersion 字段,当更新对象时,客户端返回这个值到 API 服务器,如果版本值与 etcd 不一致,则会拒绝更新。

Kubernetes 将资源的完整 Json 形式都存储在 etcd 中,etcd 是层级存储结构,kubernetes 的所有资源数据都在 etcd 的 /registry 下。

了解 API 服务器

API 服务器提供了 Restful API,用于对 Kubernetes 集群中的资源进行 CRUD 操作,并且将资源状态持久化到 etcd 中。

更改资源时 API 服务器做了什么

在 API 服务器收到一个 POST HTTP 请求后:

  • 利用认证插件认证客户端。API 服务器轮询认证插件,直到有一个插件能够认证客户端身份,包括客户端的用户名、用户 ID、用户组。
  • 通过授权插件授权客户端。授权插件根据用户名、用户 ID、用户组来决定是否授权客户端的操作,授权插件也有多个。
  • 通过准入控制插件修改资源请求。如果尝试修改、新建、删除资源,需要经过准入控制插件的验证。准入控制插件会初始化资源定义中漏配的字段为默认值,甚至修改不在请求中的相关资源,同时也会因为某些原因拒绝一个请求。
  • 持久化。之后会将资源状态的改变持久化到 etcd 中,然后给客户端一个响应。

image-20231003171103084

API 服务器通知客户端资源变更

API 服务器除了进行认证、授权、准入控制、持久化之外,没有做任何额外的工作。客户端(控制器管理器中的控制器、调度器等)可以通过 HTTP 订阅资源的变化,每当更新对象时,API 服务器会通知所有监听该对象的客户端。

image-20231003172249361

了解调度器

调度器利用 API 服务器的监听机制等待新创建的 Pod,为新的 Pod 分配节点。

调度器通过调度算法决定节点后,也不会直接去命令选中的节点去运行 Pod,而是利用 API 服务器改变 Pod 的状态。kubelet 同样通过监听机制监听到 Pod 需要调度到所在节点时,kubelet 就会创建并运行 Pod。

集群中可以运行多个不同类型的调度器,用户也可以自己去实现自己的调度器。如果没有设置调度器属性,那么 schedulerName 会被设置为 default-scheduler。

了解控制器管理器

顾名思义,控制器管理器用于管理控制器。控制器管理器管理的控制器包括 Replication 管理器、ReplicaSet 控制器、Deployment 控制器、DaemonSet 控制器、Job 控制器、Endpoint 控制器等。

控制器通过监听资源的变更,执行相应的操作,目的是将实际状态(status)调整为期望状态(spec)。控制器之间不会直接通信,只与 API 服务器进行通信,甚至不知道其他控制器的存在。

下面以创建 Deployment 为例,在 Kubernetes 中发生的事件。

image-20231005220803874

了解 kubelet

kubelet 服务器存在于数据平面上,它有以下作用:

  • 在 API 服务器上创建一个 Node 资源来注册该节点。
  • 持续监控 API 服务器是否把该节点分配给 Pod,在节点上启动 Pod 容器。并且负责删除 Pod 容器
  • 启动 Pod 容器后,持续向 API 服务器报告 Pod 的运行状态、事件和资源消耗
  • 运行容器存活探针的组件,当探针报错会重启容器。

了解 kube-proxy

在数据平面上的工作节点上,除了 kubelet 还运行着 kube-proxy。kube-proxy 的作用就是修改 iptables,确保网络包可以到达 Pod 处。

Kube-proxy 有两种模式:

  • userspace 代理模式:kube-proxy 通过修改 iptables 将数据包重定向到 kube-proxy 中,作为 客户端和 Pod 之间的代理
  • iptables 代理模式:kube-proxy 仅仅修改 iptables,将数据包直接重定向到 Pod 中。这种方式是现在的默认方式,效率更高。

Pod 网络

在 Kubernetes 中,节点内部容器运行时维护了一个虚拟网桥,每一个 Pod 与容器运行时的网桥之间都是一对 eth pair(和 docker 网络的 eth pair 差不多)。不同节点上的容器运行时虚拟网桥网段不重叠(可以使用 SDN),这样就可以保证 Pod 之间的 IP 地址不同。

Pod 之间的 IP 地址不同,可以确保 Pod 认为自己的 IP 地址与其他 Pod 认为的 IP 地址一致。

在 Pod 中的应用可以自己注册在其他 Pod 中。

image-20231005222504851

Service 如何实现

Service 用于暴露一系列的 Pod 到固定的 IP 地址和端口上,当 Pod 之间使用 Service 进行通信时,数据包被直接路由到 Pod(不经过控制平面的转发)。

  • 当一个 Service 被创建时,会立即分配一个虚拟 IP 地址给 Service。
  • 接着 API 服务器会通知所有运行在工作节点上的 kube-proxy 一个新的 Service 被创建。kuber-proxy 也会监控 Endpoint 对象的更改。
  • kube-proxy 会建立 iptables 路由规则,确保虚拟 IP 可以路由到某个 Pod 上。
  • 当 Pod A 中使用 svc 地址时,经过 iptables 会自动随机被重定向为某个 svc 背后的 Pod。

image-20231005224024481

命名空间

Pod 在默认情况下有自己的命名空间,如网络命名空间(这样 Pod 就有自己的地址)、PID 命名空间、IPC 命名空间。

可以在 spec 中设置,使用宿主节点的命名空间。