kubernetes 理论知识点汇总

环境信息

  • Kubernetes 1.29

kubeadm 初始化集群

Network setup

组件的 advertise IP 地址选择

Kubernetes 中的组件(如 KubeadmKube-apiserver 等)在初始化启动时,都需要在节点(主机)上找到一个合适的 IP 作为组件的 advertising/listening 的地址。[1]

默认情况下,此 IP 是主机上默认路由对应的网卡所在的 IP。

# ip route show
default via 172.31.16.1 dev eth0
10.244.1.0/24 via 10.244.1.0 dev flannel.1 onlink
10.244.2.0/24 via 10.244.2.0 dev flannel.1 onlink
10.244.3.0/24 via 10.244.3.0 dev flannel.1 onlink
10.244.4.0/24 via 10.244.4.0 dev flannel.1 onlink
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
172.31.16.0/20 dev eth0 proto kernel scope link src 172.31.26.11

如果系统上有多个默认路由,组件会尝试使用第一个默认路由对应的网卡所在的 IP。如果系统上没有默认路由,并且未明确为组件配置 IP,组件会初始化失败并退出

组件选择的 IP 地址将会作为 X.509 证书的 SAN(Subject Alternative Name) 的一部分。因此在系统初始化运行之后修改 IP 需要重新签发证书并重启相关组件。

Pod 网段选择

Pod 的网段必须不能和主机网络重叠,如果选用的网络插件的网络和主机的网段重叠,必须为网络插件选择合适的和主机不同的网段,在集群初始化时通过参数 --pod-network-cidr 配置,并在安装网络插件时在其 YAML 文件中修改为对应的网段。 [4]

control-plane-endpoint 参数说明

--control-plane-endpoint 选项用来配置 api-server 的共享地址,可以是域名或者负载均衡器的 IP。 [2]

如果是单主节点的 Kubernetes 集群,想要扩展成为多个 Master 节点(高可用),初始化时没有 --control-plane-endpoint,是不被支持的。

因此为了后期可以由单个 Master 节点扩展为多个 Master 节点,即高可用,初始化节点时,建议加上此选项配置 api-server 的负载均衡地址。

<– more –>

admin.conf 的重要性

kubeadm init 初始化集群成功后,会产生一个 kubeconfig 文件 /etc/kubernetes/admin.conf,此配置中包含了一个绑定到 cluster-admin 的 ClusterRole 的组,其拥有对整个集群的控制权,不要将其共享给任何人[3]

kubeadm init 初始化集群成功后,同时会生成一个名为 super-admin.confkubeconfig 文件,其中配置的超级用户可以跳过 authorization layer,比如 RBAC。不要将其共享给任何人。建议将其保存在一个安全的位置。

Node

节点名称

在 Kubernetes 集群中,节点名称(Node Name)唯一的标识一个节点。在一个集群中,不能有多个名称一样的节点,Kubernetes 系统默认同一个 节点名(Node Name) 的实例将具有同样的一个状态和属性 [7]

配置节点为不可调度

将节点标记为 不可调度(unschedulable ) 会阻止系统调度新的 Pod 到节点上,但是不会影响节点上已有的 Pod。

Labels Selectors Annotations

Label 主要用来给 Kubernetes 中的对象添加 可识别属性。 Label 可以提供高效的查询和匹配以选择 Kubernetes 中的对象,Lables 可以在对象创建时或者运行过程中随时做变更。

不具有识别属性的信息 不建议用作 Labels,而是应该写入 Annotations 中。[5]

Label Key 由 2 部分构成:

  • (可选的)前缀。系统组件(如 kube-scheduler, kube-controller-manager, kube-apiserver, kubectl) 或者第三方自动化组件为对象添加 labels 时必须带有前缀(prefix)。kubernetes.io/ and k8s.io/ 是为 Kubernetes 核心系统保留的前缀
  • (必须的)名字。

    Annotations 的 Key 命名规则和 Label Key 基本一致 [6]

Label select 用法说明

集群间通讯流量说明

API Server 到 kubelet

API Server 请求 kubelet 的主要目的包括: [8]

  • 获取到 Pods 的日志
  • (比如使用 kubectl) Attach 到 Pods 中的容器
  • 提供 kubelet 的端口转发功能。

默认情况下,API 服务器不检查 kubelet 的服务证书。这使得此类连接容易受到中间人攻击, 在非受信网络或公开网络上运行也是 不安全的
为了对这个连接进行认证,使用 --kubelet-certificate-authority 标志给 API 服务器提供一个根证书包,用于 kubelet 的服务证书。

API Server 到 nodes, pods 和 services

从 API 服务器到节点、Pod 或服务的连接默认为纯 HTTP 方式,因此既没有认证,也没有加密。 这些连接可通过给 API URL 中的节点、Pod 或服务名称添加前缀 https: 来运行在安全的 HTTPS 连接上。 不过这些连接既不会验证 HTTPS 末端提供的证书,也不会提供客户端证书。 因此,虽然连接是加密的,仍无法提供任何完整性保证。 这些连接 目前还不能安全地 在非受信网络或公共网络上运行。 [8]

