1,现在有这么一个需求,我在一个容器中去访问另外一个容器之中的数据库?

如何实现呢?实现思路一

1,暴力的手段,直接吧数据库安装在本容器内(太暴力不推荐)。

2,因为默认的docker容器中网络都是桥接到docker0,所以不同的容器之间都是在同一个子网内,所以只需要在调用数据库的容器内

填写配置数据库所在的内网ip即可。

3,方案2看似完美,but,在实际生产中可能并不知到数据库所在的ip,即数据库所在的容器暂时没有创建,或者二次创建的时候ip可能发生变化,导致其他的容器需要修改。基于以上原因,我们可以直接吧数据库的端口映射出去,在另外的容器内通过宿主机的ip去访问。但是这样就相当于暴露在外面了。

4,针对这个问题,docker 有一个link参数,可以实现通过容器名实现互联。

演示一下

1.通过--link容器通信,给test2添加一个hosts解析记录
docker run -d --name test2 --link test1 busybox /bin/sh -c "while true;do sleep 3600;done"
test2可以ping通test1

5,但是--link是不推荐使用的,而是更强大的自定义docker网络链接容器

演示如下

1.新建一个docker网络
docker network create -d bridge my-net
-d 参数指定 Docker 网络类型,有 bridge overlay

2.连接容器
运行一个容器并连接到新建的 my-net 网络

$ docker run -it --rm --name busybox1 --network my-net busybox sh
打开新的终端,再运行一个容器并加入到 my-net 网络

$ docker run -it --rm --name busybox2 --network my-net busybox sh
再打开一个新的终端查看容器信息

$ docker container ls

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b47060aca56b busybox "sh" 11 minutes ago Up 11 minutes busybox2
8720575823ec busybox "sh" 16 minutes ago Up 16 minutes busybox1
下面通过 ping 来证明 busybox1 容器和 busybox2 容器建立了互联关系。

在 busybox1 容器输入以下命令

/ # ping busybox2
PING busybox2 (172.19.0.3): 56 data bytes
64 bytes from 172.19.0.3: seq=0 ttl=64 time=0.072 ms
64 bytes from 172.19.0.3: seq=1 ttl=64 time=0.118 ms
用 ping 来测试连接 busybox2 容器,它会解析成 172.19.0.3。

同理在 busybox2 容器执行 ping busybox1,也会成功连接到。

/ # ping busybox1
PING busybox1 (172.19.0.2): 56 data bytes
64 bytes from 172.19.0.2: seq=0 ttl=64 time=0.064 ms
64 bytes from 172.19.0.2: seq=1 ttl=64 time=0.143 ms
这样,busybox1 容器和 busybox2 容器建立了互联关系。

2,上面说到的问题大多都是在同一个宿主机上的,那么如果是跨宿主机容器之间如何通信呢?前面的文章提到几种方式。

在这演示下通过隧道的方式实现(VXLAN)

1,装备环境两台能够相互ping通的主机。(docker-node1和docker-node2)

#docker-node1 里面ping 172.28.128.4 直接访问node2
ping 172.28.128.4
#docker-node2 里面ping 172.28.128.3 直接访问node1
ping 172.28.128.3

现在用docker内部的ip 互相ping

也就是docker1的172.17.0.2 ping一下docker2的172.17.0.3 其实是ping不通的,因为他们不在同一个网络,如果想通信有没有方式,其实暴露端口的方式-p 也是可以的,还有一个更好的方式 就是通过vxlan的方式。

什么是VXLAN?

VXLAN-Virtual eXtensible Local Area Network(虚拟化可扩展局域网)

VXLAN是NVO3(Network Virtualization over Layer3)中的一种网络虚拟化技术,通过将VM或物理服务器发出的数据包封装在UDP中,并使用物理网络的IP/MAC作为报文头进行封装,然后在IP网络上传输,到达目的地后由隧道终结点解封装并将数据发送给目标虚拟机或物理服务器。

docker1内部的容器和docker2内部的容器之间的通信。通过的技术是:etcd的分布式存储方式来完成。

分布式主要就是为了多台机器,每个机器里面的容器分到的ip都不相同,这样让这些容器组织成一个网络的话,他们之前就可以进行通信了,因为ip和名称都是唯一的。不会带来冲突。

