【问题标题】:Reading an environment variable in react which was set by docker在反应中读取由docker设置的环境变量
【发布时间】:2019-02-05 18:14:58
【问题描述】:

我正在使用 docker 构建我的 react 应用程序并将其部署在 nginx 中。

我在 docker-compose.yml 中设置了一个环境变量

version: '2'
services:
  nginx:
    container_name: ui
    environment:
      - HOST_IP_ADDRESS= xxx.xxx.xx.xx
    build:
      context: nginx/
    ports:
      - "80:80"

创建 docker 容器后,当我 echo 容器内的变量时,我可以看到 hi。

但是,当我尝试使用 process.env.HOST_IP_ADDRESS 在反应中阅读它时,它正在记录 undefined。

我在某处的博客文章中读到,环境变量只能在生产环境中访问。因为,我正在构建应用程序并将其部署在 nginx 中,所以我应该能够访问它,但由于某种原因我无法读取它。

我在这里做一些根本错误的事情吗?如果是这样,请告诉我一个解决方案。我不是反应专家,我只是在管理别人的代码。

更新:

Dockerfile 如下所示:

FROM node:8 as ui-builder

WORKDIR /home/ui

COPY helloworld .

RUN npm install

RUN npm run build

FROM nginx
COPY --from=ui-builder /home/ui/build /usr/share/nginx/html
CMD ["nginx", "-g", "daemon off;"]

React 组件 sn-p 如下:

import React, { Component } from 'react';

class HelloWorld extends Component {
  render() {
    console.log(process.env.HOST_IP_ADDRESS);
    return (
      <div className="helloContainer">
        <h1>Hello, world!</h1>
      </div>
    );
  }
}

export default HelloWorld;

【问题讨论】:

  • 在前端反应 - 后端环境
  • @xadm 所以,我要设置的环境是主机 docker 机器的 IP 地址。这个IP地址会被前端用来访问后端的api。
  • @xadm 上面的代码只是我在真正接触真正代码库之前尝试的一个测试sn-p。
  • 在 react 应用程序中编译或使用一些后端技术 (php) 将信息传递到应用程序(包含 js 的 html)并让应用程序参数感知
  • @xadm 的意思是 nginx 只是将 JavaScript 代码提供给浏览器,而浏览器(它不知道任何 Docker 的事情正在发生)看到 process.env.HOST_IP_ADDRESS 并不是真的确定如何处理它。

标签: reactjs docker


【解决方案1】:

我要感谢所有发布答案和 cmets 的人。结合这些答案和其他资源的帮助解决了我面临的问题。

按照@DavidMaze(在 cmets 中)的建议,我开始研究我的代码中存在的 webpack 配置。我发现 webpack 正在读取容器内声明的所有环境变量。

所以我开始尝试使用我的 Dockerfile 和 docker-compose.yml,因为我意识到在 react 构建代码时,REACT_APP_HOST_IP_ADDRESS 没有作为环境变量传递。

我改变的第一件事是 Dockerfile。我在 dockerfile 中静态声明了 IP 用于测试
ENV REACT_APP_HOST_IP_ADDRESS localhost。 通过这样做,我能够在 webpack 读取的 env 变量中看到值 localhost。

现在我尝试按照@Alex 在他的回答中的建议将 ENV 变量从 docker-compose 传递给 dockerfile,但没有奏效。

于是我参考https://github.com/docker/compose/issues/5600,将docker-compose.yml和Dockerfile改成如下

docker-compose.yml

version: '2'
services:
  nginx:
    container_name: ui
    build:
      context: nginx/
      args:
        REACT_APP_HOST_IP_ADDRESS: ${IP_ADDRESS}
    ports:
      - "80:80"

IP_ADDRESS 被导出为环境变量。

Dockerfile

FROM node:8 as ui-builder

WORKDIR /home/ui

COPY helloworld .

RUN npm install

ARG REACT_APP_HOST_IP_ADDRESS

