当 Docker 容器分布在多台宿主机上时,网络就成了绕不开的问题。Docker 自带的 overlay 网络虽然开箱即用,但在大规模场景下性能损耗、排查难度都容易被诟病。Calico 是 Tigera 开源的网络方案,它不走隧道封装的路子,而是用纯三层路由加 BGP 协议直接打通容器之间的通信,性能接近原生网络,策略能力也更强。这篇文章就来聊聊 Docker 与 Calico 的集成思路、完整安装过程以及验证方法。

一、为什么需要 Calico:Docker 默认网络的局限
Docker 默认提供 bridge、host、none 三种网络,其中 bridge 网络只适合单机场景。跨主机通信一般用 overlay 网络,overlay 依赖 VXLAN 封装,每发一个包都要额外加上一层包头,MTU 变小、CPU 开销增加,吞吐量通常会打八折甚至更多。而且 overlay 网络的流量被封装在 UDP 4789 端口里,tcpdump 抓包时看到的都是封装后的报文,定位问题相当费劲。
Calico 的思路完全不同。它把每个容器当作网络里的一等公民,直接分配一个可路由的 IP 地址,宿主机之间通过 BGP 协议交换路由信息。容器 A 访问容器 B 时,数据包直接走三层转发,没有隧道封装,性能接近裸机网络。同时 Calico 还提供网络策略能力,可以按标签精细控制容器之间的访问权限,这一点对安全要求高的场景特别实用。
另外值得一提的是可观测性。Calico 网络下的流量在每一跳都是明文的三层报文,直接用 tcpdump 抓容器网卡或者宿主机网卡就能看到真实源 IP 和目标 IP,配合路由表排查问题比 overlay 直观得多。
二、Calico 核心架构简介
在动手安装之前,先搞清楚 Calico 的几个核心组件。第一个是 Felix,它是运行在每台宿主机上的守护进程,负责写入路由表和 ACL 规则,为容器创建 veth 设备并接入内核网络。第二个是 BGP 客户端(BIRD),它把 Felix 生成的路由信息通过 BGP 协议广播给集群中其他节点,让整个集群都知道某个容器 IP 在哪台机器上。
第三个组件是集中式的存储。Calico 早期依赖 etcd 存储网络状态和策略配置,新版本也支持 Kubernetes API 作为数据面。对于纯 Docker 环境(没有 Kubernetes),etcd 仍然是最常见的搭档,网络里所有的 IP 池分配、策略定义都记录在 etcd 中,各节点的 Felix 从中读取数据并同步到本地。
理解了这个架构之后,集成的思路就清晰了:宿主机之间通过 BGP 互相学习路由,Felix 在本地维护容器路由,Docker 只需要把容器网卡接到 Calico 的管理范围内即可。
三、安装 etcd 并部署 Calico 节点
假设我们有两台宿主机,IP 分别是 192.168.1.10 和 192.168.1.11,系统为 CentOS 或 Ubuntu 均可。第一步先装 etcd,可以直接下载二进制包:
# 下载并安装 etcd wget https://github.com/etcd-io/etcd/releases/download/v3.5.9/etcd-v3.5.9-linux-amd64.tar.gz tar xzvf etcd-v3.5.9-linux-amd64.tar.gz cp etcd-v3.5.9-linux-amd64/etcd* /usr/local/bin/ # 启动 etcd,监听地址根据实际情况调整 nohup etcd --listen-client-urls http://0.0.0.0:2379 \ --advertise-client-urls http://192.168.1.10:2379 >/tmp/etcd.log 2>&1 &
接下来在两台机器上都安装 Calico 节点组件。Calico 官方提供了 calicoctl 工具和 calico-node 容器,用容器方式跑 calico-node 是最省事的做法:
# 拉取 calico-node 镜像 docker pull calico/node:v3.26.0 # 在 192.168.1.10 上启动 calico-node docker run -d --net=host --privileged --name calico-node \ -e ETCD_ENDPOINTS=http://192.168.1.10:2379 \ -e NODENAME=node1 \ -e CALICO_LIBNETWORK_ENABLED=true \ -v /var/run/docker.sock:/var/run/docker.sock \ calico/node:v3.26.0
这里有几个关键参数需要说明。ETCD_ENDPOINTS 指向刚才部署的 etcd;NODENAME 是节点在 Calico 中的标识,两台机器要设成不同名字;CALICO_LIBNETWORK_ENABLED 打开后,calico-node 会自动注册一个 Docker 网络驱动,这是与 Docker 集成的核心开关。第二台机器重复同样的操作,把 NODENAME 改为 node2 即可。
四、创建 IP 池与 Docker 网络,接入容器
calico-node 启动后,需要先定义 IP 池(IP Pool),告诉 Calico 容器从哪个网段分配地址。使用 calicoctl 完成这个操作:
# 安装 calicoctl wget https://github.com/projectcalico/calicoctl/releases/download/v3.26.0/calicoctl-linux-amd64 chmod +x calicoctl-linux-amd64 mv calicoctl-linux-amd64 /usr/local/bin/calicoctl # 配置 etcd 地址 export ETCD_ENDPOINTS=http://192.168.1.10:2379 # 创建 IP 池 cat <<EOF | calicoctl create -f - apiVersion: projectcalico.org/v3 kind: IPPool metadata: name: docker-pool spec: cidr: 10.20.0.0/16 ipipMode: Never natOutgoing: false EOF
注意这里 ipipMode 设为 Never,表示不使用 IPIP 封装,纯 BGP 三层路由;如果宿主机之间不能直接跑 BGP(比如云厂商的二层网络限制),可以改成 Always 或者使用 VXLAN 模式。natOutgoing 设为 false 则容器访问外部时不做地址伪装,适合有真实路由的环境。
接着在两台机器上分别创建 Docker 网络,驱动指定为 calico:
# 两台机器都执行 docker network create --driver calico \ --ipam-driver calico-ipam \ --subnet=10.20.0.0/16 \ calico-net # 启动测试容器 docker run -itd --net calico-net --name test1 busybox
在第二台机器上同样启动一个名为 test2 的容器。创建网络时必须指定 --ipam-driver calico-ipam,这样 IP 地址的分配才由 Calico 统一管理,避免两台机器分到冲突的 IP。
五、验证连通性与路由状态
集成完成后,先看容器的 IP 地址,再从 test1 里 ping test2 的 IP:
# 查看 test1 的 IP docker exec test1 ip addr show eth0 # 假设得到 10.20.139.65,第二台机器上 test2 是 10.20.217.1 # 在 test1 内测试跨主机连通性 docker exec test1 ping -c 3 10.20.217.1 # 查看宿主机路由表,能看到对端容器网段的路由 ip route | grep 10.20 # 输出类似:10.20.217.0/26 via 192.168.1.11 dev eth0 proto bird
如果 ping 不通,可以从几个方向排查。第一,确认两台宿主机 BGP 会话是否建立,用 calicoctl node status 查看,正常应该显示对端为 Established 状态。第二,检查 IP 池配置是否一致,两台机器的 Docker 网络 subnet 必须落在同一个 IP Pool 内。第三,确认 etcd 是否对所有节点可访问,Felix 读不到数据就不会写路由。
六、Calico 与 overlay 方案的取舍建议
从实测数据看,Calico 的 BGP 直通模式在吞吐和延迟上普遍优于 VXLAN overlay,尤其是高并发小包场景,优势更明显。如果你的宿主机在同一个二层网络内,Calico 几乎是无脑优选。但如果宿主机跨越了公网或者不相连的三层网络,纯 BGP 方案需要额外引入 BGP Reflector 或者改用 IPIP、VXLAN 封装,此时两者的差距会缩小,选择上就要结合运维复杂度综合考虑。
另一个维度是生态。Calico 最初就是为大规模容器网络设计的,网络策略、IP 池管理、路由反射器等能力都比较成熟,后续如果迁移到 Kubernetes 集群,Calico 的使用经验可以无缝延续。对纯 Docker 环境来说,唯一要注意的是 etcd 的维护成本,小规模场景可以单节点部署,生产环境建议至少三个节点组成集群,避免单点故障导致整个容器网络瘫痪。