一、前言

前面已经完成了:Master(二进制方式)部署Worker Node 加入集群kubelet / kube-proxy 启动

但目前还存在问题(本篇将依次解决):

  1. 容器镜像拉取失败
  2. Pod 跨节点无法互通
  3. 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-110.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。


结语

本篇解决了三个关键问题:

  1. containerd 镜像源问题(pause 镜像 + docker hub)
  2. 手工 bridge CNI 下的跨节点路由问题
  3. Kubernetes Secret at-rest 加密验证

当前集群:

  • 可以正常创建 Pod
  • 可以跨节点通信
  • Secret 数据已加密存储

但网络仍然是“静态路由模型”。

下一篇将会部署网络插件并加入新 node 节点

Logo

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

更多推荐