Docker部署Calico网络


  今天交流了NSX-T和K8S的集成,赶紧了解了一下原生开源的Calico网络。

  Calico是一个纯三层的虚拟网络方案,Calico为每个容器分配一个IP,每个host都是router,host之间采用了BGP协议发布路由,把不同host的容器连接起来。与VxLAN不同的是,Calico不对数据包做额外封装,不需要NAT和端口映射,扩展性和性能都很好。

实验环境

Calico依赖etcd在不同主机间共享和交换信息,存储Calico网络状态。我们将在host 192.168.33.10上运行etcd。

Calico网络中的每个主机都需要运行Calico组件,提供容器interface管理、动态路由、动态ACL、报告状态等功能。

将就了之前搭的vagrant,实验环境如下图所示:

calico1

首先安装etcd

在192.168.33.10主机上安装etcd:

yum install -y etcd

修改etcd配置文件:

[root@master etc]# cat /etc/etcd/etcd.conf 
#[Member]
#ETCD_CORS=""
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
#ETCD_WAL_DIR=""
#ETCD_LISTEN_PEER_URLS="http://localhost:2380"
ETCD_LISTEN_CLIENT_URLS="http://192.168.33.10:2379"
...
#[Clustering]
#ETCD_INITIAL_ADVERTISE_PEER_URLS="http://localhost:2380"
ETCD_ADVERTISE_CLIENT_URLS="http://192.168.33.10:2379"
...

启动etcd服务systemctl start etcd && systemctl enable etcd

修改docker配置文件连接etcd:

修改 node1 和 node2 的 Docker daemon 配置文件/etc/docker/daemon.json

连接 etcd:–cluster-store=etcd://192.168.33.10:2379

[root@node1 ~]# cat /etc/docker/daemon.json 
{
  "registry-mirrors": ["https://x3h8v36l.mirror.aliyuncs.com"],
  "cluster-store": "etcd://192.168.33.10:2379"
}

重启 Docker daemon systemctl daemon-reload && systemctl restart docker.service

部署calicoctl

官方参考文档: https://docs.projectcalico.org/v2.6/getting-started/docker/installation/manual

在node1和node2上下载calicoctl并运行calico容器:

[root@node1 ~]# wget -O /usr/local/bin/calicoctl https://github.com/projectcalico/calicoctl/releases/download/v1.6.5/calicoctl
[root@node1 ~]# chmod +x /usr/local/bin/calicoctl

创建calico配置文件:

[root@node1 ~]# mkdir /etc/calico/
[root@node1 ~]# vim /etc/calico/calicoctl.cfg
apiVersion: v1
kind: calicoApiConfig
metadata:
spec:
  datastoreType: "etcdv2"
  etcdEndpoints: "http://192.168.33.10:2379"

分别在两个节点上创建calico容器,执行后会自动下载calico镜像并运行容器:

[root@node1 ~]# calicoctl node run --node-image=quay.io/calico/node:v2.6.12 -c /etc/calico/calicoctl.cfg
Running command to load modules: modprobe -a xt_set ip6_tables
Enabling IPv4 forwarding
Enabling IPv6 forwarding
Increasing conntrack limit
Removing old calico-node container (if running).
Running the following command to start calico-node:

docker run --net=host --privileged --name=calico-node -d --restart=always -e NODENAME=node1 -e CALICO_NETWORKING_BACKEND=bird -e CALICO_LIBNETWORK_ENABLED=true -e ETCD_ENDPOINTS=http://192.168.33.10:2379 -v /var/log/calico:/var/log/calico -v /var/run/calico:/var/run/calico -v /lib/modules:/lib/modules -v /run:/run -v /run/docker/plugins:/run/docker/plugins -v /var/run/docker.sock:/var/run/docker.sock quay.io/calico/node:v2.6.12

Image may take a short time to download if it is not available locally.
Container started, checking progress logs.

2019-06-06 07:16:41.433 [INFO][8] startup.go 173: Early log level set to info
2019-06-06 07:16:41.433 [INFO][8] client.go 202: Loading config from environment
2019-06-06 07:16:41.434 [INFO][8] startup.go 83: Skipping datastore connection test
2019-06-06 07:16:41.439 [INFO][8] startup.go 259: Building new node resource Name="node1"
2019-06-06 07:16:41.439 [INFO][8] startup.go 273: Initialise BGP data
2019-06-06 07:16:41.441 [INFO][8] startup.go 467: Using autodetected IPv4 address on interface eth1: 192.168.33.11/24
2019-06-06 07:16:41.441 [INFO][8] startup.go 338: Node IPv4 changed, will check for conflicts
2019-06-06 07:16:41.444 [INFO][8] etcd.go 430: Error enumerating host directories error=100: Key not found (/calico) [11]
2019-06-06 07:16:41.444 [INFO][8] startup.go 530: No AS number configured on node resource, using global value
2019-06-06 07:16:41.448 [INFO][8] etcd.go 105: Ready flag is now set
2019-06-06 07:16:41.452 [INFO][8] client.go 133: Assigned cluster GUID ClusterGUID="05d43659a30f4f08a15f9515fcd0278f"
2019-06-06 07:16:41.471 [INFO][8] startup.go 419: CALICO_IPV4POOL_NAT_OUTGOING is true (defaulted) through environment variable
2019-06-06 07:16:41.471 [INFO][8] startup.go 659: Ensure default IPv4 pool is created. IPIP mode: off
2019-06-06 07:16:41.473 [INFO][8] startup.go 670: Created default IPv4 pool (192.168.0.0/16) with NAT outgoing true. IPIP mode: off
2019-06-06 07:16:41.473 [INFO][8] startup.go 419: FELIX_IPV6SUPPORT is true (defaulted) through environment variable
2019-06-06 07:16:41.473 [INFO][8] startup.go 626: IPv6 supported on this platform: true
2019-06-06 07:16:41.473 [INFO][8] startup.go 419: CALICO_IPV6POOL_NAT_OUTGOING is false (defaulted) through environment variable
2019-06-06 07:16:41.473 [INFO][8] startup.go 659: Ensure default IPv6 pool is created. IPIP mode: off
2019-06-06 07:16:41.475 [INFO][8] startup.go 670: Created default IPv6 pool (fd80:24e2:f998:72d6::/64) with NAT outgoing false. IPIP mode: off
2019-06-06 07:16:41.514 [INFO][8] startup.go 131: Using node name: node1
2019-06-06 07:16:41.814 [INFO][12] client.go 202: Loading config from environment
Starting libnetwork service
Calico node started successfully
  1. 设置主机网络,例如 enable IP forwarding。

  2. 下载并启动 calico-node 容器,calico 会以容器的形式运行(与 weave 类似)。

  3. 连接 etcd。

  4. calico 启动成功。

