Create-React-App无法从docker-compose.yml读取环境变量

12
version: "3"
services:
  web:
    # replace username/repo:tag with your name and image details
    image: user1/webapp:latest
    volumes:
      - ./local-db:/go/src/webapp/local-db
    environment:
      - REACT_APP_ENDPOINT=http://api.com
    deploy:
      replicas: 5
      resources:
        limits:
          cpus: "0.1"
          memory: 50M
      restart_policy:
        condition: on-failure
    ports:
      - "8080:8080"
    networks:
      - webnet
networks:
  webnet:

webapp 是一个服务器,用于提供 create-react-app 应用程序的服务,但当我运行时

console.log("process.env.REACT_APP_ENDPOINT")
console.log(process.env.REACT_APP_ENDPOINT)

根据https://daveceddia.com/multiple-environments-with-react/,我应该能够访问环境变量。我使用docker-compose运行。
docker swarm init 
docker stack deploy -c ~/webapp/docker-compose.yml webapp 

控制台日志打印undefined,但是如果我在本地机器上运行serve create-react-app而不使用docker,则前端正确打印环境变量。

3个回答

7
我注意到很多人在这方面遇到了困难,尤其是如何在Dockerfile中传递环境变量而不是使用条件脚本。因此,我提供了一个简化的Github存储库教程:
- https://github.com/mikesparr/tutorial-react-docker
如果您想阅读相关背景文章,可以参考以下公开文章:
- https://www.linkedin.com/pulse/dockerizing-your-react-app-mike-sparr/ 简而言之,您需要让Dockerfile的CMD运行一个脚本,该脚本执行构建和服务器启动步骤,以便应用程序可以使用运行时容器配置。 此外,您需要在ENV变量前缀中添加“REACT_APP_<yourvarname>”,在应用程序中使用“process.env.REACT_APP_SOMEVAR”来引用它们。

1
使用create-react-app引导的React应用程序会剥离大多数环境变量,除了NODE_ENV和以REACT_APP_<your var>为前缀的任何变量。哎呀,我没有意识到这一点。更改变量名称 = 成功。非常感谢。 - zipzit
1
只有使用“npm run”命令才能正常工作,但如果您有一个Dockerfile,其中包含npm run build命令,则.env变量将被忽略。 - Luca Perico

5

创建React应用程序(Create-react-app)推荐使用.env文件将您的环境变量嵌入到构建中。

显然,将.env文件纳入版本控制不是一个好的做法,create-react-app官方文档反对12因素应用程序哲学。

所以让我们使用一个干净的解决方案!最简单的方法是在Dockerfile构建环境中即时创建一个.env文件:

为此,请创建一个简单的脚本create-env-file.sh

touch .env

for envvar in "$@" 
do
   echo "$envvar" >> .env
done

它会将您传递给它的每个参数复制到一个新的.env文件中

然后在您的Dockerfile中在 RUN npm run build 之前调用它:

FROM node:14-alpine

WORKDIR /app

COPY src/ ./src/
COPY public/ ./public/
COPY pack*.json ./
COPY tsconfig.json .
COPY create-env-file.sh ./create-env-file.sh

RUN npm i

# Add as many arguments as you want to pass environment variables 
#   and use an ARG command for each one, so Dockerfile context will grab it from --build-arg

ARG REACT_APP_ENDPOINT

RUN sh create-env-file.sh REACT_APP_ENDPOINT=$REACT_APP_ENDPOINT

# If you want to debug the .env file, uncomment the following line
# CMD ["cat", ".env"]

RUN npm run build

RUN npm i -g serve

EXPOSE 5000

CMD ["serve", "-s", "build"]

然后使用 --build-arg 将您的环境变量传递给docker build命令:

docker build --build-arg REACT_APP_ENDPOINT=http://api.com -t front-server .

由于Docker Build将构建参数视为参数而非环境变量,因此您必须使用ARG命令引用每个传递的构建参数。 请参见此处

因此,您的docker-compose.yml文件应如下所示:

version: "3"
services:
  web:
    build:
      context: .
      args:
        REACT_APP_ENDPOINT=http://api.com
    image: user1/webapp:latest
    volumes:
      - ./local-db:/go/src/webapp/local-db
    deploy:
      replicas: 5
      resources:
        limits:
          cpus: "0.1"
          memory: 50M
      restart_policy:
        condition: on-failure
    ports:
      - "8080:8080"
    networks:
      - webnet
networks:
  webnet:

使用 --build 参数运行 docker-compose up 命令:

docker-compose up --build

这太棒了。谢谢!!! - Karanveer Singh
使用这种方法,是否可以先构建镜像,然后稍后在docker-compose中设置args? - frab
当您使用构建来设置参数时,您需要为每个环境创建一个Docker镜像。相反,您希望有一个可以被多个环境使用的单个镜像。 - Wubinator

1

1
从我所看到的,这个答案并没有明确回答原问题,即如何在create-react-app docker容器中读取环境变量。相反,它展示了如何从已知目录在单个计算机上构建单个容器。提示:当我们部署系统时,通常会在一个位置放置多个容器(前端、后端、数据库、管理工具等)。对于拥有多个容器的任何人来说,这个答案很好,但并没有帮助。而且当我们使用多个容器时,我们是从git仓库构建的。.env文件不起作用。 - zipzit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接