1 关于docker的网络通信
1.1 宿主机和容器的通信
在单机环境中:宿主机上的Docker Daemon启动时会为宿主机创建一块名为docker0的虚拟网卡,在Docker初始化时系统会分配一个IP地址绑定在这个网卡上。如
5: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:a1:3f:a3:d0 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:a1ff:fe3f:a3d0/64 scope link
valid_lft forever preferred_lft forever
docker0的角色就是一个宿主机与容器间的网桥,作为一个二层交换机,负责数据包的转发。
当使用docker创建一个容器时,如果使用了bridge模式,docker会创建一个vet对,一端绑定到docker0上,而另一端则作为容器的eth0虚拟网卡,比如docker容器中的网卡情况如下:
root@a5458e9d4096:/workspace/webdemo/controller# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.9 netmask 255.255.0.0 broadcast 172.17.255.255
ether 02:42:ac:11:00:09 txqueuelen 0 (Ethernet)
RX packets 24 bytes 1600 (1.6 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 16 bytes 804 (804.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
loop txqueuelen 1000 (Local Loopback)
RX packets 10 bytes 1348 (1.3 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 10 bytes 1348 (1.3 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
简述为:宿主机的docker0和容器的eth0
过程:
运行容器设置端口映射实际上是docker会通过iptables创建一条nat规则。
数据包发送到宿主机的端口,该端口将数据包转发到docker0网关,docker0网关将通过广播的方式找到对应ip的容器,将数据包转发到该容器的端口上。
docker要跟外部的网络进行通信,也是通过docker0和iptables的nat进行转发。
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "e2e12bf8a8ab187be867478a3d29c3b3a233cb85e961a870ccecae3fba9b2184",
"EndpointID": "26ce7607c932c80ad7e977ecc67d90c945807e24eca95ce2123aad9e122df9a2",
"Gateway": "172.17.0.1", // 指向宿主机的虚拟网卡docker0
"IPAddress": "172.17.0.9", // 容器的网卡地址
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:09",
"DriverOpts": null
}
}
案例
问题1:容器内可以使用curl -X GET “http://127.0.0.1:80/api/v1/items” 访问,在宿主机中不可以访问?
分析:
首先确定了web服务是启动的,因为在容器中是可以访问的。
宿主机不可以访问说明容器和宿主机是无法通信的。
那宿主机和容器怎么通信呢?
网络模式选择桥接模式,然后进行端口映射,这样通过宿主机的端口就可以访问到容器的端口了。
然后发现我的问题:
web服务在容器中运行的端口是80(默认运行的端口,我在程序中没有指定),然后我暴露容器的接口是8080,所以我访问8080是访问不到web服务的。
解决办法:
- 将web服务的端口暴露在8080
- 映射主机的端口映射到80
如:docker run -d -p 8064:80 --net=bridge --name=hcy_test hcy_test_webdemo:1.0
容器内部可以通过curl -X GET “http://127.0.0.1:80/api/v1/items”
这样在宿主机可以通过暴露的端口 curl -X GET “http://127.0.0.1:8064/api/v1/items”
远程主机可以通过宿主主机的ip地址来访问,如 curl -X GET “http://10.67.43.10:8064/api/v1/items”
1.2 容器与容器互联
1.2.1 两个容器的简单连接
方法一:
创建一个网络,然后两个容器运行的时候都接入这个网络,然后容器之间就可以互相通信了。
参考网址:菜鸟教程
方法二:
通过docker run --link参数实现连接
举个例子:
需求:web容器能够访问db数据库容器
步骤1:实例化数据库容器
docker run -d --name db training/postgres
步骤2:实例化web容器连接到数据库容器
docker run -d -P --name web --link db:db training/webapp python app.y
步骤3:测试
在web容器中,ping db,看是否ping通
或者查看配置文件:
cat /etc/hosts
在web容器中查看hosts是否有db
参考:Dock人技术从入门到精通第75页
1.2.2 多个容器的连接(使用Docker Compose)
背景:一个完整的项目通常需要多个容器互相配合,如一个web容器,会需要后端的数据库服务容器,前台的负载均衡容器。
编写docker-compose.yml
- 几个概念
任务:一个容器
服务:同意镜像实例化的多个容器的集合
服务栈:多个服务,如web服务、数据库服务共同构成web服务栈
Compose默认管理的是服务栈,通过子命令可以对栈中的多个服务进行管理 - 使用docker compose的三个步骤
- 使用 Dockerfile 定义应用程序的环境。
- 使用 docker-compose.yml 定义构成应用程序的服务,这样它们可以在隔离环境中一起运行。
- 最后,执行 docker-compose up 命令来启动并运行整个应用程序。
详细配置指令见菜鸟教程
举个例子:
一个Python的web应用:django的web容器配合redis容器进行通信
1、实例化redis容器
如:
$ docker pull redis
$ docker run -d --name=redis -p 6379 redis
2、实例化Django容器连接到redis容器
$ docker run -it --name=app -p 8080:8000 -v /code:/usr/src/app --link=redis:db django bash
参数说明:
-v /code:/usr/src/app 表示把宿主机上的/code目录挂载到容器内的/usr/src/app目录,可以通过直接管理宿主机上的挂载目录来管理容器内部的挂载目录。
–link=redis:db 表示把redis容器以db别名与该容器建立关系,在该容器内以db作为主机名表示了redis容器的主机地址。
3、测试Django容器是否连接到redis容器
ping db
参考地址:https://zhuanlan.zhihu.com/p/26418829