在 Docker Desktop 中替换默认 CNI 为 Calico 的步骤

解读

Docker Desktop 默认使用 bridge + host-local + iptables 这一套“开箱即用”的 CNI 插件,目的是让单机开发环境一键可用。但在国内金融、运营商以及中大型企业落地云原生时,往往要求 固定 IP、NetworkPolicy 审计、跨主机 BGP 路由、HPC 场景下高性能 等能力,Calico 就成了刚需。
面试官问“怎么在 Desktop 里换掉默认 CNI”,并不是想听你背 Linux 那套 kubeadm 流程,而是考察三点:

  1. 是否知道 Docker Desktop 本质是运行在 Windows/Mac 上的一个轻量虚拟机(LinuxKit 或 WSL2 backend),所有容器网络都在 VM 内部完成;
  2. 是否理解 Desktop 并没有暴露 kubelet,也没有 systemd,所以无法像服务器那样直接改 /etc/cni/net.d
  3. 能否给出 最小侵入、可回滚、符合企业安全规范 的落地步骤,并解释每个命令背后的原理。
    答不上这三层,基本会被判“只背过八股文”。

知识点

  • Docker Desktop 网络栈:VM 内部用 containerd,CNI 配置目录 /etc/cni/net.d 在 LinuxKit 的只读层,重启会被覆盖;
  • Calico CNI 插件组成calicocalico-ipamportmapbandwidth,以及 calico-kube-controllers
  • WSL2 backend 与 Hyper-V backend 差异:WSL2 的 VM 是 vmmem 进程,文件系统通过 \\wsl$\ 暴露,可直接在 Windows 侧写文件;
  • CNI 优先级00-*.conflist 字典序最靠前者优先;
  • Desktop 的“immutable”机制:任何对 /etc 的直接修改在重启后都会丢失,必须借助 Docker Desktop 的宿主机挂载点WSL2 发行版自启动脚本 实现持久化;
  • 国内镜像加速:Calico 官方镜像 docker.io/calico/* 在国内拉取经常超时,需提前同步到 阿里云 ACR、腾讯云 TCR 或自建 Harbor
  • 合规要求:金融客户要求 非 root 运行 Calico Node,并关闭 FELIX_PROMETHEUSMETRICSENABLED 防止信息泄露;
  • 回滚策略:保留原 10-docker.conflist,通过重命名顺序实现秒级回滚。

答案

步骤以 Windows 11 + Docker Desktop 4.28 + WSL2 backend 为例,Mac 仅需把路径换成 ~/Library/Containers/com.docker.docker/Data/vms/0/data/ 即可。
全程在 Windows 管理员 PowerShellUbuntu-22.04 WSL 发行版 中完成,不破坏 Desktop 一键升级能力

  1. 前置检查

    wsl -d docker-desktop -e cat /etc/os-release
    # 确认是 LinuxKit 5.15 以上内核,已自带 `xt_bpf` `ip_set` 模块
    docker run --rm -it --pid=host --privileged calico/node:v3.27.0 calico-node -felix-ready
    # 提前验证镜像可拉取,否则先 docker tag 国内镜像
    
  2. 准备持久化目录
    在 Windows 侧创建 %USERPROFILE%\.docker\desktop\cni\calico 目录,Desktop 会把该目录自动挂载到 VM 的 /mnt/cni只读),因此还需同步到可写路径。

  3. 编写 Calico CNI 配置
    新建 00-calico.conflist字典序必须小于 10-docker.conflist):

    {
      "cniVersion": "1.0.0",
      "name": "calico",
      "plugins": [
        {
          "type": "calico",
          "log_level": "info",
          "datastore_type": "kubernetes",
          "nodename": "__KUBERNETES_NODE_NAME__",
          "ipam": {
            "type": "calico-ipam",
            "assign_ipv4": "true",
            "ipv4_pools": ["10.88.0.0/16"]
          },
          "policy": {"type": "k8s"},
          "kubernetes": {"kubeconfig": "/etc/cni/net.d/calico-kubeconfig"}
        },
        {"type": "portmap", "snat": true, "capabilities": {"portMappings": true}},
        {"type": "bandwidth", "capabilities": {"bandwidth": true}}
      ]
    }
    

    把文件复制到 %USERPROFILE%\.docker\desktop\cni\calico\00-calico.conflist

  4. 制作 LinuxKit 自启动脚本
    在 WSL2 发行版里执行:

    sudo tee /usr/local/bin/calico-cni-install.sh <<'EOF'
    #!/bin/sh
    set -e
    mkdir -p /etc/cni/net.d
    # 利用 Desktop 的持久化挂载点
    cp /mnt/cni/00-calico.conflist /etc/cni/net.d/
    # 关闭默认 docker bridge CNI
    mv /etc/cni/net.d/10-docker.conflist /etc/cni/net.d/10-docker.conflist.bak
    # 写入 calico-kubeconfig(空文件即可,Desktop 无 kubelet)
    touch /etc/cni/net.d/calico-kubeconfig
    EOF
    sudo chmod +x /usr/local/bin/calico-cni-install.sh
    

    然后把它加入 LinuxKit 的 /etc/local.d/calico.start

    sudo tee /etc/local.d/calico.start <<'EOF'
    #!/bin/sh
    /usr/local/bin/calico-cni-install.sh
    EOF
    sudo chmod +x /etc/local.d/calico.start
    

    由于 LinuxKit 使用 openrc,local.d 脚本会在 dockerd 启动前执行,保证 CNI 顺序正确。

  5. 启动 Calico Node 容器
    在 Windows 侧编写 calico-node.yaml

    version: '3.8'
    services:
      calico-node:
        image: registry.cn-hangzhou.aliyuncs.com/acs/calico-node:v3.27.0
        container_name: calico-node
        restart: always
        network_mode: host
        pid: host
        privileged: true
        environment:
          DATASTORE_TYPE: "kubernetes"
          WAIT_FOR_DATASTORE: "true"
          CALICO_NETWORKING_BACKEND: "bird"
          CALICO_IPV4POOL_CIDR: "10.88.0.0/16"
          CALICO_IPV4POOL_IPIP: "Never"
          CALICO_IPV4POOL_VXLAN: "Never"
          FELIX_DEFAULTENDPOINTTOHOSTACTION: "ACCEPT"
          FELIX_PROMETHEUSMETRICSENABLED: "false"
          NODENAME: "docker-desktop"
        volumes:
          - /lib/modules:/lib/modules
          - /var/run/calico:/var/run/calico
          - /var/log/calico:/var/log/calico
        command: ["calico-node", "-felix"]
    

    然后:

    docker compose -f calico-node.yaml up -d
    
  6. 验证

    docker network create --driver calico --ipam-driver calico-ipam calico-net
    docker run --rm -it --network calico-net alpine ping -c 4 10.88.0.1
    

    能通说明 Calico CNI 已生效;再创建两条 NetworkPolicy:

    apiVersion: crd.projectcalico.org/v1
    kind: NetworkPolicy
    metadata:
      name: deny-all
    spec:
      selector: app == "demo"
      types:
      - Ingress
      - Egress
    

    通过 calicoctl 下发策略,确认容器间流量被阻断,即证明 Policy 引擎工作正常

  7. 回滚
    若需回滚,只需在 WSL2 里执行:

    mv /etc/cni/net.d/10-docker.conflist.bak /etc/cni/net.d/10-docker.conflist
    rm -f /etc/cni/net.d/00-calico.conflist
    docker compose -f calico-node.yaml down
    

    重启 Docker Desktop,30 秒内恢复默认 bridge 网络

拓展思考

  1. 多节点场景:Desktop 本身只模拟单机,若需验证跨主机 BGP,可在同一台 Windows 开多个 WSL2 发行版,用 L2bridge 透明网卡 打通二层,再跑两套 Calico Node,AS 号分别取 64512、64513,观察 RR(Route Reflector)自动选举Typha 水平扩展 效果。
  2. 性能调优:国内云主机常关 ipip/vxlan,但 Windows 宿主机网卡不支持 RSS 多队列 时,Calico eBPF 模式反而下降 20%,需 绑定 CPU 隔离集 并打开 FELIX_BPFENABLED=true 做基准测试。
  3. 安全合规:证监会《容器安全指引》要求 镜像签名与 CNI 策略双审计,可把 calico-typha 日志直接打到 Splunk 或阿里云 SLS,并用 falco 侧车检测 modprobe 逃逸行为。
  4. 升级策略:Docker Desktop 每季度大版本更新会重写 LinuxKit,本地脚本会被清空,因此要把步骤 4 的脚本做成 Windows 计划任务,每次 Desktop 启动后 30 秒自动下发,实现 “热补丁”级持久化