Docker配置calico网络

Calico网络简介

Calico为容器和虚拟机工作负载提供安全的网络连接。
Calico创建并管理平面第3层网络,为每个工作负载分配完全可路由的IP地址。工作负载可以在没有IP封装或网络地址转换的情况下进行通信,以实现裸机性能,简化故障排除和更好的互操作性。在需要overlay的环境中,Calico使用IP-in-IP隧道技术,或者可以与flannel等其他覆盖网络配合使用。
Calico还提供网络安全规则的动态实施。使用Calico的简单策略语言,您可以实现对容器,虚拟机工作负载和裸机主机端点之间通信的细粒度控制。
Calico在大规模生产方面经过验证,可与Kubernetes,OpenShift,Docker,Mesos,DC / OS和OpenStack集成。

实验环境描述

Calico 依赖 etcd 在不同主机间共享和交换信息,存储 Calico 网络状态。我们将在 host 192.168.92.56上运行 etcd。
Calico 网络中的每个主机都需要运行 Calico 组件,提供容器 interface 管理、动态路由、动态 ACL、报告状态等功能。
实验环境如下图所示:
Docker配置calico网络_第1张图片
主机节点:
192.168.92.56 etcd 安装docker+etcd
192.168.92.57 host1 安装docker+ calicoctl
192.168.92.58 host2 安装docker+ calicoctl
软件版本:
calicoctl(version v1.6.5) etcdctl(version: 3.2.22) docker(version:18.09.0-ce)
修改三个节点的主机名

    [root@localhost ~]# hostnamectl --static set-hostname etcd
    [root@localhost ~]# hostnamectl --static set-hostname host1
    [root@localhost ~]# hostnamectl --static set-hostname host2

在三台主机上都要设置hosts:

    [root@host1 ~]# vim /etc/hosts
    192.168.92.56     etcd 
    192.168.92.57     host1
    192.168.92.58     host2 

关闭三台主机的防火墙
若开启iptables防火墙,则需要打开2380端口通信。

    [root@host1 ~]# systemctl disable firewalld.service
    [root@host1 ~]# systemctl stop firewalld.service
    [root@host1 ~]# iptables -F
    [root@host1 ~]# firewall-cmd --state
    not running

安装etcd

在etcd主机上安装etcd

    [root@etcd ~]# yum install -y etcd

修改etcd配置文件:

    [root@etcd ~]# vim /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.92.56:2379"
    ......
    ETCD_ADVERTISE_CLIENT_URLS="http://192.168.92.56:2379"
    ......

启动etcd服务

    [root@etcd ~]# systemctl start etcd && systemctl enable etcd

查看版本

    [root@etcd ~]# etcdctl -version
    etcdctl version: 3.2.22
    API version: 2
    [root@etcd ~]# 

修改docker配置文件连接etcd
修改 host1 和 host2 的 Docker daemon 配置文件
连接 etcd:–cluster-store=etcd://192.168.92.56:2379

    [root@host1 ~]# vim /etc/docker/daemon.json
    {
      "registry-mirrors": ["http://f1361db2.m.daocloud.io"],
      "cluster-store": "etcd://192.168.92.56:2379"
    }

说明:第一行的registry-mirrors是配置docker镜像加速以后自动添加的。
重启 Docker daemon

    systemctl daemon-reload && systemctl restart docker.service

查看配置是否正确

    [root@host1 ~]# docker info | grep "Cluster Store"
    Cluster Store: etcd://192.168.92.56:2379
    [root@host1 ~]# 

部署calicoctl

官方参考文档:https://docs.projectcalico.org/v2.6/getting-started/docker/installation/manual
在host1和host2上下载calicoctl并运行calico容器。
下载calicoctl

    [root@host1 ~]# wget -O /usr/local/bin/calicoctl https://github.com/projectcalico/calicoctl/releases/download/v1.6.5/calicoctl
    [root@host1 ~]# chmod +x /usr/local/bin/calicoctl
    [root@host1 ~]# /usr/local/bin/calicoctl --version
    calicoctl version v1.6.5, build 614fcf12

创建calico容器
首先创建calico配置文件

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

分别在两个节点上创建calico容器,执行后会自动下载calico镜像并运行容器,下载镜像可能较慢,建议配置镜像加速,启动过程如下:

    [root@host1 ~]# 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=host1 -e CALICO_NETWORKING_BACKEND=bird -e CALICO_LIBNETWORK_ENABLED=true -e ETCD_ENDPOINTS=http://192.168.92.56: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.
    
    2018-11-20 09:38:51.800 [INFO][8] startup.go 173: Early log level set to info
    2018-11-20 09:38:51.801 [INFO][8] client.go 202: Loading config from environment
    2018-11-20 09:38:51.801 [INFO][8] startup.go 83: Skipping datastore connection test
    2018-11-20 09:38:51.811 [INFO][8] startup.go 259: Building new node resource Name="host1"
    2018-11-20 09:38:51.811 [INFO][8] startup.go 273: Initialise BGP data
    2018-11-20 09:38:51.812 [INFO][8] startup.go 467: Using autodetected IPv4 address on interface ens33: 192.168.92.57/24
    2018-11-20 09:38:51.812 [INFO][8] startup.go 338: Node IPv4 changed, will check for conflicts
    2018-11-20 09:38:51.814 [INFO][8] etcd.go 430: Error enumerating host directories error=100: Key not found (/calico) [11]
    2018-11-20 09:38:51.814 [INFO][8] startup.go 530: No AS number configured on node resource, using global value
    2018-11-20 09:38:51.816 [INFO][8] etcd.go 105: Ready flag is now set
    2018-11-20 09:38:51.817 [INFO][8] client.go 133: Assigned cluster GUID ClusterGUID="6608d7fcd5934b86af326f9570763e05"
    2018-11-20 09:38:51.832 [INFO][8] startup.go 419: CALICO_IPV4POOL_NAT_OUTGOING is true (defaulted) through environment variable
    2018-11-20 09:38:51.832 [INFO][8] startup.go 659: Ensure default IPv4 pool is created. IPIP mode: off
    2018-11-20 09:38:51.834 [INFO][8] startup.go 670: Created default IPv4 pool (192.168.0.0/16) with NAT outgoing true. IPIP mode: off
    2018-11-20 09:38:51.835 [INFO][8] startup.go 419: FELIX_IPV6SUPPORT is true (defaulted) through environment variable
    2018-11-20 09:38:51.835 [INFO][8] startup.go 626: IPv6 supported on this platform: true
    2018-11-20 09:38:51.835 [INFO][8] startup.go 419: CALICO_IPV6POOL_NAT_OUTGOING is false (defaulted) through environment variable
    2018-11-20 09:38:51.835 [INFO][8] startup.go 659: Ensure default IPv6 pool is created. IPIP mode: off
    2018-11-20 09:38:51.837 [INFO][8] startup.go 670: Created default IPv6 pool (fd80:24e2:f998:72d6::/64) with NAT outgoing false. IPIP mode: off
    2018-11-20 09:38:51.886 [INFO][8] startup.go 131: Using node name: host1
    2018-11-20 09:38:51.967 [INFO][13] client.go 202: Loading config from environment
    Starting libnetwork service
    Calico node started successfully
    [root@host1 ~]# 

1.设置主机网络,例如 enable IP forwarding。
2.下载并启动 calico-node 容器,calico 会以容器的形式运行(与 weave 类似)。

[root@host1 ~]# docker images
REPOSITORY            TAG                 IMAGE ID            CREATED             SIZE
quay.io/calico/node   v2.6.12             401cc3e56a1a        10 days ago         281MB
[root@host1 ~]# docker ps
CONTAINER ID        IMAGE                         COMMAND             CREATED             STATUS              PORTS               NAMES
5903e0254caf        quay.io/calico/node:v2.6.12   "start_runit"       18 minutes ago      Up 18 minutes                           calico-node
[root@host1 ~]#

3.连接 etcd。
4.calico 启动成功。

