在Docker容器环境中特定配置Angular 2 Webpack App

时间:2016-11-02 12:25:50

标签: angular nginx docker webpack

我们希望在不同环境中使用 Docker镜像部署我们的 Angular 2 应用程序(登台/测试,制作......)

在本地开发时,我们通过http://localhost:8080连接到后端REST API但是当我们在不同的环境中部署时,我们想要使用相同的Docker镜像并连接到不同的REST API端点

在运行时配置 注入 Docker容器的首选方法是什么?

有没有办法通过环境变量来做到这一点?

我们可以通过包含

之类的纯文本文件来完成此操作
{
    "BASE_URL": "https://api.test.example.com"
}

3 个答案:

答案 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更易于维护 - 一些你根本不知道它们是如何布局的文件。

让我知道你的想法!