从 0 到 1 理解 Kubernetes:一次“破坏式”学习实践(五)
一、前言
前面已经完成了:Master(二进制方式)部署、Worker Node 加入集群、kubelet / kube-proxy 启动 等
但目前还存在问题(本篇将依次解决):
- 容器镜像拉取失败
- Pod 跨节点无法互通
- etcd 中的 Secret 是否真正加密存储?
二、配置 containerd 镜像源
1. 创建测试 Pod
先测试一下:
kubectl create deployment nginx --image=nginx:latest
发现 Pod 创建失败:
kubectl describe pod xxx
# 报错:
failed to get sandbox image "registry.k8s.io/pause:3.10"...
2. 为什么会拉取 pause 镜像?
每个 Pod 在创建时,都会先启动一个:
Pause 容器(infra container)
它的作用:
- 作为 Pod 网络命名空间的持有者
- 维持 Pod 的生命周期
- 所有业务容器共享它的 netns
也就是说:每个 Pod 都必须先成功拉取 pause 镜像。
默认镜像地址是:registry.k8s.io/pause:3.10
国内网络通常无法访问。
3️. 修改 sandbox_image
在所有 Node 上执行:
vim /etc/containerd/config.toml
# 追加
[plugins."io.containerd.grpc.v1.cri"]
sandbox_image = "registry.aliyuncs.com/google_containers/pause:3.10"
解释:
- 这是 containerd CRI 插件使用的默认 Pod sandbox 镜像
- 不修改就无法创建 Pod
4. 配置 Docker Hub 镜像加速
再次创建:
kubectl create deployment nginx --image=nginx:latest
# 新报错
Warning Failed 5m25s kubelet Failed to pull image "nginx:latest": failed to pull and unpack image "docker.io/library/nginx:latest": failed to resolve reference "docker.io/library/nginx:latest": failed to do request: Head "https://registry-1.docker.io/v2/library/nginx/manifests/latest": read tcp 10.182.70.168:48242...
因为默认拉取地址是:https://registry-1.docker.io
创建 registry 加速配置
mkdir -p /etc/containerd/certs.d/docker.io
vim /etc/containerd/certs.d/docker.io/hosts.toml
# 写入
server = "https://registry-1.docker.io"
[host."https://docker.m.daocloud.io"]
capabilities = ["pull", "resolve"]
[host."https://dockerpull.com"]
capabilities = ["pull", "resolve"]
[host."https://atomhub.openatom.cn"]
capabilities = ["pull", "resolve"]
然后:
vim /etc/containerd/config.toml
# 追加
[plugins."io.containerd.grpc.v1.cri".registry]
config_path = "/etc/containerd/certs.d"
重启:
systemctl restart containerd
等一会 Pod 应该变成 Running 状态(Pod 会自动重启的)。
本地能直连访问 “外网”,但似乎没生效,也不做过多研究了。
三、静态路由配置
1️. 当前网络模型
你使用的是:
- bridge CNI
- host-local IPAM
- 手工分配 PodCIDR(/etc/cni/net.d/10-bridge.conf)
- 无 Flannel / Calico
每个 Node 有自己的:
cni0 网桥
# 如:
node-0 10.200.0.0/24
node-1 10.200.1.0/24
但 Linux 默认不知道:
10.200.1.0/24 在 node-1 上
因此:
node-0 无法访问 node-1 的 Pod。
node-0 和 node-1 的 Pod 之间也无法访问。
2️. hosts 和 route 的区别
明明前面在 hosts 里面,配置了相应地址,也能 ping 通
为什么这里还要单独配置静态路由呢,下面简单说明一下
hosts 作用
例如:
10.182.70.168 node-1 10.182.70.168 node-1
# 域名 → IP 解析
不参与路由,
这里的 node-1 和 10.182.70.168 node-1,只作为名字(域名),解析成 10.182.70.168 IP地址
route 作用
10.200.1.0/24 via 10.182.70.168
# 目标网段 → 下一跳
这是三层转发逻辑。
如果要访问 10.200.1.0/24 网段的地址,就得从 10.182.70.168 去找。
4️. 完整静态路由配置
在 Jumpbox 上操作:
{
SERVER_IP=$(grep server hosts.append | cut -d " " -f 1)
NODE_0_IP=$(grep node-0 hosts.append | cut -d " " -f 1)
NODE_0_SUBNET=$(grep node-0 hosts.append | cut -d " " -f 4)
NODE_1_IP=$(grep node-1 hosts.append | cut -d " " -f 1)
NODE_1_SUBNET=$(grep node-1 hosts.append | cut -d " " -f 4)
}
ssh root@server <<EOF
ip route add ${NODE_0_SUBNET} via ${NODE_0_IP}
ip route add ${NODE_1_SUBNET} via ${NODE_1_IP}
EOF
ssh root@node-0 <<EOF
ip route add ${NODE_1_SUBNET} via ${NODE_1_IP}
EOF
ssh root@node-1 <<EOF
ip route add ${NODE_0_SUBNET} via ${NODE_0_IP}
EOF
验证:
ssh root@server ip route
ssh root@node-0 ip route
以及分别在 node-0 和 node-1 上部署一个 Pod,互 Ping 对方
5️. 为什么不用 Flannel / Calico?
因为当前环境是:
手工二进制部署 + 最简 bridge CNI + host-local IPAM
没有部署任何真正的集群级网络插件(Overlay / 路由控制平面)。
当前网络模型的特点
- 每个 Node 独立维护自己的 Pod 网段
- 使用本地 bridge(cni0)
- 通过手工静态路由实现跨节点互通
- 没有自动路由传播机制
- 没有网络策略(NetworkPolicy)能力
本质上这是:
纯三层静态路由拼接出来的“伪集群网络”。
不使用 Flannel / Calico 的影响
如果不使用成熟 CNI 插件:
Pod 网络无法自动收敛
- 每新增一个 Node
- 所有已有节点都必须手工添加静态路由
无控制平面同步
- 不会自动读取 Node 的 PodCIDR
- 不会自动下发路由
扩容成本高
-
新增 Node =
- 配 hosts
- 配 bridge
- 配 IPAM
- 配静态路由(所有机器都要改)
无网络隔离能力
- 不支持 NetworkPolicy
- 无法实现命名空间级别流量控制
Flannel / Calico 会做什么?
它们本质上提供:
- PodCIDR 自动分配
- 路由自动传播
- VXLAN / BGP Overlay
- 网络收敛机制
- 网络策略支持
也就是说:
把“手工静态路由拼接”升级为“自动化分布式网络控制平面”。
四、Secret 加密验证(Encryption at Rest)
这是 Kubernetes 安全模型中的一部分:
验证 Secret 是否在 etcd 中以密文形式存储?
在 Jumpbox 上 操作:
kubectl create secret generic kubernetes-the-hard-way \
--from-literal="mykey=mydata"
直接读取 etcd:
ssh root@server \
'etcdctl get /registry/secrets/default/kubernetes-the-hard-way | hexdump -C'
# 打印
...k8s:enc:aescbc:v1:key1:...
说明:
- 使用 AES-CBC 加密
- 使用 encryption-config 中的 key1
- 数据已加密写入 etcd
注:这不是 etcd 加密,是 kube-apiserver 在 写入 etcd 前 加密。
流程:
kubectl
↓
kube-apiserver
↓(AES 加密)
etcd
如果没有开启 encryption-provider-config,etcd 中将直接存储明文 JSON。
结语
本篇解决了三个关键问题:
- containerd 镜像源问题(pause 镜像 + docker hub)
- 手工 bridge CNI 下的跨节点路由问题
- Kubernetes Secret at-rest 加密验证
当前集群:
- 可以正常创建 Pod
- 可以跨节点通信
- Secret 数据已加密存储
但网络仍然是“静态路由模型”。
下一篇将会部署网络插件并加入新 node 节点
更多推荐



所有评论(0)