React 在 docker, buildkite 部署,如何读取不同的 staging, qa 环境文件 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
gamesover
V2EX    React

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

  •  
  •   gamesover 2021-12-24 02:18:03 +08:00 3229 次点击
    这是一个创建于 1387 天前的主题,其中的信息可能已经有所发展或是发生改变。

    现在 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

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

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

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

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

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

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

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

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

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

    我现在一看,react 生成的生产文件,直接是把环境变量 hard code 进去的,用户一看明明白白,根本没有任何隐藏的必要
    7anshuai
        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 中
    arischow
        22
    arischow  
       2021-12-24 14:06:48 +08:00
    @7anshuai #21 我碰到和楼主一样的问题,现方法是 build N 个环境,等我来研究下你说的,多谢~
    7anshuai
        23
    7anshuai  
       2021-12-24 14:10:37 +08:00
    @arischow 我也是刚去看了下 nginx image 的文档,发现可以这么搞 差不多就是利用 nginx 来做动态化下发页面配置了吧
    gamesover
        24
    gamesover  
    OP
       2021-12-24 14:25:27 +08:00
    @7anshuai 我看了下,这个方法也是厉害,code + server 配置

    但是还要我之前说的,前端是没有任何秘密的
    用户无论如何都是可以看到想看的变量和密码,如果你植入了前端的话

    我们老大弄环境变量的一大原因是,想影响前端调用位于环境变量的 password 和 key ,这其实是暴露于用户的
    arischow
        25
    arischow  
       2021-12-24 14:33:03 +08:00
    @gamesover #24 抱歉。我想了想,跟你不一样的情况应该是我只需要在 index.html 有不同的 baseUrl 就可以了,因为到生产环境的时候静态文件会经过 CDN
    CodingNaux
        26
    CodingNaux  
       2021-12-24 14:52:17 +08:00
    需求:
    1. 打包一次
    2. 每个环境变量不同

    所以打包永远都是 webpac production mode, 环境变量通过 nodejs,通过模版写入全局变量.这样代码就能读取不同环境的变量
    CodingNaux
        27
    CodingNaux  
       2021-12-24 14:54:20 +08:00
    #26 如果有 node 层,可以用这个
    jessynt
        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 文件中
    leoskey
        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
    walpurgis
        31
    walpurgis  
       2021-12-24 19:49:15 +08:00
    仔细想想,容器注入的环境变量是给谁看的?是容器内启动的进程,前端代码想得到这些变量就必须通过它们来传递
    7anshuai
        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/
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1010 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 18:41 PVG 02:41 LAX 11:41 JFK 14:41
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86