使用 docker 时如何避免“端口冲突”?
Posted
技术标签:
【中文标题】使用 docker 时如何避免“端口冲突”?【英文标题】:How do I avoid 'port collision' when using docker? 【发布时间】:2018-06-25 04:54:15 【问题描述】:我希望标题足够描述性。我正在尝试在 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
中遗漏了什么吗?还有什么问题?
【问题讨论】:
你必须把这个"3306:3306"
改成XXXX:3306
,其中XXXX是其他空闲的端口。
【参考方案1】:
在您的 docker-compose.yml 文件中,您通过在 ports
数组中声明它们来公开您主机网络空间上的 pod 的端口,例如:
ports:
- "3306:3306"
如果您省略这部分配置,您的容器仍然可以私下相互访问,但端口不会在您的主机中绑定,避免您面临的端口冲突。
如果您需要为部分或全部服务向主机公开端口,则必须通过更改主机端的绑定端口自己处理冲突。例如,为了避免端口 3306 上的端口冲突,您可以简单地这样做:
ports:
- "3307:3306"
【讨论】:
如果我只是删除端口部分,它仍然无法正常工作,但是会出现不同的错误。我假设这是我的代码的问题,但与问题无关。将其更改为“3307:3306”无论如何都可以。谢谢!【参考方案2】:停止绑定到本地端口,让docker-compose
为您选择一个临时端口。在您的情况下,您的应用程序可以在没有任何帮助的情况下访问默认端口。如果您遵循12 Factor App 方法,请使用如下 sn-p 中的环境变量。
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
【讨论】:
请注意,通常没有必要公开 mongo 端口。默认情况下,同一网络中的服务可以相互访问;mongo
服务中的 ports
部分将端口导出到 host。
@FranklinYu - 正确。这就是为什么“app”容器可以在默认端口上连接到“mongo”的原因。您需要获取临时端口的唯一时间是从 docker 网络外部(例如,从 localhost)访问容器
这里是关于端口的简短语法文档,如果有人需要它:docs.docker.com/compose/compose-file/compose-file-v3/#ports【参考方案3】:
从 docker compose files 版本 3 开始提供的另一个选项是通过 environment variables 指定在主机上公开的不同端口。
所以一种方法可能是这样的:
version: "3.3"
services:
mysql:
container_name: mysql
image: mysql
ports:
- "$MYSQL_PORT_NUMBER:-3306:3306"
然后,如果定义了环境变量,则将使用该值。否则,将使用默认的3306
。
版本 3 docker compose 文件的第二个功能,如果存在,它们将 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
【讨论】:
以上是关于使用 docker 时如何避免“端口冲突”?的主要内容,如果未能解决你的问题,请参考以下文章