欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

docker-compose 如何访问外部容器? docker容器间访问的网络设置浅谈

程序员文章站 2022-05-15 13:10:30
...

前言

docker-compose是用于定义和运行多容器 Docker 应用程序的工具,通过docker-compose可以方便地协调多个容器的运行。
一般在使用docker-compose启动服务时,被同一个docker-compose.yml定于的服务(容器)会运行在一个隔离环境中,也就是说在这个环境中的容器是不能直接访问(如果没有设置的话)当前docker-compose外部的其它容器的,那么如何设置才能使compose中的容器访问外部容器呢?
本文以能够使compose启动的容器可以访问docker中已存在的mysql容器为目标进行讲解。docker容器间互相访问和docker-compose访问外部容器的原理是相同的。

环境

CentOS7 虚拟机环境
mysql 5.7
docker 19.03
docker-compose 1.29.1

问题描述

安装Docker时,Docker会默认创建一个内部的桥接网络docker0,每创建一个容器分配一个虚拟网卡,容器之间可以根据ip互相访问。

[[email protected] ~]# 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地址,如:

[[email protected] ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                               NAMES
13ed457ceeff        redis               "docker-entrypoint.s…"   6 months ago        Up 5 hours          0.0.0.0:6379->6379/tcp              redis
b7c1837830d4        mysql:5.7           "docker-entrypoint.s…"   6 months ago        Up 6 minutes        0.0.0.0:3306->3306/tcp, 33060/tcp   mysql

mysql的这个容器(b7c1837830d4)已经提前创建,并进行了端口映射,映射到了宿主机的3306端口,可以在外部直接访问本mysql;
查看docker内mysql的地址:

[[email protected] ~]# docker inspect b7c1837830d4
...
  "Networks": {
       "bridge": {
           "IPAMConfig": null,
           "Links": null,
           "Aliases": null,
           "NetworkID": "4f2301f96036e312cf04bc2d893764f39493090e35d15a3d0bc46980a3817e9a",
           "EndpointID": "1cc6ba035ff2f68d85db21651a2c0b09be94f54f84fd8cfca5ee779703fa1130",
           "Gateway": "172.17.0.1",   //关键
           "IPAddress": "172.17.0.2", //关键
           "IPPrefixLen": 16,
           "IPv6Gateway": "",
           "GlobalIPv6Address": "",
           "GlobalIPv6PrefixLen": 0,
           "MacAddress": "02:42:ac:11:00:04",
           "DriverOpts": null
       }
   }
...

如果不设置,默认创建的容器在172.17.0.0 网段下,gateway都是172.17.0.1,此时这些同一网段的容器是可以互通的。
但是使用docker-compose创建的容器一般都处于另一个网段,在本例中启动的docker-compose都在172.18.0.0的网段中,因此compose中的容器无法访问到mysql容器。

前置知识

docker的network模式

docker中有三种网络模式:

  • bridge:桥接 docker (默认)
  • none:不配置网络
  • host:和宿主机共享网络
    可通过以下命令查看:
[[email protected] ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
72f43ccbceb3        bridge              bridge              local
224a641ac129        host                host                local
4ce41b9297c2        none                null                local

创建出的容器默认都是bridge,可以通过以下命令查看当前network下有哪些容器(通过name和容器id辨识):

docker network inspect network名称

[[email protected] ~]# docker network inspect bridge
...
"Containers": {
            "13ed457ceeff98a4f47898016285a7cd84aab6655153c191c1cdb44b1ac8ee3f": {
                "Name": "redis",
                "EndpointID": "16b2fbb4a5893bdce43aac784a7f1dd52dda3bfd4930014b0bfae23aacb27a03",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            },
            "aded9df072e329423c7c24cc2f5722d49c5725a0eef024f3d382d4a09a84d826": {
                "Name": "stupefied_perlman",
                "EndpointID": "04db10227da5a189c23b80fab649573e96e510a71f62e4e1e2bb92841d91e5ed",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            }
...

如果想要使docker容器之间可以互通,最方便的方法就是让容器处于同一个network之下!

实现步骤

创建自定义network

这一步的目的是自己创建一个network,然后把docker-compose还有我们已有的mysql容器都放到这个network下,这样他们就可以互通了。

[[email protected] ~]# docker network create --driver bridge --subnet 172.18.0.0/16 --gateway 172.18.0.1  mynet

--driver bridge 网络模式为 桥接模式
--subnet 172.18.0.0/16 设置子网
--gateway 172.18.0.1 设置网关
--mynet 自定义的network名

查看:

[[email protected] ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
72f43ccbceb3        bridge              bridge              local
224a641ac129        host                host                local
9832e7cfc6fd        mynet               bridge              local
4ce41b9297c2        none                null                local

我们新创建的network —— mynet已经出现了。

把已有容器(mysql)的network修改为自定以network

###解除容器绑定的网络  bridge:容器以前的network  b7c:容器标识符(容器id前缀,也可写完整)
[[email protected] ~]# docker network disconnect bridge b7c
##为容器重新指定自定义网络
[[email protected] ~]# docker network connect b7c mynet
##重新启动容器
[[email protected] ~]# docker restart b7c

查看效果:

[[email protected] ~]# docker inspect mynet
...
"Containers": {
			"b7c1837830d4584d2e82f697bcb867e3f63801e5b51796f152e5815e0c48b01e": {
                "Name": "mysql",
                "EndpointID": "222689b1a48bce1fbce63b299b5cdd6026bf0e52bf1e04d0b924d5a49257d805",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            },
...

可以看到mynet的容器中出现了mysql(b7c);
查看容器的信息:

[[email protected] ~]# docker inspect b7c
...
"Networks": {
                "mynet": {
                    "IPAMConfig": {},
                    "Links": null,
                    "Aliases": [
                        "b7c1837830d4"
                    ],
                    "NetworkID": "9832e7cfc6fd3d7557623178ad4b551c391f96fe7ce8636606005b531a1edd50",
                    "EndpointID": "222689b1a48bce1fbce63b299b5cdd6026bf0e52bf1e04d0b924d5a49257d805",
                    "Gateway": "172.18.0.1",
                    "IPAddress": "172.18.0.2",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:12:00:02",
                    "DriverOpts": {}
                }
            }
...

可以看到,网段已经变动到172.18.0.0了。

设置docker-compose的配置文件

设置docker-compose的配置文件可以参看官方文档或者中文介绍
在这里因为我们已经自定义了一个network,为了使docker-compose启动的容器和mysql容器在同一个network下,要在docker-compose.yml中指定使用已存在的network:

version: '2'

services:
  web:
    build: .
    ports:
      - "8000:8000"
  db:
    image: postgres

networks:
  default:
    external:
      name: my-pre-existing-network

这是官网给的例子,需要在networks标签下使用external选项,指定已有的networks。
在本具体案例中,如下,设置networks - default - external - name: mynet, 并且把所有连接mysql的ip都改为上边查出来的172.18.0.2


version: '3.6'
services:
  xxl-job:
    image: registry.xx.aliyuncs.com/xxx/xxx:0.3
    container_name: xxl-job
    environment:
      #修改数据源连接
      spring_datasource_url: jdbc:mysql://172.18.0.2:3306/xxl_job?Unicode=true&characterEncoding=UTF-8
      spring_datasource_username: xxx
      spring_datasource_password: xxx
      spring_mail_host: smtp.qq.com
      spring_mail_port: 25
      spring_mail_username: [email protected]
      spring_mail_password: xxx
      xxl_job_accessToken:
      xxl_job_i18n:
    ports:
      - '10052:10052'
    expose:
      - '10052'
    #networks: 可以在此处单独配置
     # networkname

    command: bash -c "/opt/froxxx/start.sh xxl-job"

  
  froxxx-monitor:
    image: registry.xxx.com/xxx/xxx:0.3
    container_name: froxxx-monitor
    environment:
      # 修改数据源连接
      datasource_frosxxx_url: jdbc:mysql://172.18.0.2:3306/froxxx?useSSL=false&verifyServerCertificate=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
      datasource_frosxxx_username: xxx
      datasource_frosxxx_password: xxx
      ...
    ports:
      - '10054:10054'
      - '9999:9999'
    expose:
      - '10054'
      - '9999'
    depends_on:
      - frosxxx-spi
    #networks: 可以在此处单独配置
     # networkname

    command: bash -c "/opt/frosxxx/start.sh frosxxx-monitor"

# 网络设置
networks:
  #可以自定义network名称,这里使用default表示如果不在service中单独配置就使用该设置 
  default: 
    external: 
      #使用自定义network
      name: mynet

修改完成后,按照docker-compose的正常启动方法启动即可:

docker-compose up

记得要把以前错误的先docker-compose down删除掉。

这时再使用下边这两条命令

# docker network inspect mynet
# docker inspect 容器名 

查看mynet下是否出新了docker-compose启动的容器,以及docker-compose启动的容器是否已经和mysql容器在同一网段,如果相同,此时docker-compose中的容器就可以和mysql互通了。

总结

关键点在于docker中network的设置。

参考

官方 Networking in Compose
Docker系列教程24-Docker Compose网络设置
docker 自定义网络设置
docker容器网络更改
docker compose 菜鸟教程