常用的几种容器间通信方法
在我们日常服务部署和通信中,经常会遇到不同容器之间可能需要通信的问题,本文例举了几种容器间通信的方式以供参考
同一个Docker Compose配置内
在同一个 docker compose
配置文件中需要两个或多个容器之间进行通信,只需要两步:
- 保证所有容器都在一个网络内,最简单的方式为配置
network_mode: "bridge"
就不需要单独进行网络配置了 - 使用
links
参数挂载需要通信的容器 - 如果A容器的启动需要依赖B容器先启动,则需要配置
depends_on
参数
示例
实现 benti-images
到 mysql
的通信
version: '3'
services:
mysql:
container_name: mysql
restart: always
image: docker.io/mysql:ninemax
environment:
MYSQL_ROOT_PASSWORD: mysql
volumes:
- ./mysql/:/var/lib/mysql/
ports:
- "3308:3306"
networks:
- mynet
benti-images:
build: .
container_name: benti-images
restart: always
image: benti-images:11.0
#links链接到其它服务中的容器,配置后benti-images容器就可以用mysql连接数据库,如:mysql:3306
links:
- mysql
ports:
- "8080:7080"
#tty: true 配置是为了容器保持后台运行,不退出。如果不加这个参数,benti-images容器会不断退出不断重启
tty: true
networks:
- mynet
networks:
mynet:
driver: bridge
不同Docker Compose 配置内
当然,有时候我们可能并不想要把所有容器都放在一个docker compose
配置内,例如我有几个容器的数据库服务都使用的是mysql
容器,那么我肯定期望将mysql
容器单独配置,让别的容器直接跨compose
进行通信。
重点配置项就是external_links
,当然,通信的前提依然是所有容器都在相同的网络内。
示例
实现docker-test
到 mongo
的通信
version: '3'
services:
mongodb:
container_name: mongo
image: mongo
ports:
- '27017:27017'
volumes:
- /opt/docker_mongo/data/db:/data/db
network_mode: bridge
version: '3'
services:
app:
container_name: docker-test
restart: always
build: .
image: docker-test:1.0
ports:
- '8150:4000'
network_mode: bridge
external_links:
- mongo
使用外部网络通信
这种方式的要求就很宽松了,但是对实际情况的要求可能比较高。
- 如果你是内网(192.168.x.x)的话,可以在服务器主机中配置hosts,修改为
域名 - IP
方式访问(必须) - 如果你有公网IP(动态公网IP可以使用穿透方式自动解析IP到你的域名上)
不管你是以上哪种网络情况,最好都使用域名的方式进行访问通信,因为:
- 使用
192.168.x.x
的IP容器只会在容器内查找 - 使用动态公网IP如果路由器重新拨号会导致IP发生变化,所以最好也使用动态解析到的域名
- 使用固定IP是可以避免以上两种情况,但是如果IP变化也会产生以上问题,毕竟域名便宜,固定IP贵
有了解析出来的域名后,直接在需要通信的容器内直接配置相关参数即可,例如想要和mysql通信:mysql.cnkj.site:3306
相同容器局域网内IP通信
这种通信方式和上面那种通信方式的远离是一样的,只是可以不需要配置域名等,也不需要做穿透,但是有两点需要特别注意:
- 需要保证所有容器在同一个网络内
- 容器重启后容器的内网IP地址会发生变化
设置容器固定IP
设置容器固定IP的方法主要用来解决前面提到的第一个问题,非必须
利用 docker ipam
分配固定IP
这里用到 docker ipam
就是 IP Address Management Driver
,docker官方文档 查看
version: '3'
services:
web:
image: fukoy/nginx-php-fpm:php7.4
container_name: server-phpnginx-tp1
restart: always
volumes:
- ./www:/usr/share/nginx/typecho/ #typecho网站文件
- ./nginx/conf.d:/etc/nginx/conf.d #nginx配置文件夹
- ./nginx/nginx.conf:/etc/nginx/nginx.conf #nginx配置文件
depends_on:
- mysql
networks:
default:
ipv4_address: 172.18.0.2
proxy:
mysql:
image: mariadb
restart: always
container_name: server-mysql-tp1
volumes:
- ./mysql/data:/var/lib/mysql
- ./mysql/logs:/var/log/mysql
- ./mysql/conf:/etc/mysql/conf.d
env_file:
- mysql.env
networks:
default:
ipv4_address: 172.18.0.3
networks:
proxy:
external: true
default:
driver: bridge
ipam:
config:
- subnet: 172.19.0.0/16
可以看到,重点在于配置:
- 设置固定IP
networks:
default:
ipv4_address: 172.18.0.3
- 设置网络
ipam:
config:
- subnet: 172.19.0.0/16
但这些IP只能用于这个内部网络容器间相互访问,要打通与其他网络间的访问,至少要有一个容器要同时在两个网络内。
说得更白一点就是:
这样分配的IP,是以这个yml为单位的小局域网,只能是这个yml中创建的容器间能互相访问。
其他yml创建的容器访问不到这网络里面的容器。
因此,这种方法并不适合traefik做反代的配置。
先建外部网络,再给容器分配IP
要明确一点就是,不同容器间想互通,得在同一个网络中。
而这里我们流量都交给的traefik处理,用traefik进行反代,traefik接管了宿主机的80和443端口。
因此要成功把流量导入其他独立容器,必须要将service容器与traefik置于同一个网络中,比如我这里创建的proxy网络。
因此,不同的docker-compose.yml,都要有一个容器与traefik处于同一网段中。
这时候最佳的解决办法就是先定义一个外部网络,再分别在每个docker-compose中用ipv4_address固定IP。
创建外部网络
当然,你可以直接用默认的桥接网络
#创建proxy网络
docker network create --driver bridge --subnet=172.18.0.0/24 proxy
在不同的docker-compose指定IP
例如:
version: '3.7'
services:
v2ray:
image: alphacodinghub/v2ray-nginx
expose:
- 13307
container_name: v2ray
volumes:
- ./www/html:/var/www/html
- ./nginxconf/conf.d:/etc/nginx/conf.d
- ./v2rayconf:/etc/v2ray
restart: always
networks:
proxy:
ipv4_address: 172.18.0.3
networks:
proxy:
external: true
终上所述,利用docker-compose.yml
给容器指定固定IP很简单,直接在networks上指定即可,命令:ipv4_address: 内部ip
networks:
default:
proxy:
ipv4_address: 172.18.0.4
前提是,这个ip段必须在你在第一步开始之初就创建好的网络中,也就是docker network create --driver bridge --subnet=172.18.0.0/24 proxy
内。
这样给不同的容器分配好固定IP,就算VPS自动重启,也不会出错服务不匹配现象了。
方法
- 在容器查看内网IP
- 判断需要通信的容器是否在同一个网络内(最简单方法为compose配置中网络全部配置为
network_mode: "bridge"
)