React 在 docker, buildkite 部署,如何读取不同的 staging, qa 环境文件

2021-12-24 02:18:03 +08:00
 gamesover

现在 deployment 一般都是 docker 或者类似系统 在生产环境之外,都会有不同的测试环境,比如 staging,qa 等 假设 build 好的 image 都是一样的,你只要通过设置不同的当前 environment ,app 就会读取对应的环境文件

比如在 rails 下,设置当前 environment = staging,rails 就会读取.env.staging + .env 当前 environment = production,rails 就会读取.env.production + .env

但是 react 太怪了,只有 3 种环境,而且你不能自己修改 NODE_ENV 我看了好多种办法,比较经典比如 https://www.codingdeft.com/posts/react-environment-variables/,利用 env-cmd 读取一些 custom env file

但是 env-cmd 有个大问题,这是在 build image 阶段执行的,本来一模一样的 image ,仅仅是环境文件的不同 我要生成不同的 image 吗?比如弄个 staging image ,跑 yun run build-staging; qa image 运行 yun run build-qa ?

本来明明只要一个 image ,pass 不同的当前 env 过去就可以了。另一种奇淫技巧是,在一个 image 内生产不同 build 放在不同的 folder 下,然后制定读取不同 folder ,这个办法被我们 ops team 骂半死

我想因为各种环境都会读取.env ,有没有办法在 deploy image 前,弄个脚本,比如当前是 staging env ,执行 .env.staging >> .env

这样可行吗?或者大家有其他好办法?

2827 次点击
所在节点    React
32 条回复
gamesover
2021-12-24 05:22:24 +08:00
找到一个非常类似的 https://stackoverflow.com/a/53228931/2251303 ,这个人就是把 build 的不同环境,放到一个 image 的不同文件夹下,结果被我们 ops 老大骂死了

我没有其他办法了,谁有招?否则就只能根据不同环境,成生不同的 image ,这个也不好
gamesover
2021-12-24 08:13:43 +08:00
我试着本地跑了下 yarn run build ,发现 react 把环境变量直接在生产文件中替换了,是 hard code 进去的
所以一旦 yarn run build 跑完,你再修改.env 都是没用的
不像其他 app framework ,变量文件是运行时动态加载的

我想不出任何比 build 的不同环境,放到一个 image 的不同文件夹下的办法了
lff0305
2021-12-24 08:14:54 +08:00
Dockerfile:

ENV NODE_ENV production
ARG FILE
COPY .env ./.env
COPY $FILE ./.env.production

Build 的时候

docker build . --build-arg FILE=.env.staging
risky
2021-12-24 09:09:05 +08:00
在 public 下放置环境 env.json 管理环境变量, 使用 fetch('/env.json') 来加载环境变量, 这样一个镜像只要挂载文件或者 configMap 就能用在多个环境下
oott123
2021-12-24 09:10:47 +08:00
大哥 react 是前端框架,构建出来之后是静态文件的。你一个静态文件,自然也不可能运行的时候有变量哇。
解决的办法也有,那就是别把变量编译到代码里,用别的办法识别环境…比如放到 HTML 里,再由 js 读出来。
InternetExplorer
2021-12-24 09:17:34 +08:00
前端的运行时在浏览器里,.env 只在 build 的时候有用。有多个环境的话,可以考虑后端返回不同的配置来改变前端的状态
gamesover
2021-12-24 09:17:56 +08:00
上面提的涉及到其他问题,这样把所有的变量都编译到一个文件,生产文件可以看到任何其他环境的变量

总之,按照后台编译,动态加载环境变量是无解了
gamesover
2021-12-24 09:20:00 +08:00
@InternetExplorer 可以,但是就不能一个 image 在各个环境通用了

staging 环境需要生成 staging image
qa 环境需要生成 qa image
pre-prod 环境需要生成 pre-prod image

这些 image 除了环境变量不同,其他其实都一样
gamesover
2021-12-24 09:22:41 +08:00
@InternetExplorer sorry ,我理解你错误了,你意思是前端通过 api 从后端获取环境变量

这样子肯定不行的
ddch1997
2021-12-24 10:01:41 +08:00
是需要区分密钥之类的吗?我能想到需要区分环境的就是密钥了
XiLingHost
2021-12-24 10:03:51 +08:00
如果文件完全一样,只有环境变量的值不同,那么你可以在 Dockerfile 中用 ENV 指定环境变量名称,然后通过.env 文件来配置环境变量
XiLingHost
2021-12-24 10:06:14 +08:00
另外和你部署的方法也有关系,如果是 docker-compose 部署,除了写在 envfiles 里,你也可以直接通过 environment 来把它配置到 docker-compose.yml 中,如果是 kubernetes 部署也可以配置到 pod 的环境变量中
gamesover
2021-12-24 11:10:33 +08:00
@ddch1997 是的,比如要 call 三方 api ,人家有提供测试环境和生产环境
gamesover
2021-12-24 11:15:08 +08:00
@XiLingHost 不管各种花样,react 生成的静态文件是直接把环境变量 hard code 进去的,不是动态加载的

只有生成多个生产文件,才能解决环境变量的问题
fujishimamao
2021-12-24 11:55:29 +08:00
如果 image 是一样,那就不是 webpack 里面用到的环境变量,学 4 楼说的那样写个 json 在 public 下,html 直接引,不同的环境用 configmap 挂文件覆盖之类的方法不就能解决了
fujishimamao
2021-12-24 12:01:19 +08:00
还有这跟 react 也没关系吧
xiaoming1992
2021-12-24 12:16:28 +08:00
在命令行中加入 NODE_ENV=xxx 就可以改变 NODE_ENV 。process.env 在前端是通过 webpack DefinePlugin 构建时直接文本替换,在构建代码执行的时候也是存在内存中,肯定不会实时读取 .env 文件
7anshuai
2021-12-24 12:31:43 +08:00
CRA 的话可以使用 REACT_APP_ENV
7anshuai
2021-12-24 12:36:51 +08:00
gamesover
2021-12-24 13:57:43 +08:00
当初这么搞的一大原因,是 leader 说要隐藏生产文件中在环境变量中的的 password 和 keys

我现在一看,react 生成的生产文件,直接是把环境变量 hard code 进去的,用户一看明明白白,根本没有任何隐藏的必要

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/824120

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX