一、DOCKER 容器之间进行互相通信

容器之间互通

新建两个容器
docker run -d —name box1 busybox /bin/sh -c “while true;do sleep 3600;done”

docker run -d —name box2 busybox /bin/sh -c “while true;do sleep 3600;done”
进入box1 ping box2
docker exec -it ac1aa7242949 /bin/sh
ping 172.17.0.3
表明新建的两个容器之间是可以互通的,他们之间通过bridge docker0进行通信,docker0为他们分别组了一对
Docker容器跨宿主机通信环境搭建及常见问题 - 图1

为新建的容器指定bridge网络

创建新的bridge网络
docker network ls 查看现在的网络

docker network create -d bridge mybridge 创建自己的bridge
创建容器并且指定bridge
docker run -d —name box5 —network mybridge busybox /bin/sh -c “while true;do sleep 3600;done”

docker run -d —name box6 —network mybridge busybox /bin/sh -c “while true;do sleep 3600;done”
运用自己的创建的bridge两个容器之间会自动link
docker exec -it ac1aa7242949 /bin/sh
ping box5

一张bridge network的图,表明容器之间可以互通,还可以链接互联网

Docker容器跨宿主机通信环境搭建及常见问题 - 图2

二、Docker容器跨主机通信之:直接路由方式

概述

就目前Docker自身默认的网络来说,单台主机上的不同Docker容器可以借助docker0网桥直接通信,这没毛病,而不同主机上的Docker容器之间只能通过在主机上用映射端口的方法来进行通信,有时这种方式会很不方便,甚至达不到我们的要求,因此位于不同物理机上的Docker容器之间直接使用本身的IP地址进行通信很有必要。再者说,如果将Docker容器起在不同的物理主机上,我们不可避免的会遭遇到Docker容器的跨主机通信问题。本文就来尝试一下。
**



情景构造

如下图所示,我们有两个物理主机1和主机2,我们在各自宿主机上启动一个centos容器,启动成功之后,两个容器分别运行在两个宿主机之上,默认的IP地址分配如图所示,这也是Docker自身默认的网络。

两台主机上的容器如何通信?
此时两台主机上的Docker容器如何直接通过IP地址进行通信?
一种直接想到的方案便是通过分别在各自主机中 添加路由 来实现两个centos容器之间的直接通信。我们来试试吧



方案原理分析

由于使用容器的IP进行路由,就需要避免不同主机上的容器使用了相同的IP,为此我们应该为不同的主机分配不同的子网来保证。于是我们构造一下两个容器之间通信的路由方案,如下图所示。

容器间通信
各项配置如下:

  • 主机1的IP地址为:192.168.145.128
  • 主机2的IP地址为:192.168.145.129
  • 为主机1上的Docker容器分配的子网:172.17.1.0/24
  • 为主机2上的Docker容器分配的子网:172.17.2.0/24

这样配置之后,两个主机上的Docker容器就肯定不会使用相同的IP地址从而避免了IP冲突。
我们接下来 定义两条路由规则 即可:

  • 所有目的地址为172.17.1.0/24的包都被转发到主机1上
  • 所有目的地址为172.17.2.0/24的包都被转发到主机2上

综上所述,数据包在两个容器间的传递过程如下:

  • 从container1 发往 container2 的数据包,首先发往container1的“网关”docker0,然后通过查找主机1的路由得知需要将数据包发给主机2,数据包到达主机2后再转发给主机2的docker0,最后由其将数据包转到container2中;反向原理相同,不再赘述。

我们心里方案想的是这样,接下来实践一下看看是否可行。



实际试验

  • 0x01. 分别对主机1和主机2上的docker0进行配置

编辑主机1上的 /etc/docker/daemon.json 文件,添加内容:"bip" : "ip/netmask"

  1. { "bip", "172.17.1.252/24" }

编辑主机2上的 /etc/docker/daemon.json 文件,添加内容:"bip" : "ip/netmask"

  1. { "bip", "172.17.2.252/24" }
  • 0x02. 重启docker服务

主机1和主机2上均执行如下命令重启docker服务以使修改后的docker0网段生效

  1. systemctl restart docker
  • 0x03. 添加路由规则

主机1上添加路由规则如下:

  1. route add -net 172.17.2.0 netmask 255.255.255.0 gw 192.168.145.129

主机2上添加路由规则如下:

  1. route add -net 172.17.1.0 netmask 255.255.255.0 gw 192.168.145.128
  • 0x04. 配置iptables规则

主机1上添加如下规则:

  1. iptables -t nat -F POSTROUTING
  2. iptables -t nat -A POSTROUTING -s 172.17.1.0/24 ! -d 172.17.0.0/16 -j MASQUERADE

主机2上添加如下规则:

  1. iptables -t nat -F POSTROUTING
  2. iptables -t nat -A POSTROUTING -s 172.17.2.0/24 ! -d 172.17.0.0/16 -j MASQUERADE
  • 0x05. 启动容器

主机1上启动centos容器:

  1. docker run -it --name container1 centos /bin/bash

主机2上启动centos容器:

  1. docker run -it --name container2 centos /bin/bash
  • 0x06. 容器间直接通信

好了,现在两容器可以互ping了

container1 ping container2

container2 ping container1

三、Docker容器跨主机通信之:Calico插件方式

注意:Calico v3以上版本已经不支持Docker进行通信,并且针对ARM架构3.0版本之前的需要自己编译相关可执行文件进行使用.

一、环境配置

操作系统都是ubuntu16.04
host:10.180.149.36 x86
host1:10.180.149.73 Arm
host2:10.180.149.74 Arm

二、安装Etcd

从Github上下载etcd安装包,并将etcd保存在/usr/local/bin文件中
命令行示例:
https://github.com/etcd-io/etcd/releases
建议直接下载安装包,然后复制到相关文件中
完成后启动端口监听
etcd -listen-client-urls http://10.180.149.36:2379 -advertise-client-urls http://10.180.149.36:2379
别注意一个细节:
上面的命令执行后会一直在前台执行中,不能关闭当前终端窗口,关闭当前窗口后,上面启动的etcd集群程序就会关闭!!
正确的做法是将其切到后台执行,在上面etcd集群程序启动后,依次:
1)按键ctrl+z 将其程序挂起,会出现一个序列号,一般为1
2)执行命令:bg 1 1就是上面挂起后出现的序列号
3)执行命令disown -a 这样就将这个程序切到后台运行了
启动程序后:
修改在host1与host2中的配置文件 /etc/systemd/system/docker.service
Docker.service 示例如下:

  1. [Unit]
  2. Description=Docker Application Container Engine
  3. Documentation=https://docs.docker.com
  4. BindsTo=containerd.service
  5. After=network-online.target firewalld.service containerd.service
  6. Wants=network-online.target
  7. Requires=docker.socket
  8. [Service]
  9. Type=notify
  10. # the default is not to use systemd for cgroups because the delegate issues still
  11. # exists and systemd currently does not support the cgroup feature set required
  12. # for containers run by docker
  13. ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2376 --containerd=/run/containerd/containerd.sock --cluster-store=consul://10.180.149.36:8500 --cluster-advertise=eth0:2376 --cluster-store=etcd://10.180.149.36:2379
  14. ExecReload=/bin/kill -s HUP $MAINPID
  15. TimeoutSec=0
  16. RestartSec=2
  17. Restart=always
  18. # Note that StartLimit* options were moved from "Service" to "Unit" in systemd 229.
  19. # Both the old, and new location are accepted by systemd 229 and up, so using the old location
  20. # to make them work for either version of systemd.
  21. StartLimitBurst=3
  22. # Note that StartLimitInterval was renamed to StartLimitIntervalSec in systemd 230.
  23. # Both the old, and new name are accepted by systemd 230 and up, so using the old name to make
  24. # this option work for either version of systemd.
  25. StartLimitInterval=60s
  26. # Having non-zero Limit*s causes performance problems due to accounting overhead
  27. # in the kernel. We recommend using cgroups to do container-local accounting.
  28. LimitNOFILE=infinity
  29. LimitNPROC=infinity
  30. LimitCORE=infinity
  31. # Comment TasksMax if your systemd version does not support it.
  32. # Only systemd 226 and above support this option.
  33. TasksMax=infinity
  34. # set delegate yes so that systemd does not reset the cgroups of docker containers
  35. Delegate=yes
  36. # kill only the docker process, not all processes in the cgroup
  37. KillMode=process
  38. [Install]
  39. WantedBy=multi-user.target

重启Docker.service服务

  1. systemctl daemon-reload && systemctl restart docker.service

三、部署Calico

在host1和host2中部署calico网络,注意此处要安装Calico 3.0以下版本

  1. curl -O -L https://github.com/projectcalico/calicoctl/releases/download/v2.6.0/calicoctl
  2. chmod +x calicoctl
  3. mv calicoctl /usr/local/bin/

一、配置文件

配置calicoctl以访问您的数据存储,配置文件默认情况下,calicoctl将在上查找配置文件/etc/calico/calicoctl.cfg

  1. apiVersion: projectcalico.org/v3
  2. kind: CalicoAPIConfig
  3. metadata:
  4. spec:
  5. datastoreType: etcdv3
  6. etcdEndpoints: "https://127.0.0.1:2379"
  7. etcdCACert: |
  8. -----BEGIN CERTIFICATE-----
  9. MIICKzCCAZSgAwIBAgIBAzANBgkqhkiG9w0BAQQFADA3MQswCQYDVQQGEwJVUzER
  10. MA8GA1UEChMITmV0c2NhcGUxFTATBgNVBAsTDFN1cHJpeWEncyBDQTAeFw05NzEw
  11. MTgwMTM2MjVaFw05OTEwMTgwMTM2MjVaMEgxCzAJBgNVBAYTAlVTMREwDwYDVQQK
  12. EwhOZXRzY2FwZTENMAsGA1UECxMEUHViczEXMBUGA==
  13. -----END CERTIFICATE-----
  14. etcdCert: |
  15. -----BEGIN CERTIFICATE-----
  16. gI6iLXgMsp2EOlD56I6FA1jrCtNb01XQvX3eyFuA6g5T1jWGYBDtvQb0WRVkdUy9
  17. L/uK+sHQwtloCSuakcQAsWV9bajCQtHX8XGu25Yz56kpJ/OJjcishxT6pc/sthum
  18. A5PX739JsNUi/p5aG+H/6eNx+ukJP7QaM646YCfS5i8S9DJUvim+/BSlKi2ZiOCd
  19. 0MYH4Xb7lmAOTNmTvSYpKo9J2fZ9erw0MYSBTyjh6F7PRbHBiivgUnJfGQ==
  20. -----END CERTIFICATE-----
  21. etcdKey: |
  22. -----BEGIN RSA PRIVATE KEY-----
  23. k0dWj16h9P6TvfcNl2iwT4VIwx0uy2faWBED1DrCJcuQCy5nPrts2ZIaAWPi1t3t
  24. VbDKQvs+KXBEeqh0qYcYkejUXqIF0uKUFLjiQmZssjpL5RHqqWuYKbO87n+Jod1L
  25. TjGRHdbP0zF2U0LdjM17rc2hpJ3qrmgJ7pOLzbXMcOr+NP1ojRCArXhQ4iLs7D8T
  26. eHw9QH4luJYtnmk7x03izLMQdLWcKnUbqh/xOVPyazgJHXwRxwNXpMsBVGY=
  27. -----END RSA PRIVATE KEY-----

二、配置环境变量

如果calicoctl无法找到,读取或访问配置文件,它将检查一组特定的环境变量。

  1. ETCD_ENDPOINTS=http://myhost1:2379 calicoctl get bgppeers

附:官方安装文档https://docs.projectcalico.org/getting-started/clis/calicoctl/install

三、下载相关Docker镜像文件:

  1. docker pull calico/node
  2. docker pull quay.io/calico/node
  3. docker pull calico/node-libnetwork

四、运行calicoctl

  1. calicoctl node run --node-image=quay.io/calico/node:v2.0.6-c /etc/calico/calicoctl.cfg

启动过程如下:
① 设置主机网络,例如 enable IP forwarding。
② 下载并启动 calico-node 容器,calico 会以容器的形式运行(与 weave 类似)。
③ 连接 etcd。
④ calico 启动成功。

五、创建calico网络:

在host1和host2中运行以下命令创建网络:

  1. docker network create --driver calico --ipam-driver calico-ipam ckl_calico

六、在calico网络中运行容器:

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

  1. docker container run --net cali_net1 --name bbox1 -tid busybox

在host2中运行容器bbox2 ,也连接到cal_net1:

  1. docker container run --net cali_net1 --name bbox2 -tid busybox

七、测试calico网络连通性:

验证测试bbox1与bbox2 的连通性如下:

  1. docker exec bbox1 ping -c bbox2

四、部署常见问题及解决方式

  1. Calico node ‘calico01’ is already using the IPv4 address 172.16.91.205:Docker容器跨宿主机通信环境搭建及常见问题 - 图3imageDocker容器跨宿主机通信环境搭建及常见问题 - 图4image
    • 方法一:
      如果calico数据不重要的话,可以根据图片中的操作步骤进行删除
      etcdctl rm /calico —recusive
    • 方法二:
      根据原因是因为:
      多个calico服务,绑定在同一个IP上导致的,
      因此,需要检查calico服务的配置文件,看看是不是ip绑定重复了。
  2. calicoctl rm /calico —recursive
  3. calicoctl node status no IPv4 peers foundDocker容器跨宿主机通信环境搭建及常见问题 - 图5image原因:
    • 其他节点calico服务没有启动
    • ip绑定错误,如下所示:
      Docker容器跨宿主机通信环境搭建及常见问题 - 图6
      image
  4. Error response from daemon: Post http://%2Frun%2Fdocker%2Fplugins%2Fcalico-ipam.sock/IpamDriver.RequestPool: dial unix /run/docker/plugins/calico-ipam.sock: connect: connection refused
    Docker容器跨宿主机通信环境搭建及常见问题 - 图7
    image
  5. docker calico 环境,创建容器的容器不能ping通主机
    现象一:
    没有创建路由, 如下图所示:
    Docker容器跨宿主机通信环境搭建及常见问题 - 图8
    image

    主机和容器互相不能ping通。
    也不报错。
    原因是:配置文件
    Docker容器跨宿主机通信环境搭建及常见问题 - 图9
    image

    也不报错。
  6. docker network create —driver calico —ipam-driver calico-ipam net2 创建网络后,其他节点上没有同步网络信息?
    Docker容器跨宿主机通信环境搭建及常见问题 - 图10
    image

    Docker容器跨宿主机通信环境搭建及常见问题 - 图11
    image
    原因之一:
        其中两个节点上的docker,并没有从etcd里获取数据,因此并没有进行同步。
        解决措施:
        添加——cluster-store参数即可。
    原因之二:
        calico的libnetwork进程出问题
    Docker容器跨宿主机通信环境搭建及常见问题 - 图12
    libenetwork进程

    原因之三:
        etcd出问题
  7. ERROR: Unable to access datastore to query node configuration
    Docker容器跨宿主机通信环境搭建及常见问题 - 图13
    image
  8. Idle BGP Error: Bad BGP identifier
    现象如下图所示:
    Docker容器跨宿主机通信环境搭建及常见问题 - 图14
    master节点

    Docker容器跨宿主机通信环境搭建及常见问题 - 图15
    node1节点

    Docker容器跨宿主机通信环境搭建及常见问题 - 图16
    node2节点

    但是,这种情况,服务好像还可以使用
  9. Failed to create Calico API client: context deadline exceeded
    Docker容器跨宿主机通信环境搭建及常见问题 - 图17
    Failed to create Calico API client: context deadline exceeded

    原因是:
    calicoctl 客户端读取配置文件/etc/calico/calicoctl.cfg里配置的etcdEndpoints跟etcd集群访问策略不匹配,
    etcd集群是非安全访问方式,因此,只需要将etcdEndpoints里的https 改成 http即可了。
    Docker容器跨宿主机通信环境搭建及常见问题 - 图18
    解决措施