查看calico运行状态

    [root@host1 ~]# calicoctl node status
    Calico process is running.
    
    IPv4 BGP status
    +---------------+-------------------+-------+----------+-------------+
    | PEER ADDRESS  |     PEER TYPE     | STATE |  SINCE   |    INFO     |
    +---------------+-------------------+-------+----------+-------------+
    | 192.168.92.58 | node-to-node mesh | up    | 09:42:58 | Established |
    +---------------+-------------------+-------+----------+-------------+
    
    IPv6 BGP status
    No IPv6 peers found.
    
    [root@host1 ~]# 
    [root@host2 ~]# calicoctl node status
    Calico process is running.
    
    IPv4 BGP status
    +---------------+-------------------+-------+----------+-------------+
    | PEER ADDRESS  |     PEER TYPE     | STATE |  SINCE   |    INFO     |
    +---------------+-------------------+-------+----------+-------------+
    | 192.168.92.57 | node-to-node mesh | up    | 09:42:58 | Established |
    +---------------+-------------------+-------+----------+-------------+
    
    IPv6 BGP status
    No IPv6 peers found.
    
    [root@host2 ~]# 

创建 calico 网络
在 host1 或 host2 上执行如下命令创建 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 同步到所有主机。

    [root@host1 ~]# docker network ls
    NETWORK ID          NAME                DRIVER              SCOPE
    13688a2fa1f6        bridge              bridge              local
    4a036a209f73        cal_net1            calico              global
    634261a87b28        host                host                local
    83b3249a9250        none                null                local
    [root@host1 ~]#  

Calico网络结构

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

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

查看 bbox1 的网络配置。

    [root@host1 ~]# docker exec bbox1 ip a
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
        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.119.0/32 brd 192.168.119.0 scope global cali0
           valid_lft forever preferred_lft forever
    [root@host1 ~]# 

cali0 是 calico interface,分配的 IP 为 192.168.119.0。cali0 对应 host1 编号6 的 interface caliea27309bc46。

    [root@host1 ~]# ip a
    ......
    6: caliea27309bc46@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
        link/ether ba:9a:72:6c:61:12 brd ff:ff:ff:ff:ff:ff link-netnsid 0
        inet6 fe80::b89a:72ff:fe6c:6112/64 scope link 
           valid_lft forever preferred_lft forever
    [root@host1 ~]# 

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

    [root@host1 ~]# ip route 
    default via 192.168.92.2 dev ens33 proto static metric 100 
    172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown 
    192.168.92.0/24 dev ens33 proto kernel scope link src 192.168.92.57 metric 100 
    192.168.119.0 dev caliea27309bc46 scope link 
    blackhole 192.168.119.0/26 proto bird 

所有发送到 bbox1 的数据都会发给caliea27309bc46,因为caliea27309bc46 与 cali0 是一对 veth pair,bbox1 能够接收到数据。
接下来我们在 host2 中运行容器 bbox2,也连接到 cal_net1:

   # docker container run --net cal_net1 --name bbox2 -tid busybox

IP 为 192.168.183.64。

    [root@host2 ~]# docker exec bbox2 ip a 
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
        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.183.64/32 brd 192.168.183.64 scope global cali0
           valid_lft forever preferred_lft forever
    [root@host2 ~]# 

host2 添加了两条路由:

    [root@host2 ~]# ip route 
    default via 192.168.92.2 dev ens33 proto static metric 100 
    172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown 
    192.168.92.0/24 dev ens33 proto kernel scope link src 192.168.92.58 metric 100 
    192.168.119.0/26 via 192.168.92.57 dev ens33 proto bird 
    192.168.183.64 dev cali16a5ce997f9 scope link 
    blackhole 192.168.183.64/26 proto bird 
    [root@host2 ~]# 
  1. 目的地址为 host1 容器 subnet 192.168.119.0/26 的路由。
  2. 目的地址为本地 bbox2 容器 192.168.183.65 的路由。

同样的,host1 也自动添加了到 192.168.183.64/26 的路由。

    [root@host1 ~]# ip route 
    default via 192.168.92.2 dev ens33 proto static metric 100 
    172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown 
    192.168.92.0/24 dev ens33 proto kernel scope link src 192.168.92.57 metric 100 
    192.168.119.0 dev caliea27309bc46 scope link 
    blackhole 192.168.119.0/26 proto bird 
    192.168.183.64/26 via 192.168.92.58 dev ens33 proto bird 
    [root@host1 ~]# 

