从 0 到 1 理解 Kubernetes:一次“破坏式”学习实践(四)
前言
本篇主要部署:
- etcd(Kubernetes 的“数据库”)
- Control Plane(apiserver / controller-manager / scheduler)
- 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。
- API Server 可以无状态扩容
- 数据层可单独做高可用
操作
在 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授权访问各个kubeletAPI
操作
在 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 之类的配置。
更多推荐


所有评论(0)