【Kubernetes】Master、Node、Pod

技术实践 · 03-04
【Kubernetes】Master、Node、Pod

资源对象

Node、Pod、Replication Controller、Service 等都可以被看做一种资源对象,几乎所有的资源对象都可以通过 Kubernetes 提供的 kubectl 工具 (或 API 变成调用)执行增删改查等操作,并将其保存在 etcd 中持久化存储。
所以,Kubernetes 其实是一个高度自动化的资源控制系统,他通过跟踪对比 etcd 库里保存的 “资源期望状态” 与 当前环境中的 “实际资源状态” 的差异来实现自动控制盒自动纠错的高级功能。

在声明一个 Kubernetes 资源对象的时候,有一个关键属性 apiVersion ,以下面的 Pod 声明为例:

apiVersion: v1 
kind: Pod 
metadata: 
    name: myweb 
    labels: 
        name: myweb 
spec: 
containers: 
- name: myweb 
  image: kubeguide/tomcat-app:v1 
  ports: 
    - containerPort: 8080

Kubernetes 平台采用的是 “核心 + 外围扩展” 的设计思路,保持平台核心稳定的同时,具备持续演进升级的优势。

Kubernetes 大部分常见的核心资源对象都归属于 v1 这个核心 API,比如 Node、Pod、Service、Endpoints、Namespace、RC、PersistentVolume 等。

在版本迭代过程中,Kubernetes 先后扩展了 extensions/v1beta1、apps/v1beta1、apps/v1beta2 等 API 组,而在 1.9 版本之后引入了 apps/v1 这个正式的扩展 API 组,正式淘汰(deprecated)了 extensions/v1beta1、apps/v1beta1、apps/v1beta2 这三个 API 组。

采用 YAML 或者 JSON 格式声明(定义或者创建)一个 Kubernetes 资源对象,每个资源对象都有自己的特定语法格式(数据库中一个特定的表),但随着 Kubernetes 版本的持续升级,一些资源对象会不断引入新的属性。

Master

Master 是 Kubernetes 集群的 控制节点,在每个 Kubernetes 集群离都需要有一个 Master 来负责整个集群的管理和控制,基本上 Kubernetes 的所有控制命令都发给他。

Master 负责具体的执行过程,后面执行的所有命令基本上都是在 Master 上运行的

Master 通常会占据一个独立的服务器(高可用部署建议 3 台服务器)。

在 Master 上运行着以下进程:

Master 的核心系统进程

  • kubelet:所有节点(包括 Master)上运行的主要节点代理
  • 容器运行时:containerd 或 Docker 的守护进程
  • kube-proxy:网络代理,实现 Kubernetes Service 概念

Master 控制平面组件(通常作为静态 Pod 运行)

  • kube-apiserver:Kubernetes API Server,提供了 HTTP Rest 接口的关键服务进程,是 Kubernetes 里所有资源的 增、删、改、查 等操作的 唯一入口,也是 集群控制的入口进程。所有组件通信的中枢
  • kube-controller-manager:Kubernetes Controller Manager,Kubernetes 里所有资源对象的自动化控制中心,可以理解为 资源对象的 ”大总管“。运行控制器进程,如节点控制器、副本控制器等
  • kube-scheduler:Kubernetes Scheduler,负责资源调度(Pod 调度)的进程,“调度室”,负责观察新创建的 Pod 并选择节点来运行他们
  • etcd:集群的数据存储,保持所有集群状态,Kubernetes 里所有的资源对象的数据都被保存在 etcd 中。

Master 节点上的附加组件(可能作为 Pod 或系统服务运行)

  • CoreDNS:提供集群内 DNS 服务
  • 网络插件:如 Calico、Flannel 或 Cilium 的相关进程
  • metrics-server:收集资源指标
  • dashboard:Web UI 界面(如果安装)

系统服务

  • systemd 服务:管理 kubelet 和其他系统组件
  • journald:日志收集服务
  • 常规 Linux 系统服务:如 SSH、cron 等

Node

除了 Master,Kubernetes 集群中的其他机器被称为 Node,较早的版本也成为 Minion。

Node 可以是一台物理主机,也可以是一台虚拟机。

