3. 多集群 K8s 环境搭建:使用 Kind 与 K3s 模拟双集群

在服务网格与多集群发布流水线的学习与验证阶段,我们无法直接使用生产级物理或云上集群。因此,本章将指导你使用 Kind(Kubernetes in Docker)与 K3s(轻量级 K8s 发行版)在本地快速搭建两个独立的模拟集群:cluster-a 与 cluster-b。这两个集群将作为后续章节中服务网格跨集群通信、流量镜像与故障转移的基础设施。

3.1 技术选型对比:Kind vs K3s

在本地模拟多集群场景时,Kind 与 K3s 各有侧重。下表从核心维度进行对比,帮助你根据实验角色选择最合适的方案。

对比维度 Kind K3s
运行方式 每个集群节点运行在 Docker 容器中 原生进程运行,可部署在 VM 或裸机
资源占用 中等(每个节点约 0.5-1 GB 内存) 低(约 256 MB 内存即可运行)
CNI 支持 默认使用 Kindnet,可替换为 Calico/Cilium 内置 Flannel,支持自定义 CNI
多集群网络互通 需额外配置路由或隧道(如 WireGuard) 原生支持 K3s 集群间隧道(--flannel-backend=wireguard)
适用场景 CI/CD 流水线、快速测试、多节点模拟 边缘计算、资源受限环境、生产级轻量部署
本课程角色 cluster-a(主集群,运行控制面与流水线) cluster-b(从集群,运行工作负载与网格 sidecar)
选型建议: 本课程将 cluster-a 配置为 Kind 集群,以模拟标准 K8s 环境;cluster-b 使用 K3s,以体现资源节约与边缘部署场景。这种异构组合更能检验服务网格的跨集群兼容性。

3.2 环境准备与前置条件

在开始搭建之前,请确保你的本地开发机满足以下最低要求:

  • 操作系统: Linux(推荐 Ubuntu 22.04+)或 macOS(Intel/Apple Silicon)
  • Docker: 版本 20.10+,并已启动 Docker daemon
  • kubectl: 版本 1.27+,与目标 K8s 版本偏差不超过 ±1 个次要版本
  • 资源配额: 至少 4 核 CPU、8 GB 可用内存、20 GB 磁盘空间
  • 网络: 能够访问 Docker Hub 与 GitHub Releases(用于拉取镜像与二进制)

3.3 搭建 cluster-a(Kind 集群)

Kind 通过声明式 YAML 配置文件定义集群拓扑。我们将创建一个包含 1 个控制面节点 + 2 个 Worker 节点的集群,并暴露 80/443 端口供后续 Ingress 使用。

3.3.1 安装 Kind

# 下载 Kind 二进制(Linux/macOS)
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.20.0/kind-linux-amd64
chmod +x ./kind
sudo mv ./kind /usr/local/bin/kind

# 验证安装
kind version

3.3.2 创建集群配置文件

创建 kind-cluster-a.yaml:

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: cluster-a
nodes:
  - role: control-plane
    extraPortMappings:
      - containerPort: 80
        hostPort: 80
      - containerPort: 443
        hostPort: 443
  - role: worker
  - role: worker

3.3.3 启动集群

kind create cluster --config kind-cluster-a.yaml

# 验证节点状态
kubectl get nodes --context kind-cluster-a
预期输出: 三个节点均为 Ready 状态,控制面节点带有 control-plane 角色标签。

3.4 搭建 cluster-b(K3s 集群)

K3s 采用单二进制安装,我们使用官方安装脚本部署一个单节点集群(包含内嵌 etcd),并禁用 Traefik 以避免与后续服务网格冲突。

3.4.1 安装 K3s

# 使用国内镜像加速(可选)
export INSTALL_K3S_MIRROR=cn

# 安装 K3s 单节点集群,禁用 Traefik 与 Metrics Server
curl -sfL https://get.k3s.io | sh -s - \
  --disable traefik \
  --disable metrics-server \
  --write-kubeconfig-mode 644

# 验证集群状态
kubectl get nodes --context default
注意: K3s 默认将 kubeconfig 写入 /etc/rancher/k3s/k3s.yaml。如果本地已有其他集群配置,请使用 --kubeconfig 参数或合并上下文。

