前言

本篇主要部署:

  1. etcd(Kubernetes 的“数据库”)
  2. Control Plane(apiserver / controller-manager / scheduler)
  3. Worker Node(containerd / kubelet / kube-proxy / CNI)

它们之间的依赖关系是:

          +------------------+
          |   etcd (状态库)  |
          +--------+---------+
                   ^
                   |
+------------------+------------------+
|         Kubernetes API Server        |
+------------------+------------------+
        ^                   ^
        |                   |
controller-manager       scheduler
        ^
        |
     kubelet (node-0, node-1, ...)
        ^
        |
     container runtime + CNI + kube-proxy

让 node-0、node-1 成为可调度节点,并成功向控制平面注册。


一、etcd

简要说明

Kubernetes 的所有组件几乎都是无状态的,真正保存集群状态的地方只有一个:etcd

它存储的内容包括但不限于:

  • Pod 定义
  • Node 列表
  • Service / Endpoint
  • ConfigMap / Secret
  • RBAC 规则
  • Lease(选主)
  • 所有资源对象的期望状态与当前状态

如果把 Kubernetes 看作一个操作系统,那么:

etcd 就是它的硬盘。

kube-apiserver 本身并不保存任何数据,它只是一个 API 网关。所有写操作都会转发给 etcd。

  1. API Server 可以无状态扩容
  2. 数据层可单独做高可用

操作

在 jumpbox 上:

scp \
  downloads/etcd-v3.4.36-linux-amd64.tar.gz \
  units/etcd.service \
  root@server:~/
ssh root@server
  apt install -y tar
  tar -xvf etcd-v3.4.36-linux-amd64.tar.gz
  mv etcd-v3.4.36-linux-amd64/etcd* /usr/local/bin/
  mkdir -p /etc/etcd /var/lib/etcd
  chmod 700 /var/lib/etcd
  cp ca.crt kube-api-server.key kube-api-server.crt \
    /etc/etcd/
	
	mv etcd.service /etc/systemd/system/
	chmod 644 /etc/systemd/system/etcd.service

这步意义是(TLS 认证):

  • etcd 作为 HTTPS 服务端
  • kube-apiserver 作为客户端
  • 双向认证

启动

  systemctl daemon-reload
  systemctl enable etcd
  systemctl start etcd

检查状态

systemctl status etcd.service
etcdctl member list

# 示例输出:
6702b0a34e2cfd39, started, controller, ..., false

最后的 false 表示:

是否为 learner 节点(只同步日志,不参与 Raft 投票)

你这里是 单节点 etcd,因此是普通成员。

写入过程

创建一个 Pod 过程是这样的:

API Server 写入期望状态(我要一个 Pod)
→ 写入者:API Server
→ 写入内容:Pod 的 spec(镜像、资源、端口等期望配置)
→ 写入次数:通常 1 次(除非用户修改 Pod)

Scheduler 写入调度结果(这个 Pod 放到哪个 Node)
→ 写入者:Scheduler(通过 API Server)
→ 写入内容:spec.nodeName = node-x
→ 写入次数:1 次(正常情况下)

etcd 对象发生变化,通过 Watch(钩子)触发,由 API Server 会 推送事件给订阅者

Kubelet 写入运行状态(Pod 已经跑起来了)
→ 写入者:Kubelet(通过 API Server)
→ 写入内容:Pod 的 status(Pending / Running / Ready / Failed 等)
→ 写入次数:多次(状态变化一次写一次)

etcd 对象发生变化,通过 Watch(钩子)触发,由 API Server 会 推送事件给订阅者

API Server 负责写入期望状态,Scheduler 负责写入调度决策,Kubelet 负责持续写入实际运行状态。

三、Control Plane(Kubernetes API Server, Scheduler, and Controller Manager)

Control Plane 由三个核心组件构成:

组件 角色
kube-apiserver 集群唯一入口
controller-manager 状态调谐器
scheduler 资源调度器

1. kube-apiserver 简要说明

它是 Kubernetes 的中枢神经系统。

任何操作都必须经过它:

  • kubectl
  • kubelet 上报
  • controller 修改状态
  • scheduler 绑定 node

它负责:

  • 认证(Authentication)
  • 授权(Authorization)
  • 准入控制(Admission)
  • 校验(Validation)
  • 写入 etcd

2. scheduler 简要说明

为“未绑定 node 的 Pod”选择一个最合适的 node

它会考虑:

  • CPU
  • 内存
  • 亲和性
  • 污点 / 容忍
  • 负载
  • topology

3. controller-manager 简要说明

Controller Manager 就是集群状态的“自动运维机器人”,负责各类资源的自我修复和维护。
跟据写好期望状态(YAML),Controller Manager 负责自动修复和调度,Kubelet 负责执行。

controller-manager 不是一个程序,而是一堆 controller:

Controller 干嘛的
NodeController 监控 node 状态
ReplicaSetController 保证副本数
JobController 任务调度
ServiceAccountController 账号管理
EndpointController service 关联 pod

操作

在 jumpbox 上:

