作者:钓鱼翁玩围脖 | 来源:互联网 | 2022-12-29 18:52
我试图容纳一个前端Web应用程序,我有麻烦弄清楚如何传递环境变量.该应用程序是一个Angular应用程序,因此它是100%客户端.
在典型的后端服务中,传递环境变量很容易,因为一切都在同一主机上运行,因此后端服务可以轻松选择环境变量.但是,在前端应用程序中,这是不同的:应用程序在客户端的浏览器中运行.
我想通过环境变量配置我的应用程序,因为这使部署更容易.所有配置都可以完成,docker-compose.yml
无需维护多个映像,每个映像都适用于所有可能的环境.只有一个不可变的图像.这遵循12因素应用原则,可以在https://12factor.net/config上找到.
我正在构建我的应用程序映像如下:
FROM node:alpine as builder
COPY package.json ./
RUN npm i && mkdir /app && cp -R ./node_modules ./app
WORKDIR /app
COPY . .
RUN $(npm bin)/ng build
FROM nginx:alpine
COPY nginx/default.conf /etc/nginx/conf.d/
RUN rm -rf /usr/share/nginx/html/*
COPY --from=builder /app/dist /usr/share/nginx/html
CMD ["nginx", "-g", "daemon off;"]
在app/config.ts
,我有:
export const cOnfig= {
REST_API_URL: 'http://default-url-to-my-backend-rest-api'
};
理想情况下,我想在我的网站上做这样的事情docker-compose.yml
:
backend:
image: ...
frontend:
image: my-frontend-app
environment:
- REST_API_URL=http://backend:8080/api
所以我相信我应该改变它app/config.ts
来替换REST_API_URL
环境变量.因为我更喜欢不可变的Docker镜像(所以我不想在构建期间进行替换),我很困惑如何在这里取得进展.我相信我应该支持app/config.ts
在nginx代理启动之前改变运行时.但是,这个文件被缩小并且webpack-bundled的事实使得这更加困难.
任何想法如何解决这个问题?
1> Daniel Calde..:
我解决这个问题的方式如下:
1.使用唯一且可识别的字符串在enviroment.prod.ts中设置值:
export const envirOnment= {
production: true,
REST_API_URL: 'REST_API_URL_REPLACE',
};
2.创建一个entryPoint.sh,每次你完成容器的docker运行时,都会执行这个entryPoint.
#!/bin/bash
set -xe
: "${REST_API_URL_REPLACE?Need an api url}"
sed -i "s/REST_API_URL_REPLACE/$REST_API_URL_REPLACE/g" /usr/share/nginx/html/main*bundle.js
exec "$@"
如您所见,此入口点获取'REST_API_URL_REPLACE'参数并在main*bundle.js文件中替换它(在本例中)以获取var的值.
3.在CMD之前的dockerfile中添加entrypoint.sh(它需要执行权限):
FROM node:alpine as builder
COPY package.json ./
RUN npm i && mkdir /app && cp -R ./node_modules ./app
WORKDIR /app
COPY . .
RUN $(npm bin)/ng build --prod
FROM nginx:alpine
COPY nginx/default.conf /etc/nginx/conf.d/
RUN rm -rf /usr/share/nginx/html/*
COPY --from=builder /app/dist /usr/share/nginx/html
# Copy the EntryPoint
COPY ./entryPoint.sh /
RUN chmod +x entryPoint.sh
ENTRYPOINT ["/entryPoint.sh"]
CMD ["nginx", "-g", "daemon off;"]
4.使用env或使用docker-compose(必须转义斜杠)来恢复图像:
docker run -e REST_API_URL_REPLACE='http:\/\/backend:8080\/api'-p 80:80 image:tag
可能存在一个更好的解决方案,不需要在缩小文件中使用常规表达式,但这样可以正常工作.
2> Gene C..:
将您的环境变量放在index.html
!!
相信我,我知道你来自哪里!将特定于环境的变量烘烤到Angular应用程序的构建阶段中,与我所学到的有关可移植性和关注点分离的一切情况背道而驰。
可是等等!仔细看一下常见的Angular index.html
:
这就是所有配置!!!
就像用来维护Docker应用程序的docker-compose.yml一样:
版本化的不可变资产
环境变量
应用程序绑定
环境元数据
甚至不同的捆绑包都感觉像是docker image sorta的图层,不是吗?
runtime
就像您很少更改的基本图片一样。
polyfills
是您需要的那些没有包含在您所需的基本映像中的东西。
main
是您的实际应用,每个版本都会有很大的变化。
您可以使用前端应用程序执行与使用Docker应用程序相同的操作!
构建,版本化和发布不可变资产(js包/ Docker映像)
将部署清单发布到登台(index.html / docker-compose.yml)
分阶段测试
将部署清单发布到生产中。引用您刚刚测试的相同资产!即刻!原子地!
怎么样??
只是将臭味指向/src/environments/environment.prod.ts
该window
对象。
export const envirOnment= (window as any).env;
// or be a rebel and just use window.env directly in your components
并使用环境变量WHERE THEY BELONG将脚本添加到index.html !:
我对这种方法感到非常强烈,因此我创建了一个专用于此的网站:https : //immutablewebapps.org。我想您会发现还有很多其他好处!
~~~
现在,我已经使用两个AWS S3存储桶成功完成了此操作:一个用于版本化的静态资产,一个仅用于版本化index.html
(这使路由变得非常简单:index.html
为每个路径提供服务)。我还没有像您建议的那样运行容器。如果要使用容器,则希望在构建和发布新资产以及发布新资产之间进行明确区分index.html
。也许我会index.html
从带有容器环境变量的模板中即时渲染。
如果您选择这种方法,我很想知道结果如何!