我们都知道Docker容器之间是互相隔离的,不能互相访问,但如果有些依赖关系的服务要怎么办呢。下面介绍几种方法解决容器互访问题。
虚拟ip访问
安装Docker时,Docker会默认创建一个内部的桥接网络docker0,每创建一个容器分配一个虚拟网卡,容器之间可以根据ip互相访问。
[root@master ~]# ifconfig
docker0: flags=4419<UP,BROADCAST,RUNNING,PROMISC,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
inet6 fe80::42:ecff:fefb:4f56 prefixlen 64 scopeid 0x20<link>
ether 02:42:ec:fb:4f:56 txqueuelen 0 (Ethernet)
RX packets 439143754 bytes 128557512771 (119.7 GiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 204101251 bytes 111401928320 (103.7 GiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
显然上面网卡的地址是172.17.0.1,然后看一下其他容器的IP地址,如:
[root@master ~]# docker ps
132b54e8bf0f nginx "nginx -g 'daemon of…" 10 months ago Up 3 hours 0.0.0.0:11180->80/tcp nginx
64b298e41e38 tomcat:8.5 "catalina.sh run" 10 months ago Up 3 hours 0.0.0.0:8092->8080/tcp tomcatB
20573cd3ae78 tomcat:8.5 "catalina.sh run" 10 months ago Up 3 hours 0.0.0.0:8091->8080/tcp tomcatA
看一下nginx的IP地址:
[root@master ~]# docker inspect 132b54e8bf0f
...
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "4f2301f96036e312cf04bc2d893764f39493090e35d15a3d0bc46980a3817e9a",
"EndpointID": "1cc6ba035ff2f68d85db21651a2c0b09be94f54f84fd8cfca5ee779703fa1130",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.4",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:04",
"DriverOpts": null
}
}
地址是172.17.0.4,再看一下tomcatA的IP地址:
[root@master ~]# docker inspect tomcatA
...
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "4f2301f96036e312cf04bc2d893764f39493090e35d15a3d0bc46980a3817e9a",
"EndpointID": "70abb178c727cf4766bbd8e8cdb1fe1d285e4d1ad150459a6418f9ee7a428274",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.6",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:06",
"DriverOpts": null
}
}
地址是172.17.0.6,注意,这两个容器的Gateway都是172.17.0.1,因此,他们之间相互可以ping通。
如下:
[root@master ~]# docker exec -it tomcatB /bin/bash
root@64b298e41e38:/usr/local/tomcat# ip address
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 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
31: eth0@if32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:05 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.5/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
root@64b298e41e38:/usr/local/tomcat# ping 172.17.0.6
PING 172.17.0.6 (172.17.0.6) 56(84) bytes of data.
64 bytes from 172.17.0.6: icmp_seq=1 ttl=64 time=0.111 ms
64 bytes from 172.17.0.6: icmp_seq=2 ttl=64 time=0.092 ms
64 bytes from 172.17.0.6: icmp_seq=3 ttl=64 time=0.105 ms
64 bytes from 172.17.0.6: icmp_seq=4 ttl=64 time=0.100 ms
64 bytes from 172.17.0.6: icmp_seq=5 ttl=64 time=0.059 ms
^C
--- 172.17.0.6 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 3999ms
rtt min/avg/max/mdev = 0.059/0.093/0.111/0.020 ms
上面,首先进入容器tomcatB,然后获取IP地址是172.17.0.5,再去ping容器tomcatA的地址172.17.0.6,通过。
使用容器内IP地址这种方式,首先你必须知道每个容器的IP,但实际情况是你并不一定能获取到这个地址,在实际使用中并不实用。
如:
[root@datanode1 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2f81fe405433 mysql:5.7 "/.r/r docker-entryp…" 2 months ago Up 2 months r-mysql-mysql-1-30bfa217
有一个这样的mysql容器,进入容器后,你无法使用命令ifconfig
或者ip address
,因为容器就没有集成这些命令,然后用docker inspect
查看容器也发现IP地址为空
[root@datanode1 ~]# docker exec -it 2f81fe405433 /bin/bash
root@2f81fe405433:/# ifconfig
bash: ifconfig: command not found
root@2f81fe405433:/# ip address
bash: ip: command not found
root@2f81fe405433:/# exit
exit
[root@datanode1 ~]# docker inspect 2f81fe405433
...
"Networks": {
"none": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "801ce736d6cff60a8eab3e8bff5727f1b6ebaa89f2d53315514dfc3dbf112134",
"EndpointID": "0fee4ef4c035c10040da81166054df8d805fdd3f0ff3aa97e595baa05f71ff70",
"Gateway": "",
"IPAddress": "",
"IPPrefixLen": 0,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "",
"DriverOpts": null
}
}
link
运行容器的时候加上参数link。
运行第一个容器
docker run -it --name centos-1 docker.io/centos:latest
运行第二个容器
[root@CentOS ~]# docker run -it --name centos-2 --link centos-1:centos-1 docker.io/centos:latest
--link:参数中第一个centos-1是容器名,第二个centos-1是定义的容器别名(使用别名访问容器),为了方便使用,一般别名默认容器名。
[root@e0841aa13c5b /]# ping centos-1
PING centos-1 (172.17.0.7) 56(84) bytes of data.
64 bytes from centos-1 (172.17.0.7): icmp_seq=1 ttl=64 time=0.210 ms
64 bytes from centos-1 (172.17.0.7): icmp_seq=2 ttl=64 time=0.116 ms
64 bytes from centos-1 (172.17.0.7): icmp_seq=3 ttl=64 time=0.112 ms
64 bytes from centos-1 (172.17.0.7): icmp_seq=4 ttl=64 time=0.114 ms
此方法对容器创建的顺序有要求,如果集群内部多个容器要互访,使用就不太方便。
创建bridge网络
- 安装好docker后,运行如下命令创建bridge网络:
docker network create testnet
查询到新创建的bridge testnet
[root@master ~]# docker network create testnet
41b2f0c05d93aaf14eea6b686c9da6bcfb9b36b3ab4f6f81bc08b65d6b3ac935
[root@master ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
4f2301f96036 bridge bridge local
4ef93e2e7978 docker-taiga_default bridge local
2b3e95aceda3 host host local
34d4431a931c none null local
41b2f0c05d93 testnet bridge local
- 运行容器连接到testnet网络
使用方法:docker run -it --name <容器名> --network <bridge> --network-alias <网络别名> <镜像名>
[root@master ~]# docker run -it --name centos-1 --network testnet --network-alias centos-1 docker.io/centos:latest
[root@master ~]# docker run -it --name centos-2 --network testnet --network-alias centos-2 docker.io/centos:latest
- 从一个容器ping另外一个容器,测试结果如下
[root@0bce3262d2df /]# ping centos-1
PING centos-1 (172.20.0.2) 56(84) bytes of data.
64 bytes from centos-1.testnet (172.20.0.2): icmp_seq=1 ttl=64 time=0.158 ms
64 bytes from centos-1.testnet (172.20.0.2): icmp_seq=2 ttl=64 time=0.108 ms
64 bytes from centos-1.testnet (172.20.0.2): icmp_seq=3 ttl=64 time=0.112 ms
64 bytes from centos-1.testnet (172.20.0.2): icmp_seq=4 ttl=64 time=0.113 ms
- 若访问容器中服务,可以使用这用方式访问
<网络别名>:<服务端口号>
推荐使用这种方法,自定义网络,因为使用的是网络别名,可以不用顾虑ip是否变动,只要连接到docker内部bright网络即可互访。bridge也可以建立多个,隔离在不同的网段。
容器内脚本访问容器内服务
容器服务
1、以mysql:5.6镜像创建一个mysql容器服务 容器端口3306映射宿主机端口3307
启动后配置阿里云服务器安全组开放映射的端口
docker run -id -p 3307:3306 \
--name=my1 \
--network testnet \
--network-alias my1 \
-v $PWD/conf/myconf.d:/etc/mysql/conf.d \
-v $PWD/logs:/logs \
-v $PWD/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=root \
mysql:5.6
脚本创建
2、以centos:7基础镜像创建一个python脚本 查询mysql数据库中的内容
docker run -it \
--name=my2 \
--network testnet \
--network-alias my2 \
centos:7 \
bash
脚本
import pymysql
db = pymysql.connect("120.78.72.136","root","root","docker",port=3307)
cursor = db.cursor()
cursor.execute("SELECT * FROM test")
data = cursor.fetchone()
print (data)
db.close()
ip为宿主机ip 端口为容器映射到宿主机的端口
容器访问容器服务(离线)
s1容器放mysql服务,s2容器放一个python脚本能够查询s1容器内mysql数据库的内容
由上面方法创建bridge网络,s1和s2容器能够后互相ping通
创建s1容器(mysql)
docker run -id -p 3307:3306 \
--name=s1 \
--network testnet \
--network-alias s1 \
-v $PWD/conf/myconf.d:/etc/mysql/conf.d \
-v $PWD/logs:/logs \
-v $PWD/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=root \
mysql:5.6
容器端口3306映射宿主机端口3307,对外开放3307端口,若想让外部访问需配置安全组开放3307端口
docker exec -it s1 bash # 进入容器内
mysql -uroot -proot # 进入mysql数据库 创建库和表
创建s2容器(python脚本)
容器创建
docker run -it \
--name=my2 \
--network testnet \
--network-alias my2 \
centos:7 \
bash
脚本创建
import pymysql
db = pymysql.connect("s1","root","root","docker",port=3306)
cursor = db.cursor()
cursor.execute("SELECT * FROM test")
data = cursor.fetchone()
print (data)
db.close()
# s1 为网络别名 在我们创建容器时创建
# 3306 容器内的服务端口号
参考:https://www.cnblogs.com/songzhixue/p/12540152.html