scp \
  downloads/kube-apiserver \
  downloads/kube-controller-manager \
  downloads/kube-scheduler \
  downloads/kubectl \
  units/kube-apiserver.service \
  units/kube-controller-manager.service \
  units/kube-scheduler.service \
  configs/kube-scheduler.yaml \
  configs/kube-apiserver-to-kubelet.yaml \
  root@server:~/
  ssh root@server
  mkdir -p /etc/kubernetes/config

  chmod +x kube-apiserver \
    kube-controller-manager \
    kube-scheduler kubectl

  mv kube-apiserver \
    kube-controller-manager \
    kube-scheduler kubectl \
    /usr/local/bin/

  mkdir -p /var/lib/kubernetes/

  mv ca.crt ca.key \
    kube-api-server.key kube-api-server.crt \
    service-accounts.key service-accounts.crt \
    encryption-config.yaml \
    /var/lib/kubernetes/

Kubernetes API Server

	mv kube-apiserver.service /etc/systemd/system/kube-apiserver.service

Kubernetes Controller Manager

	mv kube-controller-manager.kubeconfig /var/lib/kubernetes/
	mv kube-controller-manager.service /etc/systemd/system/

Kubernetes Scheduler

	mv kube-scheduler.kubeconfig /var/lib/kubernetes/
	mv kube-scheduler.yaml /etc/kubernetes/config/
	mv kube-scheduler.service /etc/systemd/system/

启动

  systemctl daemon-reload

  systemctl enable kube-apiserver \
    kube-controller-manager kube-scheduler

  systemctl start kube-apiserver \
    kube-controller-manager kube-scheduler

检验

systemctl status kube-apiserver kube-controller-manager kube-scheduler

kubectl cluster-info   --kubeconfig admin.kubeconfig

三、RBAC

简要说明

RBAC 就是 Kubernetes 的“门禁系统”,确保用户和组件只能访问允许的 API 和资源,保证集群操作安全可控。

在 Kubernetes 中,kubelet 也是一个 HTTP API 服务,它提供了多种接口,包括:

  • exec:在 Pod 容器里执行命令
  • logs:获取容器日志
  • metrics:采集节点/容器指标
  • Pod 状态:获取节点上 Pod 的当前状态

API Server 需要访问 kubelet 的原因:

  • 用户执行 kubectl logs 时,流程是:
    kubectl → apiserver → kubelet
  • 用户执行 kubectl exec 时,流程是:
    kubectl → apiserver → kubelet
  • 获取监控指标或 Pod 状态时,同样通过 API Server 访问 kubelet

Kubernetes 的安全模型核心原则:

所有访问 = API 调用,所有 API 调用都必须经过授权

RBAC 就是解决 “谁可以访问哪些 API、拥有哪些权限” 的问题。

  • kubectl 授权访问集群资源(本质是控制 apiserver 请求授权)
  • apiserver 授权访问各个 kubelet API

操作

在 jumpbox 上:

ssh root@server

向 Kubernetes 集群里创建 RBAC 权限配置对象

用于允许 kube-apiserver 以特定身份访问 kubelet 的 HTTPS 接口

kubectl apply -f kube-apiserver-to-kubelet.yaml \
  --kubeconfig admin.kubeconfig

可以查看 kube-apiserver-to-kubelet.yaml 都有什么权限

版本验证
用 curl 访问 kube-apiserver 的 HTTPS 接口

/version 是 匿名可访问接口,和上面没有因果关系
如果前面跟 “官方” 教程一样,那这里只能在 server 机子上操作

 curl -k --cacert ca.crt https://server.kubernetes.local:6443/version
{
  "major": "1",
  "minor": "32",
  "gitVersion": "v1.32.0",
  "gitCommit": "70d3.....",
  "gitTreeState": "clean",
  "buildDate": "2024-12-11T17:59:15Z",
  "goVersion": "go1.23.3",
  "compiler": "gc",
  "platform": "linux/amd64"
}

五、Worker Node

简要说明

Worker Node 是 Kubernetes 集群中真正运行业务负载的节点

它的主要职责是:

  • 运行 Pod / 容器(承载实际应用)
  • 接收并执行来自控制面的调度结果
  • 向控制面汇报 Pod 和节点的运行状态

一个 Worker Node 上通常包含:

组件 作用
containerd 运行容器
runc 真正创建 Linux 容器
CNI plugins 容器网络
kubelet node agent
kube-proxy service 转发
crictl 调试工具

操作

在 jumpbox 上:

for host in node-0 node-1; do
  SUBNET=$(grep $host hosts.append  | cut -d " " -f 4)
  sed "s|SUBNET|$SUBNET|g" \
    configs/10-bridge.conf > 10-bridge.conf 

  sed "s|SUBNET|$SUBNET|g" \
    configs/kubelet-config.yaml > kubelet-config.yaml

  scp 10-bridge.conf kubelet-config.yaml \
  root@$host:~/
