create-react-app构建的静态React项目无法读取K8s容器环境变量
问题结论
使用create-react-app(以下简称CRA)创建的纯静态React应用,无法直接读取容器运行阶段定义的环境变量,你遇到的undefined问题是CRA的环境变量机制和前端应用的运行特性决定的。
根本原因
- CRA的环境变量注入逻辑发生在构建阶段:执行
react-scripts build打包时,工具会遍历代码,把所有process.env.REACT_APP_*格式的引用直接替换为构建时对应环境变量的字符串值,硬编码进最终生成的静态JS文件中。打包完成后,这些值就固定了,不会再随运行环境变化。 - 静态React应用的代码最终运行在用户的浏览器端,而非你部署服务的容器内部。浏览器属于客户端环境,没有任何渠道可以直接读取服务器容器里配置的环境变量。
- 你当前配置里用
npm start(即react-scripts start)启动的是webpack开发服务器,这个服务仅用于本地开发,虽然理论上它启动时会读取当前进程的环境变量注入前端,但它没有做生产级的性能、安全优化,内存占用高、访问延迟高,完全不适合生产部署。
解决方案
根据你是否需要动态调整环境变量(即改k8s配置后不需要重建镜像即可生效),可以选以下两种方案:
方案1:构建阶段注入环境变量(适合变量值固定的场景)
把环境变量的传递提前到镜像构建阶段,在执行npm run build时就把REACT_APP_开头的变量传入,让值直接打包进静态资源。
调整后的Dockerfile参考:
# 构建阶段 FROM node:18-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . # 接收构建时传入的参数 ARG REACT_APP_MY_ENV_VARIABLE # 构建时注入变量,生成静态文件 RUN npm run build # 生产运行阶段,用Nginx托管静态资源 FROM nginx:alpine COPY --from=builder /app/build /usr/share/nginx/html EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]
如果用k8s构建镜像,可以在构建流程中把对应的值作为build-arg传入即可。这个方案的缺点是修改环境变量必须重新构建镜像,无法通过修改Deployment的env配置重启Pod生效。
方案2:运行时动态注入环境变量(推荐,适合需要灵活调整配置的场景)
通过容器启动脚本动态生成配置文件,实现改k8s env配置后重启Pod即可生效,不需要重建镜像。
具体操作步骤:
- 在项目
public目录下新建config.js模板文件,内容如下:
window.APP_RUNTIME_CONFIG = { MY_ENV_VARIABLE: "" }
- 打开
public/index.html,在引入业务JS脚本的标签之前,提前引入这个配置文件:
<script src="%PUBLIC_URL%/config.js"></script>
- 调整前端代码,不再通过
process.env读取值,改为读取全局配置:
// 原来的写法:const envVal = process.env.REACT_APP_MY_ENV_VARIABLE const envVal = window.APP_RUNTIME_CONFIG.MY_ENV_VARIABLE
- 新建容器入口脚本
entrypoint.sh,作用是在Nginx启动前,把容器当前的环境变量写入config.js:
#!/bin/sh # 动态生成运行时配置文件 cat > /usr/share/nginx/html/config.js << EOF window.APP_RUNTIME_CONFIG = { MY_ENV_VARIABLE: "$REACT_APP_MY_ENV_VARIABLE" } EOF # 执行传入的启动命令 exec "$@"
- 调整Dockerfile,加入入口脚本配置:
FROM node:18-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build FROM nginx:alpine COPY --from=builder /app/build /usr/share/nginx/html # 拷贝入口脚本并赋予执行权限 COPY entrypoint.sh /entrypoint.sh RUN chmod +x /entrypoint.sh EXPOSE 80 # 配置入口点 ENTRYPOINT ["/entrypoint.sh"] CMD ["nginx", "-g", "daemon off;"]
用这个方案构建的镜像,你在k8s Deployment中配置的REACT_APP_MY_ENV_VARIABLE会在Pod启动时被自动写入配置文件,前端加载页面时就能拿到最新值,不需要重建镜像。
注意事项
- 永远不要在生产环境使用
react-scripts start部署应用,它的设计目标仅为本地开发调试。 - 不要把敏感信息(比如密钥、数据库密码)存在前端可以读到的环境变量里,所有前端可访问的配置都相当于公开给所有访问用户的。
内容的提问来源于stack exchange,提问作者Huzan Toorkey
相关产品推荐
相关产品推荐