docker-node1上安装etcd

sudo yum -y install wget
wget https://github.com/coreos/etcd/releases/download/v3.0.12/etcd-v3.0.12-linux-amd64.tar.gz
tar zxvf etcd-v3.0.12-linux-amd64.tar.gz
cd etcd-v3.0.12-linux-amd64
#查看ip地址 172.28.128.3
ip a


#注意ip地址的修改,不同的机器可能不相同。通过ip a查看
nohup ./etcd --name docker-node1 --initial-advertise-peer-urls http://172.28.128.3:2380 \
--listen-peer-urls http://172.28.128.3:2380 \
--listen-client-urls http://172.28.128.3:2379,http://127.0.0.1:2379 \
--advertise-client-urls http://172.28.128.3:2379 \
--initial-cluster-token etcd-cluster \
--initial-cluster docker-node1=http://172.28.128.3:2380,docker-node2=http://172.28.128.4:2380 \
--initial-cluster-state new&

docker-node2 上安装etcd

sudo yum -y install wget
wget https://github.com/coreos/etcd/releases/download/v3.0.12/etcd-v3.0.12-linux-amd64.tar.gz
tar zxvf etcd-v3.0.12-linux-amd64.tar.gz
cd etcd-v3.0.12-linux-amd64
#查看ip地址 172.28.128.4
ip a


#注意ip地址的修改,不同的机器可能不相同。通过ip a查看
nohup ./etcd --name docker-node1 --initial-advertise-peer-urls http://172.28.128.4:2380 \
--listen-peer-urls http://172.28.128.4:2380 \
--listen-client-urls http://172.28.128.4:2379,http://127.0.0.1:2379 \
--advertise-client-urls http://172.28.128.4:2379 \
--initial-cluster-token etcd-cluster \
--initial-cluster docker-node1=http://172.28.128.3:2380,docker-node2=http://172.28.128.4:2380 \
--initial-cluster-state new&

docker-node1 和 docker-node2 共同操作查看状

./etcdctl cluster-heallth
sudo service docker stop

docker-node1 和docker-node2 分别操作

docker-node1

sudo /usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-store=etcd://172.28.128.3:2379 --cluster-advertise=172.28.128.3:2375&
exit
vagrant ssh docker-node1
sudo docker network ls

docker-node2

sudo /usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-store=etcd://172.28.128.4:2379 --cluster-advertise=172.28.128.4:2375&
exit
vagrant ssh docker-node2
sudo docker network ls

docker-node1

sudo docker network create -d overlay demo
sudo docker network ls

docker-node2

#docker-node1创建了overlay网络后,node2也创建了。这是为什么呢?其实这就是etcd帮咱们做的。
sudo docker network ls

docker-node1 查看网络信息

sudo docker network inspect demo

创建连接demo网络的容器

创建docker-node1内部的容器tes11t1

sudo docker run -d --name tes11t1--net demo busybox sh -c "while true; do sleep 3600; done"
sudo docker ps

创建docker-node2内部的容器tes11t1

#说有相同容器已经存在了,不允许创建。如果在同一台docker机器上不允许名称一样的,说明这2个docker-node1 和docker-node2 已经在同一个网络空间内了
sudo docker run -d --name tes11t1--net demo busybox sh -c "while true; do sleep 3600; done"


更改一个名称,可以成功创建

sudo docker run -d --natme test111--net demo busybox sh -c "while true; do sleep 3600; done"

sudo docker ps

docker-node1中的容器,查看tes11t1的ip地址
sudo docker exec tes11t1 ip a

docker-node2中的容器,查看tes11t1的ip地址

sudo docker exec test111 ip a

查看下demo的network

sudo docker network inspect demo

试试2个容器能否互相ping通

docker-node2

sudo docker exec test111 ping 10.0.0.2
sudo docker exec test111 ping tes11t1

docker-node1

sudo docker exec tes11t1 ping 10.0.0.3
sudo docker exec tes11t1 ping test111

PS:本次通过第三方工具etcd分布式的方式完成2台机器,2个容器组件网络,实现相互的访问,这里只是通过ping的方式,如果按照上次说的 flask-redis,可以一台是redis 一台是flask 应该也是可以通信的。多机的方式基本就是这样。