问题描述
我正在使用 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'
};