常用的几种容器间通信方法

在我们日常服务部署和通信中,经常会遇到不同容器之间可能需要通信的问题,本文例举了几种容器间通信的方式以供参考

同一个Docker Compose配置内

在同一个 docker compose 配置文件中需要两个或多个容器之间进行通信,只需要两步:

  1. 保证所有容器都在一个网络内,最简单的方式为配置 network_mode: "bridge" 就不需要单独进行网络配置了
  2. 使用 links 参数挂载需要通信的容器
  3. 如果A容器的启动需要依赖B容器先启动,则需要配置 depends_on 参数

示例

实现 benti-imagesmysql 的通信

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-testmongo 的通信

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通信

这种通信方式和上面那种通信方式的远离是一样的,只是可以不需要配置域名等,也不需要做穿透,但是有两点需要特别注意:

  1. 需要保证所有容器在同一个网络内
  2. 容器重启后容器的内网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自动重启,也不会出错服务不匹配现象了。

方法

  1. 在容器查看内网IP
  2. 判断需要通信的容器是否在同一个网络内(最简单方法为compose配置中网络全部配置为network_mode: "bridge"

docker1.webp