Node 是 Kubernetes 集群中的工作负载节点,每个 Node 都会被 Master 分配一些工作负载(Docker 容器),当某个 Node 宕机时,其上的工作负载会被 Master 自动转移到其他节点上。

在每个 Node 上都运行着以下进程:

Node 上的核心进程

  • kubelet:负责 Pod 对应的容器的创建、启停等任务,同时与 Master 密切协作,实现集群管理的基本功能。
    • 是最重要的节点代理
    • 负责与容器运行时交互,管理 Pod 的生命周期
    • 监控分配到节点的 Pod,确保它们按照 PodSpec 运行
    • 向 API 服务器报告节点和 Pod 状态
  • kube-proxy:实现 Kubernetes Service 的通信与负载均衡机制的重要组件
    • 负责维护节点的网络规则
    • 处理集群内部的网络通信
    • 支持不同的代理模式(iptables / IPVS)
  • Docker Enginecontainerd:Docker 引擎 / 容器运行时,负责本机的容器创建和管理工作。
    • 负责容器的实际运行
    • 镜像管理和存储
    • 在 K8s 1.24 版本之前 Node 节点通常需要运行 Docker Engine,Docker Engine 通过 dockershim 与 kubelet 交互
    • 在 K8s 1.24 版本及以后,不需要运行 Docker Engine,直接使用容器运行时。
    • containerd 相比 Docker Engine 性能更好,减少了一层抽象,资源消耗更少,架构更简单易于维护
    • 生产环境建议可以直接使用 containerd 作为容器运行时,可以直接使用 crictl 命令工具管理容器
    • 即使不用 Docker Engine,仍然可以运行 Docker 容器镜像,因为这些镜像遵循 OCI(开放容器倡议)标准,可以背任何兼容的容器运行时使用。