Calico 的默认连通性

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

    [root@host1 ~]# docker exec bbox1 ping -c 2 bbox2
    PING bbox2 (192.168.183.64): 56 data bytes
    64 bytes from 192.168.183.64: seq=0 ttl=62 time=0.654 ms
    64 bytes from 192.168.183.64: seq=1 ttl=62 time=1.282 ms

ping 成功,数据包流向如下图所示。
Docker配置calico网络_第2张图片
① 根据 bbox1 的路由表,将数据包从 cal0 发出。

    [root@host1 ~]# docker exec bbox1 ip route
    default via 169.254.1.1 dev cali0 
    169.254.1.1 dev cali0 scope link 
    [root@host1 ~]# 

② 数据经过 veth pair 到达 host1,查看路由表,数据由 ens33发给 host2(192.168.92.58)。
192.168.183.64/26 via 192.168.92.58 dev ens33 proto bird
③ host2 收到数据包,根据路由表发送给 calic8bf9e68397,进而通过 veth pair cali0 到达 bbox2。
192.168.183.64 dev cali16a5ce997f9 scope link
接下来我们看看不同 calico 网络之间的连通性。
创建 cal_net2。

    docker network create --driver calico --ipam-driver calico-ipam cal_net2

在 host1 中运行容器 bbox3,连接到 cal_net2:

    docker container run --net cal_net2 --name bbox3 -tid busybox

calico 为 bbox3 分配了 IP 192.168.119.1。

    [root@host1 ~]# docker exec bbox3 ip address show cali0
    7: cali0@if8: <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.119.1/32 brd 192.168.119.1 scope global cali0
           valid_lft forever preferred_lft forever
    [root@host1 ~]# 

验证 bbox1 与 bbox3 的连通性。

    [root@host1 ~]# docker exec bbox1 ping -c 2 bbox3
    ping: bad address 'bbox3'
    [root@host1 ~]# 

虽然 bbox1 和 bbox3 都位于 host1,而且都在一个 subnet 192.168.119.0/26,但它们属于不同的 calico 网络,默认不能通行。
calico 默认的 policy 规则是:容器只能与同一个 calico 网络中的容器通信。
calico 的每个网络都有一个同名的 profile,profile 中定义了该网络的 policy。我们具体看一下 cal_net1 的 profile:

    [root@host1 ~]# calicoctl get profile cal_net1 -o yaml
    - apiVersion: v1
      kind: profile
      metadata:
        name: cal_net1
        tags:
        - cal_net1
      spec:
        egress:
        - action: allow
          destination: {}
          source: {}
        ingress:
        - action: allow
          destination: {}
          source:
            tag: cal_net1
    [root@host1 ~]# 

① 命名为 cal_net1,这就是 calico 网络 cal_net1 的 profile。
② 为 profile 添加一个 tag cal_net1。注意,这个 tag 虽然也叫 cal_net1,其实可以随便设置,这跟上面的 name: cal_net1 没有任何关系。此 tag 后面会用到。
③ egress 对从容器发出的数据包进行控制,当前没有任何限制。
④ ingress 对进入容器的数据包进行限制,当前设置是接收来自 tag cal_net1 的容器,根据第 ① 步设置我们知道,实际上就是只接收本网络的数据包,这也进一步解释了前面的实验结果。
既然这是默认 policy,那就有方法定制 policy,这也是 calico 较其他网络方案最大的特性。下一节就我们讨论如何定制 calico policy。

定制 Calico 网络 Policy

Calico 默认的 policy 规则是:容器只能与同一个 calico 网络中的容器通信。calico 能够让用户定义灵活的 policy 规则,精细化控制进出容器的流量,下面我们就来实践一个场景:
创建一个新的 calico 网络 cal_web 并部署一个 httpd 容器 web1。
定义 policy 允许 cal_net2 中的容器访问 web1 的 80 端口。
首先创建 cal_web。

   # docker network create --driver calico --ipam-driver calico-ipam cal_web 