查看calico运行状态:

[root@node1 ~]# calicoctl node status
Calico process is running.

IPv4 BGP status
+---------------+-------------------+-------+----------+--------+
| PEER ADDRESS  |     PEER TYPE     | STATE |  SINCE   |  INFO  |
+---------------+-------------------+-------+----------+--------+
| 192.168.33.12 | node-to-node mesh | start | 07:17:09 | Active |
+---------------+-------------------+-------+----------+--------+

IPv6 BGP status
No IPv6 peers found.

[root@node1 ~]# calicoctl node status
Calico process is running.

IPv4 BGP status
+---------------+-------------------+-------+----------+-------------+
| PEER ADDRESS  |     PEER TYPE     | STATE |  SINCE   |    INFO     |
+---------------+-------------------+-------+----------+-------------+
| 192.168.33.12 | node-to-node mesh | up    | 07:17:13 | Established |
+---------------+-------------------+-------+----------+-------------+

IPv6 BGP status
No IPv6 peers found.

创建calico网络:

在 node1 或 node2 上执行如下命令创建 calico 网络 cal_ent1:

docker network create --driver calico --ipam-driver calico-ipam cal_net1

  • –driver calico 指定使用 calico 的 libnetwork CNM driver。

  • –ipam-driver calico-ipam 指定使用 calico 的 IPAM driver 管理 IP。

calico 为 global 网络,etcd 会将 cal_net 同步到所有主机。

Calico网络结构

在 node1 中运行容器 bbox1 并连接到 cal_net1:

docker container run --net cal_net1 --name bbox1 -tid busybox

查看 bbox1 的网络配置:

[root@node1 ~]# docker exec bbox1 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
5: cali0@if6: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff
    inet 192.168.166.128/32 brd 192.168.166.128 scope global cali0
       valid_lft forever preferred_lft forever

cali0 是 calico interface,分配的 IP 为 192.168.166.128。cali0 对应 node1 编号 6 的 interface calicce21fc3677@if5

node1 将作为 router 负责转发目的地址为 bbox1 的数据包

[root@node1 ~]# ip r
default via 10.0.2.2 dev eth0 proto static metric 100 
10.0.2.0/24 dev eth0 proto kernel scope link src 10.0.2.15 metric 100 
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 
192.168.33.0/24 dev eth1 proto kernel scope link src 192.168.33.11 metric 100 
192.168.104.0/26 via 192.168.33.12 dev eth1 proto bird 
192.168.166.128 dev calicce21fc3677 scope link 
blackhole 192.168.166.128/26 proto bird 

所有发送到 bbox1 的数据都会发给calicce21fc3677,因为calicce21fc3677 与 cali0 是一对 veth pair,bbox1 能够接收到数据。

接下来我们在 host2 中运行容器 bbox2,也连接到 cal_net1:

[root@node2 ~]# docker exec bbox2 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
5: cali0@if6: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff
    inet 192.168.104.0/32 brd 192.168.104.0 scope global cali0
       valid_lft forever preferred_lft forever

IP 为192.168.104.0

node2 添加了两条路由:

[root@node2 ~]# ip r
default via 10.0.2.2 dev eth0 proto static metric 100 
10.0.2.0/24 dev eth0 proto kernel scope link src 10.0.2.15 metric 100 
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 
192.168.33.0/24 dev eth1 proto kernel scope link src 192.168.33.12 metric 100 
192.168.104.0 dev calib5228fd5fcd scope link 
blackhole 192.168.104.0/26 proto bird 
192.168.166.128/26 via 192.168.33.11 dev eth1 proto bird 
  1. 目的地址为 node1 容器 subnet 192.168.166.128/26 的路由。
  2. 目的地址为本地 bbox2 容器 192.168.104.0 的路由。
  3. 注意到node1的路由表,同样的,node1 也自动添加了到 192.168.104.0/26 的路由。

Calico 的默认连通性

测试一下 bbox1 与 bbox2 的连通性:

[root@node1 ~]# docker exec bbox1 ping bbox2
PING bbox2 (192.168.104.0): 56 data bytes
64 bytes from 192.168.104.0: seq=0 ttl=62 time=0.996 ms
64 bytes from 192.168.104.0: seq=1 ttl=62 time=0.568 ms
64 bytes from 192.168.104.0: seq=2 ttl=62 time=0.498 ms
64 bytes from 192.168.104.0: seq=3 ttl=62 time=0.539 ms

calico 默认的 policy 规则是:容器只能与同一个 calico 网络中的容器通信。

既然这是默认 policy,那就有方法定制 policy,这也是 calico 较其他网络方案最大的特性。