现在 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
这样可行吗?或者大家有其他好办法?
1
gamesover OP 找到一个非常类似的 https://stackoverflow.com/a/53228931/2251303 ,这个人就是把 build 的不同环境,放到一个 image 的不同文件夹下,结果被我们 ops 老大骂死了
我没有其他办法了,谁有招?否则就只能根据不同环境,成生不同的 image ,这个也不好 |
2
gamesover OP 我试着本地跑了下 yarn run build ,发现 react 把环境变量直接在生产文件中替换了,是 hard code 进去的
所以一旦 yarn run build 跑完,你再修改.env 都是没用的 不像其他 app framework ,变量文件是运行时动态加载的 我想不出任何比 build 的不同环境,放到一个 image 的不同文件夹下的办法了 |
3
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 |
4
risky 2021-12-24 09:09:05 +08:00
在 public 下放置环境 env.json 管理环境变量, 使用 fetch('/env.json') 来加载环境变量, 这样一个镜像只要挂载文件或者 configMap 就能用在多个环境下
|
5
oott123 2021-12-24 09:10:47 +08:00 via Android 1
大哥 react 是前端框架,构建出来之后是静态文件的。你一个静态文件,自然也不可能运行的时候有变量哇。
解决的办法也有,那就是别把变量编译到代码里,用别的办法识别环境…比如放到 HTML 里,再由 js 读出来。 |
6
InternetExplorer 2021-12-24 09:17:34 +08:00
前端的运行时在浏览器里,.env 只在 build 的时候有用。有多个环境的话,可以考虑后端返回不同的配置来改变前端的状态
|
7
gamesover OP 上面提的涉及到其他问题,这样把所有的变量都编译到一个文件,生产文件可以看到任何其他环境的变量
总之,按照后台编译,动态加载环境变量是无解了 |
8
gamesover OP @InternetExplorer 可以,但是就不能一个 image 在各个环境通用了
staging 环境需要生成 staging image qa 环境需要生成 qa image pre-prod 环境需要生成 pre-prod image 这些 image 除了环境变量不同,其他其实都一样 |
9
gamesover OP |
10
ddch1997 2021-12-24 10:01:41 +08:00
是需要区分密钥之类的吗?我能想到需要区分环境的就是密钥了
|
11
XiLingHost 2021-12-24 10:03:51 +08:00
如果文件完全一样,只有环境变量的值不同,那么你可以在 Dockerfile 中用 ENV 指定环境变量名称,然后通过.env 文件来配置环境变量
|
12
XiLingHost 2021-12-24 10:06:14 +08:00
另外和你部署的方法也有关系,如果是 docker-compose 部署,除了写在 envfiles 里,你也可以直接通过 environment 来把它配置到 docker-compose.yml 中,如果是 kubernetes 部署也可以配置到 pod 的环境变量中
|
14
gamesover OP |
15
fujishimamao 2021-12-24 11:55:29 +08:00 via Android
如果 image 是一样,那就不是 webpack 里面用到的环境变量,学 4 楼说的那样写个 json 在 public 下,html 直接引,不同的环境用 configmap 挂文件覆盖之类的方法不就能解决了
|
16
fujishimamao 2021-12-24 12:01:19 +08:00 via Android
还有这跟 react 也没关系吧
|
17
xiaoming1992 2021-12-24 12:16:28 +08:00 via Android
在命令行中加入 NODE_ENV=xxx 就可以改变 NODE_ENV 。process.env 在前端是通过 webpack DefinePlugin 构建时直接文本替换,在构建代码执行的时候也是存在内存中,肯定不会实时读取 .env 文件
|
18
7anshuai 2021-12-24 12:31:43 +08:00
CRA 的话可以使用 REACT_APP_ENV
|
19
7anshuai 2021-12-24 12:36:51 +08:00
|
20
gamesover OP 当初这么搞的一大原因,是 leader 说要隐藏生产文件中在环境变量中的的 password 和 keys
我现在一看,react 生成的生产文件,直接是把环境变量 hard code 进去的,用户一看明明白白,根本没有任何隐藏的必要 |
21
7anshuai 2021-12-24 14:03:40 +08:00 1
迫于上条及上上条都答非所问,午休时间琢磨了下
react app 从 html script 里读取环境变量的配置吧,docker nginx image ( 1.19 版本开始) 支持使用 /etc/nginx/templates/*.template 模板文件来提取环境变量到 /etc/nginx/conf.d 中,所以你可以试试在启动 nginx 时把想要的环境变量动态的通过 nginx http_sub_filter 指令,注入到 index.html 中 |
23
7anshuai 2021-12-24 14:10:37 +08:00
@arischow 我也是刚去看了下 nginx image 的文档,发现可以这么搞 差不多就是利用 nginx 来做动态化下发页面配置了吧 😂
|
24
gamesover OP @7anshuai 我看了下,这个方法也是厉害,code + server 配置
但是还要我之前说的,前端是没有任何秘密的 用户无论如何都是可以看到想看的变量和密码,如果你植入了前端的话 我们老大弄环境变量的一大原因是,想影响前端调用位于环境变量的 password 和 key ,这其实是暴露于用户的 |
25
arischow 2021-12-24 14:33:03 +08:00
@gamesover #24 抱歉。我想了想,跟你不一样的情况应该是我只需要在 index.html 有不同的 baseUrl 就可以了,因为到生产环境的时候静态文件会经过 CDN
|
26
CodingNaux 2021-12-24 14:52:17 +08:00
需求:
1. 打包一次 2. 每个环境变量不同 所以打包永远都是 webpac production mode, 环境变量通过 nodejs,通过模版写入全局变量.这样代码就能读取不同环境的变量 |
27
CodingNaux 2021-12-24 14:54:20 +08:00
#26 如果有 node 层,可以用这个
|
28
jessynt 2021-12-24 14:57:57 +08:00
|
29
jessynt 2021-12-24 15:03:00 +08:00
参考: https://developers.redhat.com/blog/2021/03/04/making-environment-variables-accessible-in-front-end-containers
在容器启动时,替换环境变量到打包好的 js 文件中 |
30
leoskey 2021-12-24 18:51:42 +08:00
react build 后的文件是无法修改配置的,建议一下两种
1.在 docker build 时指定参数,--build-arg host=https:// 参考 #3 2.利用环境域名不同,react 里加载相对路径的配置文件 /config.js ,实际路径是 http://stg/config.js 或 http://pd/config.js |
31
walpurgis 2021-12-24 19:49:15 +08:00
仔细想想,容器注入的环境变量是给谁看的?是容器内启动的进程,前端代码想得到这些变量就必须通过它们来传递
|
32
7anshuai 2021-12-24 23:16:47 +08:00
@gamesover 正如 create-react-app 文档中说的那样:WARNING: Do not store any secrets (such as private API keys) in your React app!
API 的密钥应该存在服务器,React app 通过服务端接口再去调用第三方服务 @arischow 晚上闲着没事,写了篇博客记录一下上面提到的思路,供参考 https://7anshuai.js.org/blog/add-react-app-env-vars-by-nginx/ |