Docker Compose 通过 localhost 访问另一个容器

Docker Compose accessing another container via localhost

我正在思考如何访问其他容器 运行 作为 docker-compose 服务的一部分。

我看过很多关于在其他容器中通过服务名称访问容器的答案,但也有很多教程只是简单地使用具有公开端口的本地主机。

所以我只是想弄清楚什么时候使用哪个以及为什么它以这种方式工作。

我的示例应用程序是:https://github.com/daniil/full-stack-js-docker-tutorial

其中,我有一个将 ui 和 api 服务映射在一起的 NGINX 服务器,但事实上我意识到在我的 React 容器 (3000:3000) 内部我实际上可以只需向 http://localhost:5050.

发出 axios 请求即可访问 Express 容器 (5050:5050)

但与此同时,如果我尝试通过本地主机连接到我的 MySQL 容器 (9906:3306),它不起作用,我必须使用 db 作为主机,即容器名称。

谁能帮我理解它是如何工作的:

这里的重要细节是您的 React 应用程序实际上并不 运行 在容器中。它在 Docker space 外部的最终用户浏览器中是 运行,因此无法访问 Docker 的内部网络。

假设您有一个典型的应用程序:

version: '3.8'
services:
  frontend: { ... }
  backend: { ... }
  database: { ... }
  proxy: { ... }

当一个容器直接调用另一个容器时使用Compose服务名称和服务的默认端口。 backend 容器可能配置为 database:5432 作为其数据库 URL; Nginx proxy 可能配置为 proxy_pass http://frontend:3000ports: 不是必需的,如果存在则将被忽略。这 out-of-the-box 无需指定 networks:container_name: 并且对于大多数简单的应用程序,您可以安全地省略这两个选项。

当浏览器应用程序调用容器时 使用主机的 DNS 名称或 IP 地址以及该容器的第一个 ports: 号码。

当浏览器应用程序调用容器时,并且您绝对肯定浏览器与容器位于同一主机上,仅在这种情况下,您可以使用http://localhost:12345,再次匹配目标容器的第一个 ports: 编号。

What is the purpose or benefit of NGINX reverse proxy to tie client and api together?

避免实际需要知道主机名。假设你的 Nginx 配置看起来像

location / {
  proxy_pass http://frontend:3000 ;
}
location /api {
  proxy_pass http://backend:3000 ;
}

然后浏览器应用程序可以向 /api 发出 HTTP GET 请求,根本不需要知道服务器的主机名;它将使用与当前页面的 URL.

中相同的 hast 名称

这也意味着您可以避免直接发布其他涉及的容器,甚至可能有多个 back-end 个容器用于不同的目的。

完整但最小的设置可能如下所示:

version: '3.8'
services:
  frontend:
    build: ./frontend
  backend:
    build: ./backend
    environment:
      PGHOST: database
      # PGUSER, PGPASSWORD
  database:
    image: 'postgres:14'
    volumes:
      - 'pgdata:/var/lib/postgresql/data'
    environment: {} # POSTGRES_USER, POSTGRES_PASSWORD
  proxy:
    image: 'nginx:1.21'
    volumes:
      - './default.conf:/etc/nginx/conf.d/default.conf'
    ports:
      - '12345:80'
volumes:
  pgdata:

使用上面显示的此设置和 Nginx 配置,浏览器调用 http://localhost:12345 将检索主应用程序。如果浏览器应用程序随后请求 /api/foo,那将被转换为 http://localhost:12345/api/foo,后者在 Docker space.

中被代理到 http://backend:3000/foo