部署至Kubernetes的CRA React应用如何分环境配置不同API地址
Kubernetes上部署CRA React应用的多环境API配置方案
方案一:基于ConfigMap动态生成.env通过process.env读取的可行性说明
该方案可行,但存在明确的适用限制,必须匹配CRA的编译特性实现
CRA的process.env变量是构建阶段静态替换的,不是运行时动态读取,也就是说你在容器启动后再往项目目录写.env文件,已经构建好的静态JS代码不会重新读取这些值,必须把.env生成步骤放在构建执行前。
具体实现步骤:
- 按环境做ConfigMap隔离:因为不同环境部署在独立集群,直接在每个集群创建同名的
react-app-configConfigMap,写入对应环境的API地址即可,示例:
# dev集群ConfigMap apiVersion: v1 kind: ConfigMap metadata: name: react-app-config data: REACT_APP_API_ENDPOINT: "https://dev-cluster.api/endpoint"
注意:CRA要求所有自定义环境变量必须以
REACT_APP_开头,否则构建时不会被识别注入,直接写API_ENDPOINT会导致代码里读取到undefined。test/staging/production集群只需要替换ConfigMap中对应的值即可。
- 调整CI/CD构建逻辑:在对应环境的流水线中,先通过kubectl获取目标集群ConfigMap中的变量值,写入项目根目录的
.env.production文件,再执行npm run build构建静态资源,最后把构建产物打包成镜像部署到对应集群。
这个方案的缺点是每个环境需要单独构建镜像,无法实现一次构建多环境复用,镜像版本和环境强绑定,不符合云原生应用交付的最佳实践。
关于「React直接访问ConfigMap获取配置」的解答
默认不可行,极度不推荐
React代码最终是编译成静态JS运行在终端用户的浏览器里,不是运行在Kubernetes集群的Pod内部,既没有权限访问Kubernetes集群的API,也读取不到Pod内部挂载的ConfigMap文件。如果硬要实现这个逻辑,需要额外开发后端服务、暴露K8s API、配置公网访问和权限控制,安全风险极高,维护成本远大于收益。
更优实现方案:运行时全局配置注入(一次构建,多环境复用)
这个方案不需要依赖CRA构建时的环境变量替换,镜像构建完成后可以在所有环境复用,只需要通过不同环境的ConfigMap注入对应配置即可,是目前生产环境最常用的实现方式:
- 第一步:在项目
public目录下新建config.js文件,写入全局配置占位:
window.APP_CONFIG = { API_ENDPOINT: "" };
- 第二步:在
public/index.html的<head>标签最顶部引入该配置文件,保证业务代码加载前配置已经生效:
<script src="%PUBLIC_URL%/config.js"></script>
- 第三步:替换业务代码中的环境变量读取逻辑,不再使用
process.env,改为读取全局配置:
// 原逻辑 const API_URL = process.env.REACT_APP_API_ENDPOINT; const API_URL = window.APP_CONFIG.API_ENDPOINT;
- 第四步:调整容器镜像的启动逻辑,在Nginx(或其他静态资源服务)启动前,把Pod中从ConfigMap注入的环境变量写入静态资源目录下的
config.js文件。
示例Dockerfile:
对应的# 构建阶段:正常安装依赖、构建静态资源,不需要注入任何环境相关变量 FROM node:18-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build # 运行阶段:使用Nginx托管静态资源 FROM nginx:alpine # 复制构建产物到Nginx静态资源目录 COPY --from=builder /app/build /usr/share/nginx/html # 复制启动脚本 COPY entrypoint.sh /entrypoint.sh RUN chmod +x /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"] CMD ["nginx", "-g", "daemon off;"]entrypoint.sh启动脚本内容:#!/bin/sh # 动态生成运行时配置文件 cat > /usr/share/nginx/html/config.js << EOF window.APP_CONFIG = { API_ENDPOINT: "${API_ENDPOINT}" }; EOF # 启动Nginx exec "$@" - 第五步:在各集群的Deployment配置中,把对应环境的ConfigMap以环境变量形式注入容器:
containers: - name: react-app image: your-react-app-image:latest # 所有环境用同一个镜像 envFrom: - configMapRef: name: react-app-config # 每个集群的ConfigMap存对应环境的API地址
这个方案的优势:
- 镜像只需要构建一次,从流程上避免了不同环境构建逻辑不一致导致的上线故障
- 配置调整不需要重新构建、推送镜像,只需要更新对应集群的ConfigMap后重启Pod即可生效
- 没有额外的依赖组件,维护成本极低
内容的提问来源于stack exchange,提问作者Huzan Toorkey
相关产品推荐
相关产品推荐

