Docker Compose下Robot Framework容器无法通过localhost访问Web应用
我使用Docker Compose搭建Web应用,并在独立容器中运行Robot Framework做测试。前端与后端服务可通过宿主机的localhost正常连接,但测试容器无法通过https://localhost:3000及https://localhost:8000/api/v1访问应用,仅通过服务名(如isp-frontend:3000)访问可正常工作。请问是否有办法实现测试容器通过localhost访问应用?
相关Docker Compose配置
version: '3.7' services: frontend: container_name: isp-frontend build: context: ./frontend dockerfile: Dockerfile.local ports: - "3000:3000" networks: - isp-network expose: - 3000 environment: # (while it's applied when TS is compiled) # For the frontend can be applied only during the build! # You have to build manually without cache if one of those are changed at least for the prod mode. - REACT_APP_BACKEND_API=https://localhost:8000/api/v1 - HTTPS=true - SSL_CRT_FILE=/app/dev-cert.dev-pem - SSL_KEY_FILE=/app/dev-key.dev-pem - CI=true - CHOKIDAR_USEPOLLING=true # - REACT_APP_ENV=sandbox postgres: image: postgres environment: POSTGRES_USER: test POSTGRES_PASSWORD: test PGDATA: /data/postgres volumes: - postgres:/data/postgres ports: - "5432:5432" networks: - isp-network restart: unless-stopped pgadmin: image: dpage/pgadmin4 environment: PGADMIN_DEFAULT_EMAIL: "test@test.com" PGADMIN_DEFAULT_PASSWORD: dev volumes: - pgadmin:/root/.pgadmin - ./pgadmin-config/servers.json:/pgadmin4/servers.json ports: - "5050:80" networks: - isp-network restart: unless-stopped backend: container_name: isp-backend build: context: ./backend dockerfile: Dockerfile.local # these ports will be accessible internally and published on the host machine. ports: - "8000:443" volumes: - ./backend:/app command: > bash -c "pip list && env && exec /start-reload.sh" networks: - isp-network depends_on: - postgres # These ports will be accessible by other services connected to the same network, # but won't be published on the host machine. expose: - 80 - 443 environment: - GOOGLE_APPLICATION_CREDENTIALS=/app/.secret/secret.json - APP_DB_CONNECTION_STRING=postgresql+psycopg2://test:test@postgres:5432/postgres - LOG_LEVEL=debug - SQLALCHEMY_ECHO=True - CORS=https://localhost:3000,http://localhost:3000,https://isp-frontend:3000 - PORT=443 - AUTH_ALLOWED_DOMAINS=* - AUTH_REDIRECT_URL=https://localhost:3000/login # make uvicorn run as SSL/HTTPS - UVICORN_SSL_CERTFILE=/app/dev-cert.dev-pem - UVICORN_SSL_KEYFILE=/app/dev-key.dev-pem - UVICORN_RELOAD_EXCLUDE=env\*,venv\*,env,venv,.gitlab\*,.pytest_cache\*,.scannerwork\*,.secret\*,.vscode - UVICORN_RELOAD_DIR=/app/ # port of uvicorn inside of the container - PRE_START_PATH=/app/scripts/alembic-upgrade.sh testing: container_name: testing build: context: ./isp-testing dockerfile: Dockerfile volumes: - ./isp-testing:/isp-app command: > bash -c "/wait && mkdir -p /isp-app/tests/report && cd /isp-app/tests/ && robot --outputdir \"../report/FE_log\" --include US24 ." networks: - isp-network depends_on: - backend - frontend environment: - WAIT_HOSTS=frontend:3000 - WAIT_TIMEOUT=3000 - WAIT_SLEEP_INTERVAL=300 - WAIT_HOST_CONNECT_TIMEOUT=300 - FRONTEND_URL=https://isp-frontend:3000 - BACKEND_URL=https://isp-backend:8000/api/v1 - ROCHE_EMAIL=test@test.com - ROCHE_PASS=RJ2ND - ROCHE_USERNAME=TEST volumes: postgres: pgadmin: testing: networks: isp-network: driver: bridge
问题原因
Docker容器内的localhost指向容器自身的回环地址,而非宿主机。测试容器里访问localhost:3000时,实际是尝试访问自己容器的3000端口,而非宿主机上映射的前端服务端口,因此无法连通。
解决方案
1. 使用宿主机专用域名host.docker.internal
Docker提供了内置域名host.docker.internal,用于容器访问宿主机。直接修改测试容器的环境变量即可:
testing: environment: - FRONTEND_URL=https://host.docker.internal:3000 - BACKEND_URL=https://host.docker.internal:8000/api/v1
- 注意:Linux系统下Docker版本低于20.10时,需要额外添加
extra_hosts配置:testing: extra_hosts: - "host.docker.internal:host-gateway"
2. 手动映射localhost到宿主机IP
在测试服务的配置中添加extra_hosts,把localhost指向宿主机的Docker网关IP(通常是172.17.0.1,可通过docker network inspect isp-network查看实际网关):
testing: extra_hosts: - "localhost:172.17.0.1"
这样测试容器内的localhost就会解析到宿主机,从而访问宿主机上暴露的3000、8000端口。
3. 优先使用服务名访问(推荐)
Docker Compose会自动为同一网络内的服务配置DNS解析,使用服务名(如isp-frontend:3000、isp-backend:443/api/v1)访问是最稳定的方式,无需依赖宿主机IP,也不会因网络配置变化失效。如果不是硬性要求用localhost,建议保持这种方式。
内容的提问来源于stack exchange,提问作者user2439278

