我们希望在不同环境中使用 Docker镜像部署我们的 Angular 2 应用程序(登台/测试,制作......)
在本地开发时,我们通过http://localhost:8080连接到后端REST API但是当我们在不同的环境中部署时,我们想要使用相同的Docker镜像并连接到不同的REST API端点。
在运行时将配置 注入到 Docker容器的首选方法是什么?
有没有办法通过环境变量来做到这一点?
我们可以通过包含
之类的纯文本文件来完成此操作{
"BASE_URL": "https://api.test.example.com"
}
答案 0 :(得分:10)
在这篇文章和Twitter上进行了一些讨论后,看起来没有简单的方法可以通过Webpack实现我想要的东西。这些文件仅在运行时作为静态文件提供,并且无法在构建时排除文件并将其包含在运行时。
所以我决定采用我想到的解决方案/解决方法:在启动docker容器时更改静态文件。
我通过
创建我的泊坞窗图像npm run build:prod
docker build -t angularapp .
我使用官方的nginx docker镜像作为我的基本图像,Dockerfile看起来像
FROM nginx:1.11.1
COPY dist /usr/share/nginx/html
COPY run.sh /run.sh
CMD ["bash", "/run.sh"]
run.sh
用于通过sed
修改配置文件,然后启动nginx:
#!/bin/sh
/bin/sed -i "s|http://localhost:8080|${BASE_URL}|" /usr/share/nginx/html/api.config.chunk.js
nginx -g 'daemon off;'
这允许我在BASE_URL
文件(简化)中配置docker-compose.yml
via环境变量:
version: '2'
services:
api:
image: restapi
frontend:
image: angularapp
environment:
BASE_URL: https://api.test.example.com
通过此解决方案/解决方法,我可以通过在启动docker容器时配置通过环境变量使用的REST API端点,将我的jenkins作业创建的docker镜像部署到所有环境(开发,登台,生产)中的特定版本部署。
答案 1 :(得分:3)
这里的最终解决方案完全依赖于你的CI / CD工具链的样子,但这个解决方案几乎可以被塑造成任何东西。
第一步:向dependencies
添加https://github.com/motdotla/dotenv之类的内容,这将处理您的配置值。还有其他的选择和根据您的需求,自己动手也很容易。
根据文档,尽早在您的应用中加载配置(全局app.module.ts是我个人的选择,因为我们希望全局可用)。
简单 - 基于process.env.NODE_ENV
你将为每个堆栈加载不同的配置并使DX变得简单,我总是给配置值一个默认值,这样我的开发人员就不用费心了。
对于TESTING, STAGING, PRODUCTION
- 例如,您要设置BASE_URL_STAGING
&您正在使用的任何CI提供程序的环境变量中都有BASE_URL_PRODUCTION
。
作为CI运行的一部分&基于git branch,将您的配置值写入.env
文件,然后将COPY
添加到Dockerfile
|| docker-compose.yml
引入您在docker build期间编写的环境文件。
验证完成后,当您推送新的泊坞窗映像时,.env是部署程序包的一部分,目标是您需要的环境特定端点。
答案 2 :(得分:1)
我会采取略微不同的方式,但与你的sed
- shellcript类似。
我喜欢你提到的“纯文本配置文件”的想法,如何:
从已知位置提供配置文件,例如./config
?
由于您的JS已经从当前站点加载,至少在那里您应该能够依赖相对路径。
步骤1:在docker容器中启动的shellscript将环境变量中的配置参数写入纯文本文件,并将其放在与压缩角度代码相同的文件夹中。
步骤2:在加载应用程序的主HTML文件中,有一些这样的初始化代码:
$(function() {
$.get('./config')
.then(function(res) {
window.appConfig = res.data;
// your bootstrapping call
angular.bootstrap(....);
});
});
第3步:使用角度应用中的全局变量,例如:如果您使用的是OpaqueToken:
import { OpaqueToken } from '@angular/core';
const CONFIG_TOKEN = new OpaqueToken('config');
export const THIRDPARTYLIBPROVIDERS = [
{ provide: CONFIG_TOKEN, useValue: window.appConfig }
];
是的,这仍然有点hacky&在您的开发环境中,用于为ng-app提供服务的节点代理也必须公开这样的配置端点。 此外,这还需要一个额外的请求,但这可以通过稍微扩展init-code来缓存localStorage中的数据(例如,假设这些数据不会随时间真正改变)而轻松避免。
但总而言之,我认为这比sed
更易于维护 - 一些你根本不知道它们是如何布局的文件。
让我知道你的想法!