问题描述
在使用Docker容器时,遇到了一个问题:他想要在容器内部连接到主机(他正在Ubuntu上运行)。他尝试了几种解决方案,包括添加extra_hosts: host.docker.internal:host-gateway
,但仍然无法建立连接。他是通过docker-compose up
命令运行Docker的。
例如,当他在容器内运行脚本requests.get("http//:host.docker.internal:8000")
时,会收到以下错误:
requests.exceptions.ConnectionError: HTTPConnectionPool(host='localhost', port=8000): Max retries exceeded with url: / (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f18ac13dd90>: Failed to establish a new connection: [Errno 111] Connection refused'))
这是他的docker-compose.yml
文件:
version: 3.7
services:
web:
container_name: schedule_model_service-api
build: .
ports:
- "8001:8001"
command: startserver
volumes:
- ./:/app
env_file:
- .env
depends_on:
- postgres
- redis
extra_hosts:
- "host.docker.internal:host-gateway"
worker:
container_name: schedule_model_service-worker
build: .
command: celeryworker
volumes:
- ./:/app
env_file:
- .env
depends_on:
- web
- postgres
- redis
redis:
container_name: schedule_model_service-redis
image: redis:6.2.6
volumes:
- ./docker-data/redis:/var/lib/redis
env_file:
- .env
restart: on-failure
postgres:
container_name: schedule_model_service-db
image: postgres:14.1
volumes:
- ./docker-data/postgresql:/var/lib/postgresql/data
env_file:
- .env
restart: on-failure
解决方案
请注意以下操作注意版本差异及修改前做好备份。
方案1
如果容器需要连接到主机或远程服务,你需要知道主机的IP地址或域名。任何其他的解决方法只适用于你的笔记本电脑或者只是用于学术目的,在真实的场景和真实的用户中是无效的。例如,AWS中的容器需要连接到Azure的MySQL。
在你的情况下,你需要获取主机的本地IP地址。你可以在docker-compose up
之前获取IP地址,如下所示:
export MACHINE_HOST_IP=$(hostname -I | awk '{print $1}')
docker-compose up ...
然后,在你的compose文件中使用这个值。例如,如果你的主机上有一个MySQL数据库,你的容器需要连接到它,你可以使用以下配置:
version: '3.2'
services:
wordpress:
environment:
DB_HOST : ${MACHINE_HOST_IP}:3306
DB_USER : usr_wordpress
请参考以下链接进行进一步了解:
– https://stackoverflow.com/questions/52173352/what-is-the-difference-between-publishing-808080-and-80808080-in-a-docker-run/52213178#52213178
– https://stackoverflow.com/questions/63136530/how-to-connect-api-with-web-spa-through-docker/63207679#63207679
方案2
问题可能是你在requests.get("http//:host.docker.internal:8000")
中多了一个冒号。应该是requests.get("http//host.docker.internal:8000")
。
你可能遇到了requests URL解析的一个bug;从异常消息中可以看出,它试图连接到localhost:8000
,而更合理的做法应该是报告URL格式错误。