Kubernetes 支持使用 SSH tunnels 来加密从 API 到 nodes 的链接(目前已经处于废弃状态,推荐使用 Konnectivity service 替代)。

Leases

Kubernetes 使用 Lease API 来更新 kubelet 发送到 Kubernetes API Server 的心跳信息。Kubernetes 中的每一个节点在 kube-node-lease Namespace 中都有一个 Lease Object。kubelet 向系统上报心跳的过程,就是在更新对应的 Lease Object 的 spec.renewTime 字段,Kubernetes 控制平面会使用这个上报的时间戳来决定节点是否可用 [9]

# kubectl describe lease -n kube-node-lease k8s-admin
Name: k8s-node1
Namespace: kube-node-lease
Labels: <none>
Annotations: <none>
API Version: coordination.k8s.io/v1
Kind: Lease
Metadata:
Creation Timestamp: 2023-09-07T09:54:15Z
Managed Fields:
API Version: coordination.k8s.io/v1
Fields Type: FieldsV1
...
Owner References:
API Version: v1
Kind: Node
Name: k8s-node1
UID: db3dafee-1232-4c07-a1c6-524f86a96fbe
Resource Version: 46696081
UID: 053d9b79-81be-4f3f-801e-09192012c822
Spec:
Holder Identity: k8s-node1
Lease Duration Seconds: 40
Renew Time: 2024-02-03T02:30:11.760176Z
Events: <none>

Leases 也被用来确保 HA 的组件(类似 kube-controller-managerkube-scheduler)在同一时刻只有一个实例提供服务,其他实例处于备用状态 [9]

kubelet

串行和并行拉取镜像

Kubelet 默认(同一个节点)串行的拉取镜像,即同一时间只发送一个拉取镜像的请求到 Registry Server,其他的拉取镜像的请求保持等待,直到当前请求处理完成。多个节点上的镜像拉取请求是隔离的,即不同的节点在同一时间是并行的拉取镜像的。 [10]

如果要配置一个节点上的 Kubelet 并行的拉取镜像,可以在 kubelet 的配置中配置 serializeImagePullsfalse,前提是 Registry Server 和 CRI 支持并行拉取镜像。

Pod

Pod 状态

Pod 的状态字段(status) 是一个 PodStatus Object。其中包含 phase 字段。phase 字段描述/记录了 Pod 在其整个生命周期中所处的阶段 [11]

phase 字段可以有以下值:

Value Description
Pending Kubernetes 集群已经接收到创建 Pod 的请求,并且开始调度到节点、下载容器镜像并启动容器,但是有一个或多个容器还未正常运行
Running Pod 已经被调度到某个节点,并且 Pod 中所有的容器已经被创建,至少其中的一个容器已经处于运行状态或重启中
Succeeded Pod 中所有的容器都已经成功终止,并且不会再被重启
Failed Pod 中所有的容器都被终止,但至少有一个容器终止失败,也就是说,容器要么以非零状态码退出或者是被系统终止
Unknow 因为某些原因,Pod 的状态获取不到。这个经常发生在和 Pod 运行的节点通信异常时

Pod 中的容器的状态

Kubernetes 会跟踪 Pod 中每个容器的状态。一旦通过 Scheduler 将 Pod 分配到某个 Node,Kubernetes 会通过 CRI 创建 Pod 中的容器。

在 Kubernetes 中,容器可以有以下 3 种状态 [11]

Value Description
Waiting 表示容器正在进行必要的操作以正常启动,比如拉取镜像、应用 Secret 数据等。当容器处于此状态时,可以通过 kubectl describe pod 查看输出中对应容器的信息,一般会包含一个 Reason 字段简述 Waiting 的原因
Running 表示容器在正常运行
Terminated 表示容器运行结束或者因为某些原因失败。详细信息可以通过 kubectl describe pod 查看

QoS

Kubernetes 会根据 Pod 定义中的 resource requests and limits 将 Pod 划归到某一个 QoS 类中,Kubernetes 将会根据 QoS 类来决定在节点资源不足的情况下,哪些 Pod 将会被优先驱逐(Evict)。目前存在的 QoS 类主要有以下三个 [12]

QoS Class 说明 被驱逐权重
Guaranteed Pod 中的 每个容器必须定义 CPU & Mem requestlimit,并且 request 的值等于 limit 的值,确保系统会预留定义的资源给 Pod 和其中的容器 最后被驱逐
Burstable Pod 中 至少有一个容器定义了 CPU Mem 的 request。可以不定义 limit如果未定义 limit,默认可以使用节点上所有可用的资源 中间级别
BestEffort 未定义任何 CPU Mem 的 requestlimit 最先被驱逐

Memory QoS 基于系统内核的 cgroup v2 实现 [12]

Pod 中如果有个容器因为 Limit 被 kill,系统只会 kill 掉这一个容器并重启之,不会影响其他容器

脚注