Node 上的网络组件

  • CNI 插件进程:
    • 如 Calico、Flannel、Cilium 或 Weave 的代理程序
    • 负责 Pod 网络配置和跨节点通信
    • 实现网络策略(如果支持

Node 上的监控和日志组件

  • 节点级监控代理
    • node_exporter(Prometheus)
    • 收集节点级别的指标
  • 日志收集代理
    • 如 Fluentd、Filebeat 等
    • 收集容器和系统日志

Node 上的系统服务

  • systemd 服务:管理 kubelet 和其他系统组件
  • journald:系统日志服务
  • 常规 Linux 系统服务:如 SSH、cron 等

Node 上的工作负载容器

  • 用户应用容器:实际运行的业务应用
  • Pause 容器:每个 Pod 的基础容器,持有网络命名空间
  • 边车容器:如服务网格代理(Istio、Linkerd)

Node 可以在运行期间动态增加到 Kubernetes 集群中,前提是在这个节点上已经正确安装、配置和启动了上述关键进程。

在默认情况下 kubelet 会向 Master 注册自己,同时也是 Kubernetes 推荐的 Node 管理方式。

一旦 Node 被纳入集群管理范围,kubelet 进程就会定时向 Master 汇报自身的情报,如 操作系统、Docker 版本、机器的 CPU 和内存情况,以及 当前有哪些 Pod 在运行等。这样 Master 就可以获知每个 Node 的资源使用情况,并实现高效均衡的资源调度策略。

某个 Node 在超过指定时间不上报信息时,会被 Master 判定为 “失联”,Node 的状态被标记为 不可用(Not Ready),随后 Master 会触发 “工作负载大转移” 的自动流程。

查看集群中有多少 Node

可以通过以下命令查看 集群中有多少个 Node:

kubectl get nodes

image

查看某个 Node 的详细信息

通过以下命令查看 某个 Node 的详细信息

kubectl describe node node1

内容如下

Name:               node1
Roles:              control-plane
Labels:             beta.kubernetes.io/arch=amd64
                    beta.kubernetes.io/os=linux
                    kubernetes.io/arch=amd64
                    kubernetes.io/hostname=node1
                    kubernetes.io/os=linux
                    node-role.kubernetes.io/control-plane=
                    node.kubernetes.io/exclude-from-external-load-balancers=
Annotations:        kubeadm.alpha.kubernetes.io/cri-socket: unix:///var/run/containerd/containerd.sock
                    node.alpha.kubernetes.io/ttl: 0
                    projectcalico.org/IPv4Address: 192.168.25.72/22
                    projectcalico.org/IPv4VXLANTunnelAddr: 10.234.168.1
                    volumes.kubernetes.io/controller-managed-attach-detach: true
CreationTimestamp:  Thu, 20 Feb 2025 06:28:51 +0000
Taints:             <none>
Unschedulable:      false
Lease:
  HolderIdentity:  node1
  AcquireTime:     <unset>
  RenewTime:       Mon, 03 Mar 2025 06:32:04 +0000
Conditions:
  Type                 Status  LastHeartbeatTime                 LastTransitionTime                Reason
        Message
  ----                 ------  -----------------                 ------------------                ------
        -------
  NetworkUnavailable   False   Thu, 20 Feb 2025 06:30:05 +0000   Thu, 20 Feb 2025 06:30:05 +0000   CalicoIsUp
        Calico is running on this node
  MemoryPressure       False   Mon, 03 Mar 2025 06:32:04 +0000   Thu, 20 Feb 2025 06:28:49 +0000   KubeletHasSufficientMemory   kubelet has sufficient memory available
  DiskPressure         False   Mon, 03 Mar 2025 06:32:04 +0000   Thu, 20 Feb 2025 06:28:49 +0000   KubeletHasNoDiskPressure     kubelet has no disk pressure
  PIDPressure          False   Mon, 03 Mar 2025 06:32:04 +0000   Thu, 20 Feb 2025 06:28:49 +0000   KubeletHasSufficientPID      kubelet has sufficient PID available
  Ready                True    Mon, 03 Mar 2025 06:32:04 +0000   Thu, 20 Feb 2025 06:31:15 +0000   KubeletReady
        kubelet is posting ready status. AppArmor enabled
Addresses:
  InternalIP:  192.168.25.72
  Hostname:    node1
Capacity:
  cpu:                4
  ephemeral-storage:  102626232Ki
  hugepages-2Mi:      0
  memory:             8136068Ki
  pods:               110
Allocatable:
  cpu:                4
  ephemeral-storage:  94580335255
  hugepages-2Mi:      0
  memory:             8033668Ki
  pods:               110
System Info:
  Machine ID:                 b789b3370e69479f907f0c605dd54107
  System UUID:                b789b337-0e69-479f-907f-0c605dd54107
  Boot ID:                    b0a92107-4cf1-42ab-bdc7-17b6902b56e1
  Kernel Version:             5.4.0-205-generic
  OS Image:                   Ubuntu 20.04.5 LTS
  Operating System:           linux
  Architecture:               amd64
  Container Runtime Version:  containerd://1.6.19
  Kubelet Version:            v1.26.4
  Kube-Proxy Version:         v1.26.4
PodCIDR:                      10.234.0.0/23
PodCIDRs:                     10.234.0.0/23
Non-terminated Pods:          (17 in total)
  Namespace                   Name                                        CPU Requests  CPU Limits  Memory Requests  Memory Limits  Age
  ---------                   ----                                        ------------  ----------  ---------------  -------------  ---
  default                     mysql-8n5ss                                 0 (0%)        0 (0%)      0 (0%)           0 (0%)         3d21h
  default                     myweb-4t4rj                                 0 (0%)        0 (0%)      0 (0%)           0 (0%)         2d21h
  default                     myweb-mnlxr                                 0 (0%)        0 (0%)      0 (0%)           0 (0%)         2d21h
  default                     netchecker-agent-5wkcf                      15m (0%)      30m (0%)    64M (0%)         100M (1%)      11d
  default                     netchecker-agent-hostnet-w2bdc              15m (0%)      30m (0%)    64M (0%)         100M (1%)      11d
  default                     netchecker-server-67c989ccbb-2hfdd          150m (3%)     300m (7%)   192M (2%)        512M (6%)      11d
  kube-system                 calico-kube-controllers-7967fb4566-7v5f7    30m (0%)      1 (25%)     64M (0%)         256M (3%)      11d
  kube-system                 calico-node-gc8j5                           150m (3%)     300m (7%)   64M (0%)         500M (6%)      11d
  kube-system                 coredns-55859db765-5w4rc                    100m (2%)     0 (0%)      70Mi (0%)        300Mi (3%)     11d
  kube-system                 dns-autoscaler-998c74f6b-b4mml              20m (0%)      0 (0%)      10Mi (0%)        0 (0%)         11d
  kube-system                 kube-apiserver-node1                        250m (6%)     0 (0%)      0 (0%)           0 (0%)         11d
  kube-system                 kube-controller-manager-node1               200m (5%)     0 (0%)      0 (0%)           0 (0%)         11d
  kube-system                 kube-proxy-742df                            0 (0%)        0 (0%)      0 (0%)           0 (0%)         11d
  kube-system                 kube-scheduler-node1                        100m (2%)     0 (0%)      0 (0%)           0 (0%)         11d
  kube-system                 metrics-server-556d5d785-krfxq              100m (2%)     100m (2%)   200Mi (2%)       200Mi (2%)     11d
  kube-system                 nodelocaldns-6xctx                          100m (2%)     0 (0%)      70Mi (0%)        200Mi (2%)     11d
  kuboard                     kuboard-v3-node1                            0 (0%)        0 (0%)      0 (0%)           0 (0%)         11d
Allocated resources:
  (Total limits may be over 100 percent, i.e., overcommitted.)
  Resource           Requests        Limits
  --------           --------        ------
  cpu                1230m (30%)     1760m (44%)
  memory             815001600 (9%)  2202003200 (26%)
  ephemeral-storage  0 (0%)          0 (0%)
  hugepages-2Mi      0 (0%)          0 (0%)
Events:              <none>

以上内容:

  • Node 基本信息:名称、标签、创建时间等image
  • Node 当前的运行状态:Node 启动后会做一系列的自检工作,
    • DiskPressure 磁盘空间是否不足
    • MemoryPressure 内存是否不足
    • NetworkUnavailable 网络是否正常
    • PIDPressure PID 资源是否充足
    • 在一切正常时设置 Node 为 Ready 状态(Ready=True),表示 Node 出于健康状态,Master 将可以在其上调度新的任务了(如,启动 Pod)
      image
  • Node 的主机地址与主机名
  • Node 上的资源数量:
    • Node 可用的系统资源,包括 CPU、内存数量、最大可调度 Pod 数量等
    • image
  • Node 可分配的资源量:描述 Node 当前可用于分配的资源量
    image
  • 主机系统信息:
    • 主机 ID
    • 系统 UUID
    • Linux kernel 版本号
    • 操作系统类型与版本
    • 容器运行时版本号
    • kubelet 与 kube-proxy 版本号
      image
  • 当前运行的 Pod 列表概要信息image
  • 已分配的资源使用概要信息,如 资源申请的最低、最大允许使用量占系统总量的百分比image
  • Node 相关的 Event 信息image

containerd 容器运行时

containerd 是一个工业级标准的容器运行时,原本是 Docker 的核心组件,后来被分离出来成为独立项目,现在由 CNCF (Cloud Native Computing Foundation) 托管。

containerd 的架够层次如下:
Kubernetes —> kubelet —> CRI 插件 —> containerd —> runc

  • kubelet 通过 CRI(容器运行时接口)与 containerd 通信
  • containerd 负责容器的生命周期管理
  • 最终通过 runc 来创建和运行容器

containerd 主要功能:

  • 镜像管理(拉取、推送、删除)
  • 容器生命周期管理(创建、启动、停止、删除)
  • 存储管理
  • 网络接口

containerd 的常用工具:

  • crictl:替代了 docker CLI 的命令行工具
  • ctr:containerd 的原生命令行工具
  • nerdctl:功能更完善的 containerd 客户端工具

Pod

Pod 是 Kubernetes 最重要的基本概念,每个 Pod 都有一个特殊的被称为 “根容器” 的 Pause 容器。
Pause 容器对应的镜像属于 Kubernetes 平台的一部分,除了 Pause 容器,每个 Pod 还包含一个或多个紧密相关的用户业务容器image

为什么会有 Pod 这个概念

在一组容器作为一个单元的情况下,难以简单地对“整体”进行判断及有效地行动。
比如,一个容器死亡了,此时算是整体死亡吗?是 N/M 的死亡率吗?引入业务无关并且不易死亡的 Pause 容器作为 Pod 的根容器,以它的状态来代表整个容器组的状态,可以解决上述问题。

Pod 里的多个业务容器共享 Pause 容器的 IP,共享 Pause 容器挂接的 Volume,简化了密切关联的业务容器之间的通信问题,也很好地解决了业务容器间的文件共享问题。

Kubernetes 为每个 Pod 都分配了唯一的 IP 地址,称之为 Pod IP,一个 Pod 里的多个容器共享 Pod IP 地址。Kubernetes 要求底层网络支持集群内任意两个 Pod 之间的 TCP/IP 直接通信,这通常采用 虚拟二层网络技术来实现(Flannel、Open vSwitch 等)。

在 Kubernetes 里,一个 Pod 里的容器与另外主机上的 Pod 容器能够直接通信。

Pod 类型

Pod 有两种类型:普通的 Pod 及 静态 Pod(Static Pod)

image

静态 Pod

静态 Pod 比较特殊,并没有被存放在 Kubernetes 的 etcd 存储里,而是被 存放在某个具体的 Node 上的一个具体文件中,并且只在此 Node 上启动、运行。

静态 Pod 不通过 Kubernetes API 服务器管理,而是直接由特定节点上的 kubelet 进程管理。
静态 Pod 的配置文件通常会存放在 Node 上的特定目录中,这个目录是 kubelet 的配置参数 --pod-manifest-path 所制定的路径。
在大多数的 Kubernetes 部署中,这个默认路径是: /etc/kubernetes/manifests/ 或者 /etc/kubelet.d/

kubelet 会定期扫描配置的静态 Pod 目录

kubelet 对静态 Pod 的生命周期管理

当发现新的 Pod 定义文件时,kubelet 会自动创建并启动对应的 Pod;
当文件被修改时,kubelet 会重新创建 Pod
当文件被删除时,kubelet 会终止对应的 Pod

kubelet 会为每个静态 Pod 在 Kubernetes API 服务器中创建一个 Pod 对象( mirror Pod),这个镜像对象是 只读 的,不能通过 API Server 修改或删除

静态 Pod 的特点

  • 只依赖于特定节点上的 kubelet,不依赖于 Kubernetes API 服务器
  • 即使 API 服务器不可用,静态 Pod 也能正常运行
  • 通常用于部署控制平面组件(如 kube-apiserver、kube-controller-manager、kube-scheduler 等)
  • 无法使用 Deployment、DaemonSet 等控制器管理
  • 不支持健康检查、滚动更新等高级功能

静态 Pod 的创建方式

静态 Pod 是通过将 Pod 定义文件放置在特定节点的指定目录中来创建的:

sudo cp myweb-pod.yaml /etc/kubernetes/manifests/
  • 直接由特定节点上的 kubelet 管理,不经过 API 服务器

普通 Pod

普通的 Pod 一旦被创建,就会被放入 etcd 中存储,随后会被 Kubernetes Master 调度到某个具体的 Node 上并进行绑定(Binding),随后该 Pod 被对应的 Node 上的 kubelet 进程实例化成一组相关的 Docker 容器并启动。

默认情况下,当 Pod 里的某个容器停止时,Kubernetes 会自动检测到问题,并且重新启动这个 Pod(重启 Pod 里的所有容器)

如果 Pod 所在的 Node 宕机,就会将这个 Node 上的所有 Pod 重新调度到其他节点上。

创建一个普通 Pod

可以采用 YAML 或者 JSON 格式的文件来定义或者描述,如:

apiVersion: v1 
kind: Pod 
metadata: 
    name: myweb 
    labels: 
        name: myweb 
    spec: 
        containers: 
        - name: myweb 
          image: kubeguide/tomcat-app:v1 
          ports: 
          - containerPort: 8080 
          env: 
          - name: MYSQL_SERVICE_HOST 
            value: 'mysql' 
          - name: MYSQL_SERVICE_PORT 
            value: '3306'

这是一个创建普通 Pod 的 YAML 定义文件

  • kind 为 Pod 表明这是一个 Pod 的定义
  • metadata 里的
    • name 属性为 Pod 名称
    • 定义一个 name=myweb 的标签
  • Pod 里面所包含的容器组的定义,在 spec 中声明
    • 定义了一个名为 myweb、对应镜像为 kubeguide/tomcat-app:v1 的容器
    • 该容器注入了 名为 MYSQL_SERVICE_HOST='mysql'MYSQL_SERVICE_PORT='3306 的环境变量(env 关键字)
    • 并且在 8080 端口(containerPort)启动容器进程
  • 容器端口 containerPort
    • Endpoint:代表此 Pod 里的一个服务进程的对外通信地址
    • 一个 Pod 里面也存在具有多个 Endpoint 的情况,比如我们把 Tomcat 定义为一个 Pod 时,可以对外暴露管理端口与服务端口这两个 Endpoint

静态 Pod 与普通 Pod 一些主要区别(操作上)

特性 静态 Pod 普通 Pod
创建方式 通过文件系统上的清单文件 通过 API 服务器
管理者 直接由 kubelet 管理 由控制平面组件协作管理
调度 无调度,固定在特定节点 由 kube-scheduler 动态调度
依赖性 仅依赖 kubelet 和容器运行时 依赖完整的控制平面
可见性 在 API 服务器中有只读镜像 完全可见且可管理
更新方式 修改/替换清单文件 通过 API 服务器更新
删除方式 从清单目录移除文件 通过 API 服务器删除
命名规则 自动添加节点名称后缀 按用户指定名称创建

一个很简单的区分方式:

  • 如果是通过 kubectl apply 创建的就是 普通的 pod
  • 如果选择将定义文件放在特定的目录 /etc/kubernetes/mainfests/ 的不走 kubectl 的是 静态pod

静态 Pod 与 普通 Pod 的实际应用场景

静态 Pod 适用于

  • 控制平面组件(避免循环依赖)
  • 需要在特定节点上始终运行的关键服务
  • 不依赖 API 服务器的基础设施组件

普通 Pod 适用于

  • 常规应用工作负载
  • 需要调度灵活性的服务
  • 需要使用高级 Kubernetes 功能的应用

Event

Event 是一个四件的记录,记录了事件的最早产生时间、最后重现时间、重复次数、发起者、类型,以及导致此事件的原因等众多信息。

可以通过以下命令查看 Node / Pod 的 Event

kubectl describe pod <podname> # pod
kubectl describe node <nodename> # node

资源配额

每个 Pod 都可以对其能使用的服务器上的计算资源设置限额,当前可以设置限额的计算资源有 CPU 和 Memory 两种。
CPU 的资源单位是 CPU(Core)的数量,是一个绝对值而非相对值。

一个 CPU 的资源配额相当大,所以在 Kubernetes 里通常以 千分之一 的 CPU 配额为最小单位,用 m 来表示。

通常一个容器的 CPU 配额被定义为 100~300m,即占用 0.1~0.3 个 CPU

由于 CPU 配额是一个绝对值,所以无论在拥有一个 Core 的机器上,还是在拥有 48 个 Core 的机器上,100m 这个配额所代表的 CPU 的使用量都是一样的。

与 CPU 配额类似,Memory 配额也是一个绝对值,单位是 内存字节数

资源配额设置

一个计算资源进行配额限定时需要设定以下两个参数:

  • Requests:该资源的最小申请量,系统必选满足要求
  • Limits:该资源最大允许使用的量,不能被突破,当容器试图使用超过这个量的资源时,可能会被 Kubernetes “杀掉”并重启。

通常会把 Requests 设置为一个较小的值,符合容器平时的工作负载情况下的资源需求,把 Limit 设置为 峰值负载情况下资源占用的最大量。

References

  • claude 3.5 sonnet
  • claude 3.7 sonnet
  • Kubernetes 权威指南:从 Docker 到 Kubernetes 实践全接触(第 4 版)
Kubernetes
  1. tl.s 31 天前

    写的很详细,赞👍

粤ICP备2024349207号