ENV REACT_APP_HOST_IP_ADDRESS $REACT_APP_HOST_IP_ADDRESS

RUN npm run build

FROM nginx
COPY --from=ui-builder /home/ui/build /usr/share/nginx/html
CMD ["nginx", "-g", "daemon off;"]

反应组件

import React, { Component } from 'react';

class HelloWorld extends Component {
  render() {
    console.log(process.env.REACT_APP_HOST_IP_ADDRESS);
    return (
      <div className="helloContainer">
        <h1>Hello, world!</h1>
      </div>
    );
  }
}

export default HelloWorld;

这个配置使得在镜像构建过程中通过 docker-compose 中的 ARG 传递给 Dockerfile 的变量可用,因此这些变量可以反过来声明为 env 变量,如果 webpack 读取 env 变量,React 可以在构建过程中使用这些变量。

webpack 将能够使用 DefinePlugin 读取环境变量 https://webpack.js.org/plugins/define-plugin/.

确保在变量前加上 REACT_APP_(如 here 所示),否则 React 不会接收到它。

【讨论】:

  • 那么REACT_APP_HOST_IP_ADDRESS arg 的实际值保存在哪里?
  • 对我来说,它在 Dockerfile 中没有 ENV REACT_APP_HOST_IP_ADDRESS $REACT_APP_HOST_IP_ADDRESS 行的情况下工作。
  • 这个答案解决了我的问题,但有点不完整。对于那些有困难的人,只需在执行“docker build”命令时查看这个补充答案。 stackoverflow.com/questions/42297387/…
【解决方案2】:

环境变量应该以 REACT_APP_ 开头,否则 NODE_ENV 变量会有点混乱,你的环境变量将不起作用:

environment:
  - REACT_APP_DEBUG=TRUE

否则,docker-compose.yml 无效,您将看到错误消息:

services.client.environment contains an invalid type, it should be an object, or an array

这是一个工作示例:

docker-compose.yml

version: "3.3"

services:
  client:
    container_name: client
    environment:
      - REACT_APP_DEBUG=TRUE
    build:
      dockerfile: Dockerfile
      context: ./web/client

Dockerfile

FROM node:6.0.0

# Set env variable
ARG REACT_APP_DEBUG
ENV REACT_APP_DEBUG=$REACT_APP_DEBUG

# that will be empty
RUN echo "DEBUG": $REACT_APP_DEBUG

运行:

->docker-compose run  client node
->process.env.REACT_APP_DEBUG 
'TRUE'

【讨论】:

  • 你好,我试过你的建议,react 仍然无法访问环境变量。我已经用我用来测试这个场景的其他几个 sn-ps 更新了这个问题。如果您发现任何其他问题,请告诉我:)
  • 在 Docker 文件中增加了一行来设置环境变量。
  • 将不起作用,因为您需要在变量前面加上 REACT_APP_
【解决方案3】:

你应该检查下一个时刻

我。你的环境变量有前缀 REACT_APP_

二。在 docker 文件中你有 ARG 和 ENV 命令,比如

ARG REACT_APP_DEBUG
ENV REACT_APP_DEBUG=$REACT_APP_DEBUG

三。你将你的 arg 作为 build arg 在 docker-compose.yml 中看起来像

services:
  my-app:
    build:
      args:
        REACT_APP_DEBUG=True

或者在 docker build 中看起来像

docker build -t my_app:dev --build-arg REACT_APP_DEBUG=True .

