如何将主机 IP 地址传递给 Docker Compose 文件?

问题描述

我正在使用 docker-compose(文件 1)构建一个应用程序,我想知道如何将主机 IP 地址与 docker-compose 文件通信。该应用程序由数据库、前端和后端组成。它的目的是我想从本地网络上的其他计算机访问我的应用程序。它在前端工作正常,但是当我想与后端通信时,它不再起作用。我怀疑这是由于前端试图将数据发送到本地主机(对于本地网络上的另一台计算机来说,这是不正确的)。因此,我想直接在 docker-compose 文件中将主机的 IP 地址传递给前端应用程序,以便它可以与后端通信!有什么想法吗?

文件 1

    version: "3.7"

    services:
      db:
        build: 
          context: ./database
        command: --default-authentication-plugin=MysqL_native_password  --sql_mode=""
        restart: always
        cap_add:
          - SYS_NICE  # CAP_SYS_NICE
        volumes:
          - db_data:/var/lib/MysqL
        ports:
          - ${MysqL_PORT}:${MysqL_PORT}
        environment:
          MysqL_DATABASE: ${MysqL_DATABASE}
          MysqL_PASSWORD: ${MysqL_PASSWORD}
          MysqL_ROOT_PASSWORD: ${MysqL_ROOT_PASSWORD}
          MysqL_TCP_PORT: ${MysqL_PORT}
        env_file: ./.env

      back:
        depends_on:
          - db
        build: 
          context: ./backend
          target: development
        volumes: 
          - ./backend:/app
          - /app/node_modules
        restart: "no"
        ports:
          - ${BACKEND_PORT}:${BACKEND_PORT}
        env_file: ./.env

      front:
        depends_on:
          - back
          - db
        build:
          context: ./frontend
          target: development
        stdin_open: true
        volumes:
          - ./frontend:/app
          - /app/node_modules
        restart: "no"
        ports:
          - ${FRONTEND_PORT}:${FRONTEND_PORT}
        env_file: ./.env

    volumes:
      db_data: {}

这是我在前端 env 上用于与后端通信的 api url,我将动态替换为主机 IP。

文件 2

const dev = {
    ...env,apiUrl: "http://localhost:3000/api",};

非常感谢您的帮助! 最好的

解决方法

环境变量是一种简单的方式来传递像这样的少量配置。

对于这种特殊情况,我可能会配置一个 URL 而不是主机的 IP 地址。您可以非常合理地希望将此应用程序部署在负载均衡器之后;该负载均衡器可能会终止 TLS,因此您可以宣传 https: URL;您的客户端可能无法直接访问您的本地 IP 地址;如果您有一个 DNS 名称,您更愿意宣传一个 DNS 名称而不是一个 IP 地址。

在 Node 代码中,您可以在 process.env 中找到环境变量:

const dev = {
  ...env,apiUrl: process.env.API_URL || 'http://localhost:3000/api'
};

然后在您的 docker-compose.yml 中您可以直接设置该网址:

services:
  front:
    environment:
      API_URL: http://10.20.30.40/api
      # API_URL: https://example.com/myapp/api
,

你想要的是shell command substitution
类似:MYVAR=$(ip route get 1 | awk '{print $NF;exit}')

不幸的是,compose 不支持命令替换。
Compose 仅​​支持“静态”shell 变量,也就是 shell variable expansion
最好的办法是使用适当的错误消息声明强制变量

# requires for the var to be pre-declared in shell
environment:
  API_URL: ${API_URL:?"Variable API_URL must present in shell."}

# alternatively you could provide some default value
environment:
  API_URL: ${API_URL:-192.0.2.2}

另一种解决方案可能是使用 envsubst 就地编辑您的撰写文件。
检查 this answer 以获取示例。


还要注意,没有“主机的IP地址”这样的东西:)
它有点传统且非常模糊的 term

“主 IP”是“无论您的系统在什么时候使用它”的别名 将流量发送到默认路由”。在没有源的情况下 该路由上的短语,这是所用接口的第一个地址 (或多或少)。

因此,在编写命令以定义“主机的 IP”时需要小心。
在简单的网络配置中,这可能或多或少地工作正常。
ip route get 1 | awk '{print $NF;exit}'
但最好检查这个 discussion 并确保您的最终命令返回您期望的内容。

,

通过在这样的特定服务的环境变量中添加 HOST_IP=http://host.docker.internal:PORT

environment:
  - HOST_IP=http://host.docker.internal:4001/

可以通过像访问nodejs代码中的环境变量来访问docker内部的主机ip

var host_url=process.env.HOST_IP

注意:由于您只能访问主机 ip,因此您需要在 url 末尾手动添加端口,它仅适用于开发服务器,不适用于生产。

,

您应该在前端配置中添加一个环境变量,该变量指定 api 端点的 URL,并在 URL 中使用后端容器的主机名。 Networking in Compose 的文档详细说明了用于容器的默认主机名和网络。

按如下方式修改您的 docker compose 文件:

services:
  front:
    environment:
      API_URL: http://back:${BACKEND_PORT}/api

按如下方式修改您的 javascript 文件:

const dev = {
  ...env,apiUrl: process.env.API_URL || 'http://localhost:3000/api'
};