使用docker时如何避免“端口冲突”?

时间:2018-01-16 13:04:54

标签: mysql docker port

我希望标题足够描述。我试图在docker中执行我的节点应用程序(使用mongo和mysql)。我正在使用docker-compose启动应用,并在下面显示docker-compose.yml文件:

version: "3.3"
services:
  app:
    container_name: app
    restart: always
    build: .
    volumes:
      - ./:/app
    ports:
      - "3000:3000"
    links:
      - mongo
      - mysql
  mongo:
    container_name: mongo
    image: mongo
   ports:
      - "27017:27017"
  mysql:
    container_name: mysql
    image: mysql
    ports:
      - "3306:3306"

每当我尝试使用docker-compose up启动时,我都会收到以下错误:

ERROR: for mysql  Cannot start service mysql: driver failed programming external connectivity on endpoint mysql (785b03daaa662bb3c344025f89fd28f49eabb43104b1c9a16ab425ab5120309f): Error starting userland proxy: listen tcp 0.0.0.0:3306: bind: address already in use

ERROR: for mysql  Cannot start service mysql: driver failed programming external connectivity on endpoint mysql (785b03daaa662bb3c344025f89fd28f49eabb43104b1c9a16ab425ab5120309f): Error starting userland proxy: listen tcp 0.0.0.0:3306: bind: address already in use
ERROR: Encountered errors while bringing up the project.

我做了一些研究,似乎gitlab-runner正在使用mysql服务。我的理解是,如果我通过docker容器运行此设置,它们将与主机系统隔离,因此我不会遇到任何端口冲突。我公开的唯一端口是我Dockerfile中的端口 - 在我的情况下是3000.我错过了docker-compose.yml中的内容吗?还有什么可能是错的?

3 个答案:

答案 0 :(得分:3)

停止绑定到本地端口,让docker-compose为您选择一个短暂的端口。在您的情况下,您的应用程序可以在没有任何帮助的情况下进入默认端口如果您遵循12 Factor App方法,请使用以下代码段中的环境变量。

version: "3.3"
services:
  app:
    restart: always
    build: .
    volumes:
      - ./:/app
    ports:
      - 3000  # will be bound to an ephemeral port
    environment:
      MONGODB_URL: mongodb://mongo/db  # can reach port 27017 without help
  mongo:
    image: mongo
    ports:
      - 27017

这是通过环境变量或命令行标志配置应用程序的主要原因。

如果您需要从主机访问docker应用程序,可以使用docker-compose port获取临时端口。我经常使用如下的shell函数:

get_exposed_port() {  # SERVICE PORT
    docker-compose port $1 $2 | cut -d: -f2
}

答案 1 :(得分:2)

从docker compose版本3开始可用的另一个选项是指定通过environment variables在主机上公开的其他端口。

所以一种实现方法可能是这样的:

version: "3.3"
services:
  mysql:
    container_name: mysql
    image: mysql
    ports:
      - "${MYSQL_PORT_NUMBER-:3306}:3306"

然后,如果定义了环境变量,则将使用该值。否则,将使用默认的3306

版本3泊坞窗的第二个功能是组成文件,如果存在一个文件,它们将read environment variables from a .env file.env文件必须位于运行docker-compose的目录中。

最后,要调试所有这些,可以使用docker-compose config发出变量扩展的docker compose文件。使用.env来执行以下操作:

MYSQL_PORT_NUMBER=3307

给出以下结果:

$ docker-compose -f mysql-port-conflict.yaml config
services:
  mysql:
    container_name: mysql
    image: mysql
    ports:
    - published: 3307
      target: 3306
version: '3.3'

表明mysql将在主机的端口3307上可用。当然,任何要连接到mysql的应用程序也都需要了解${MYSQL_PORT_NUMBER}

HTH

答案 2 :(得分:1)

在您的docker-compose.yml文件中,您通过在ports数组中声明它们来展示主机网络空间中的端口,例如:

ports:
  - "3306:3306"

如果省略这部分配置,您的容器仍然可以私下相互联系,但端口不会绑定在主机上,避免了您遇到的端口冲突。

如果您需要将端口暴露给主机以获取部分或全部服务,则必须通过更改主机端的绑定端口来自行处理冲突。例如,为了避免端口3306上的端口冲突,您可以执行以下操作:

ports:
  - "3307:3306"