【讨论】:

    【解决方案4】:

    我在API Platform 中检查了它是如何完成的,config 只是根据 env('.env' 文件)定义了 consts:

    export const API_HOST = process.env.REACT_APP_API_ENTRYPOINT;
    export const API_PATH = '/';
    

    导入这个你有一个值(API_HOST),而process.env.HOST_IP_ADDRESS指的是运行时不可用的深层对象结构。

    【讨论】:

    • 这就是为什么我想在react构建过程中读取env变量并编译env变量的原因之一。
    • 所以根据你的说法,我需要做的就是在反应应用程序中创建一个.env 文件并将process.env.HOST_IP_ADDRESS 读入一个变量并将该文件导入到我需要使用它的任何地方。正确的?如果是这样,这听起来很简单。我先试试这个。
    【解决方案5】:

    这是我在我的 javascript 代码中使用 Dockerfile 中的 ENV、webpack.config.js 和 process.env 中的解决方案:

    首先在 Dockerfile 中设置环境变量及其值:

    ...
    RUN npm install
    ENV MY_ENV_VAR my_env_value
    ...
    

    然后使用DefinePlugin插件,将其添加到webpack.config.js中的process.env:

    const webpack = require('webpack');
    ...
      plugins: [
        new webpack.DefinePlugin({
          'process.env.MY_ENV_VAR': JSON.stringify(env.MY_ENV_VAR),
        }),
      ],
    ...
    

    最后在你的代码中使用 env 变量:

    const host = process.env.MY_ENV_VAR || 'a_default_value_in_case_no_env_is_found';
    

    【讨论】:

      【解决方案6】:

      我使用 Github CI 为每个环境设置秘密。首先在 GH 动作文件中我使用run: docker build ... --build-arg REACT_APP_APIURL=${{ secrets.REACT_APP_APIURL }} .

      然后我在我的 repo 中的Dockerfile 中使用它们来使用 React 应用程序构建最终图像,例如:

      ARG REACT_APP_APIURL
      RUN test -n "$REACT_APP_APIURL" || (echo "REACT_APP_APIURL not set in GH/your environment" && false)
      ...
      RUN npm run build
      

      此值自动用于npm run build(在我的反应打字稿代码库中使用为process.env.REACT_APP_APIURL)。我选择检查这个值,如果我的 Docker 映像或某处的配置有问题,让应用程序在加载时立即失败。

      export const config = {
        apiUrl: setApiUrlFromEnv(),
      };
        
      function setApiUrlFromEnv() {
        if (process.env.REACT_APP_APIURL) {
          return process.env.REACT_APP_APIURL;
        } else {
          // if something goes wrong in setup, do not start app and show err directly in web console
          throw new Error(
            `ENV not configured properly (REACT_APP_APIURL) to use desired ENV variables (${process.env.REACT_APP_APIURL})`
          );
        }
      }
      

      【讨论】:

        【解决方案7】:

        第 1 步:将 env 的参数添加到 docker-compose 文件中

        我们使用 args 代替环境字段,因为环境字段在构建阶段不可用

        services:
            ...
            web_app:
                build:
                  context: .
                  dockerfile: Dockerfile
                  args:
                    - MY_ENV=HELLO_WORLD
        

        Step 1_alternative:如果镜像是由cloudbuild而不是docker-compose构建的,我们应该在cloudbuild.yml文件中添加args

        steps:
        - name: ...
            args:
            ...
            - --build-arg
          - MY_ENV=HELLO_WORLD
        

        步骤:2:将 ARGS 和 ENVS 添加到 dockerfile

        我们使用 ARG 命令从 docker-compose args 中获取变量

        我们使用 ENV 为构建设置环境

        ARG MY_ENV
        
        ENV MY_ENV=$MY_ENV
        
        RUN echo "$MY_ENV"
        

        第 3 步: 更新 webpack 配置

        • 使用 webpack.ProvidePlugin({ process: "process/browser" }) 在 web 应用中启用进程
        • 使用 webpack.DefinePlugin 定义 Web 应用中可用的 env 变量
        • 通过 npm i -S 进程将进程库添加到 dev 依赖项
        plugins: [
            new webpack.ProvidePlugin({
              process: "process/browser"
            }),
            new webpack.DefinePlugin({ "process.env": JSON.stringify(process.env) })
          ]
        

        【讨论】:

          猜你喜欢
          • 2021-08-15
          • 2020-05-28
          • 2015-01-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-07-16
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多