done
for host in node-0 node-1; do
  scp \
    downloads/runc.amd64 \
    downloads/crictl-v1.32.0-linux-amd64.tar.gz \
    downloads/cni-plugins-linux-amd64-v1.6.2.tgz \
    downloads/containerd-2.0.3-linux-amd64.tar.gz \
    downloads/kubectl \
    downloads/kubelet \
    downloads/kube-proxy \
    configs/99-loopback.conf \
    configs/containerd-config.toml \
    configs/kubelet-config.yaml \
    configs/kube-proxy-config.yaml \
    units/containerd.service \
    units/kubelet.service \
    units/kube-proxy.service \
    root@$host:~/
done

这里又把 kubelet-config.yaml 覆盖了(官方误操作)

对比两份文件(kubelet-config.yaml)

diff kubelet-config.yaml kubelet-config.yaml.2
17c17
< podCIDR: "SUBNET"
---
> podCIDR: "10.200.0.0/24"

因为 kubelet 加入集群并不依赖 podCIDR,所以两个配置均能加入集群。

但整个教程里并没配置 CNI 插件(即:Flannel/Calico),所以 podCIDR 不会生效,教程里的是 “静态手工建网”(node 节点里的 10-bridge.conf 文件)

所以无论用哪个配置都一样,不会出现问题(因为读了 10-bridge.conf 就不会读 podCIDR

继续,两台 node 上操作:

ssh root@node-0
apt -y update
apt install -y socat conntrack ipset tar

关闭 swap(默认没开)

swapon --show
swapoff -a
sudo sed -i '/swap/s/^/#/' /etc/fstab
mkdir -p \
  /etc/cni/net.d \
  /opt/cni/bin \
  /var/lib/kubelet \
  /var/lib/kube-proxy \
  /var/lib/kubernetes \
  /var/run/kubernetes
  mkdir -p containerd
  tar -xvf crictl-v1.32.0-linux-amd64.tar.gz
  tar -xvf containerd-2.0.3-linux-amd64.tar.gz -C containerd
  tar -xvf cni-plugins-linux-amd64-v1.6.2.tgz -C /opt/cni/bin/
  mv runc.amd64 runc
  chmod +x crictl kubectl kube-proxy kubelet runc 
  mv crictl kubectl kube-proxy kubelet runc /usr/local/bin/
  mv containerd/bin/* /bin/
mv 10-bridge.conf 99-loopback.conf /etc/cni/net.d/

这个是 CNI(Container Network Interface),负责:

  • 给 Pod 分配 IP
  • 建 veth
  • 建 bridge
  • 路由
  • NAT
    10-bridge.conf 定义:
  • 用 bridge 模式
  • 哪个子网
  • 是否 NAT
    99-loopback.conf 给每个容器(Pod)分配 127.0.0.1

10-bridge.conf 里面定义了 pod 指向的本地网关(网桥 cni0)
首次创建 pod 时才会创建这个创建网桥
不同 node 节点间,网桥IP与分配网段不能重复

  mkdir -p /etc/containerd/
  mv containerd-config.toml /etc/containerd/config.toml
  mv containerd.service /etc/systemd/system/
  mv kubelet-config.yaml /var/lib/kubelet/
  mv kubelet.service /etc/systemd/system/
  mv kube-proxy-config.yaml /var/lib/kube-proxy/
  mv kube-proxy.service /etc/systemd/system/

关 selinux(如要)

sudo sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
setenforce 0
  systemctl daemon-reload
  systemctl enable containerd kubelet kube-proxy
  systemctl start containerd kubelet kube-proxy

最后检验

ssh root@server "kubectl get nodes --kubeconfig admin.kubeconfig"

NAME     STATUS   ROLES    AGE    VERSION
node-0   Ready    <none>   103s   v1.32.0
node-1   Ready    <none>   8s     v1.32.0

配置 kubectl 默认访问集群

在未配置默认 kubeconfig 的情况下,每次使用 kubectl 都需要显式指定配置文件,例如:

kubectl version --kubeconfig admin.kubeconfig

每次都指定参数很麻烦,下面提供两种常见方式配置默认 kubeconfig,任选其一即可

1. 直接替换默认 kubeconfig

cp admin.kubeconfig ~/.kube/config

kubectl 默认会读取 ~/.kube/config,复制完成后即可直接使用 kubectl 命令访问集群。

2. 通过 kubectl 命令手动配置

kubectl config set-cluster kubernetes-the-hard-way \
  --certificate-authority=ca.crt \
  --embed-certs=true \
  --server=https://server.kubernetes.local:6443

kubectl config set-credentials admin \
  --client-certificate=admin.crt \
  --client-key=admin.key

kubectl config set-context kubernetes-the-hard-way \
  --cluster=kubernetes-the-hard-way \
  --user=admin

kubectl config use-context kubernetes-the-hard-way

和前面创建 admin.kubeconfig 是一样的。

验证

完成配置后,直接执行:

kubectl version

输出示例如下,说明客户端已成功连接到 kube-apiserver:

Client Version: v1.32.0
Kustomize Version: v5.5.0
Server Version: v1.32.0

如果未配置 kubeconfig,直接执行 kubectl 会报错:

The connection to the server localhost:8080 was refused - did you specify the right host or port?

该报错并非 Kubernetes 服务异常,而是由于 kubectl 未找到有效的集群配置文件

结语

这里配置得七七八八了,剩下还有一些环境 CNI 之类的配置。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