在 host1 中运行容器 web1,连接到 cal_web:

    docker container run --net cal_web --name web1 -d httpd
    [root@host1 ~]# docker exec -it web1 bash
    root@98c33620a550:/usr/local/apache2#    
    root@98c33620a550:/usr/local/apache2# apt-get update
    root@98c33620a550:/usr/local/apache2# apt-get install iproute
    root@98c33620a550:/usr/local/apache2# 
    root@98c33620a550:/usr/local/apache2# exit
    exit
    [root@host1 ~]#

web1 的 IP 为 192.168.119.2

    [root@host1 ~]# docker container exec web1 ip address show cali0
    9: cali0@if10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
        link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff link-netnsid 0
        inet 192.168.119.2/32 brd 192.168.119.2 scope global cali0
           valid_lft forever preferred_lft forever
    [root@host1 ~]# 

目前 bbox3 还无法访问 web1 的 80 端口。

    [root@host1 ~]# docker container exec bbox3 wget 192.168.119.2
    Connecting to 192.168.119.2 (192.168.119.2:80)
    wget: can't connect to remote host (192.168.119.2): Connection timed out
    [root@host1 ~]# 

创建 policy 文件 web.yml,内容为:

    [root@host1 ~]# vim web.yml
    - apiVersion: v1
      kind: profile
      metadata:
        name: cal_web
      spec:
        ingress:
        - action: allow
          protocol: tcp
          source:
            tag: cal_net2
          destination:
            ports:
            - 80

① profile 与 cal_web 网络同名,cal_web 的所有容器(web1)都会应用此 profile 中的 policy。
② ingress 允许 cal_net2 中的容器(bbox3)访问。
③ 只开放 80 端口。
应用该 policy。

  #  calicoctl apply -f web.yml

现在 bbox3 已经能够访问 web1 的 http 服务了。

    [root@host1 ~]# docker container exec bbox3 wget 192.168.119.2
    Connecting to 192.168.119.2 (192.168.119.2:80)
    index.html           100% |********************************|    45  0:00:00 ETA
    
    [root@host1 ~]# 

不过 ping 还是不行,因为只放开了 80 端口。

    [root@host1 ~]# docker container exec bbox3 ping -c 2 192.168.119.2
    PING 192.168.119.2 (192.168.119.2): 56 data bytes
    
    --- 192.168.119.2 ping statistics ---
    2 packets transmitted, 0 packets received, 100% packet loss
    [root@host1 ~]# 

上面这个例子比较简单,不过已经向我们展示了 calico 强大的 policy 功能。通过 policy,可以动态实现非常复杂的容器访问控制。有关 calico policy 更多的配置,可参看官网文档 http://docs.projectcalico.org/v2.0/reference/calicoctl/resources/policy

定制 Calico IP 池

calico 会为自动为网络分配 subnet,当然我们也可以定制。
首先定义一个 IP Pool,比如:

    [root@host1 ~]# vim ipPool.yaml                
    - apiVersion: v1
      kind: ipPool
      metadata:
    cidr: 17.2.0.0/16
    [root@host1 ~]# calicoctl create -f ipPool.yaml
    Successfully created 1 'ipPool' resource(s)
    [root@host1 ~]# 

用此 IP Pool 创建 calico 网络。

   # docker network create --driver calico --ipam-driver calico-ipam --subnet=17.2.0.0/16 my_net

此时运行容器将分配到指定 subnet 中的 IP。

    [root@host1 ~]# docker network create --driver calico --ipam-driver calico-ipam --subnet=17.2.0.0/16 my_net
    511cec9967a597fd8a6d32dce519e2d93764076c3fca9dedc56c89311c50a4a7
    [root@host1 ~]# docker container run --net my_net -ti busybox
    / # ip address show cali0
    11: cali0@if12: <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 17.2.119.0/32 brd 17.2.119.0 scope global cali0
           valid_lft forever preferred_lft forever
    / # 

当然也可以通过 --ip 为容器指定 IP,但必须在 subnet 范围之内。

    [root@host1 ~]# docker container run --net my_net --ip 17.2.3.11 -ti busybox
    / # ip address show cali0
    13: cali0@if14: <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 17.2.3.11/32 brd 17.2.3.11 scope global cali0
           valid_lft forever preferred_lft forever
    / # 

参考:https://www.cnblogs.com/CloudMan6/p/7509975.html

你可能感兴趣的:(docker)