3.4.2 配置 kubeconfig 上下文

为了方便管理两个集群,我们将 K3s 的 kubeconfig 合并到本地 ~/.kube/config 中,并重命名上下文为 cluster-b:

# 导出 K3s 配置
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml

# 重命名上下文
kubectl config rename-context default cluster-b

# 合并到本地配置
export KUBECONFIG=~/.kube/config:/etc/rancher/k3s/k3s.yaml
kubectl config view --flatten > ~/.kube/config.new
mv ~/.kube/config.new ~/.kube/config

# 验证两个上下文
kubectl config get-contexts

3.5 多集群网络互通配置

服务网格要求集群间 Pod 网络能够直接通信。由于 Kind 与 K3s 运行在同一个 Docker 宿主机上,我们可以通过 路由表 + 隧道接口 实现互通。下面使用 WireGuard 建立点对点隧道。

3.5.1 获取集群 Pod CIDR

集群 Pod CIDR Service CIDR
cluster-a (Kind) 10.244.0.0/16 10.96.0.0/12
cluster-b (K3s) 10.42.0.0/16 10.43.0.0/16

3.5.2 配置 WireGuard 隧道

在宿主机上创建 WireGuard 接口,并添加路由规则:

# 安装 WireGuard
sudo apt install wireguard -y

# 创建隧道配置(/etc/wireguard/k8s-tunnel.conf)
[Interface]
Address = 172.16.0.1/24
PrivateKey = <宿主机私钥>

[Peer]
PublicKey = <对端公钥>
AllowedIPs = 10.244.0.0/16, 10.42.0.0/16
Endpoint = 127.0.0.1:51820
PersistentKeepalive = 25
简化方案: 如果仅用于实验,也可以直接在每个集群的节点上添加静态路由,指向对方集群的 Docker 网桥。但 WireGuard 方案更接近生产环境的多集群网络模型。

3.6 验证多集群就绪状态

完成上述步骤后,执行以下验证清单:

  1. 集群可达性: kubectl cluster-info --context kind-cluster-a 与 kubectl cluster-info --context cluster-b 均返回正常。
  2. 跨集群 Pod 通信: 在 cluster-a 中创建一个测试 Pod,直接 ping cluster-b 中某个 Pod 的 IP 地址。
  3. kubeconfig 上下文切换: kubectl config use-context kind-cluster-a 与 kubectl config use-context cluster-b 无报错。
验证命令示例:
kubectl --context kind-cluster-a run test-pod --image=busybox -- sleep 3600
kubectl --context kind-cluster-a exec test-pod -- ping -c 3 <cluster-b-pod-ip>
多集群 Kind + K3s 拓扑结构图 多集群模拟环境拓扑(Kind + K3s) 宿主机(Docker Host) cluster-a (Kind) 控制面节点 (control-plane) Worker 节点 1 Worker 节点 2 Pod CIDR: 10.244.0.0/16 cluster-b (K3s) 单节点 (内嵌 etcd + control-plane) Worker 角色(同节点) Pod CIDR: 10.42.0.0/16 WireGuard 隧道(跨集群网络互通)

3.7 常见问题与避坑指南

  • 端口冲突: 如果宿主机 80/443 已被占用,修改 extraPortMappings 中的 hostPort 为其他端口(如 8080/8443)。
  • K3s 安装失败: 检查 systemctl status k3s 日志,常见原因为 SELinux 或 AppArmor 限制,可临时设置为 Permissive 模式。
  • 跨集群 DNS 解析: 默认情况下,集群间无法解析对方 Service 名称。后续章节将使用服务网格的 ServiceEntry 或 MultiClusterService 解决。
  • 资源不足: 如果同时运行两个集群导致宿主机 OOM,可减少 Kind 集群的 Worker 节点数量,或为 K3s 增加 --kubelet-arg max-pods=20 限制。
重要提醒: 本章搭建的集群仅用于本地实验与课程练习。切勿将 Kind 或单节点 K3s 直接用于生产环境,它们缺乏高可用与持久化存储等生产级特性。