Configure Angular 2 Webpack in a specific Docker container environment

We want to deploy our Angular 2 application using Docker images in different environments (production / testing, production, ...)

When developing locally, we connect to the base REST API through http: // localhost: 8080 , but when we deploy in different environments, we want to use the same Docker image and connect to a different REST API endpoint .

What would be the preferred way to insert this configuration into the Docker container at runtime ?

Is there a way to do this using environment variables ?

Can we do this with a plain text file containing something like

{ "BASE_URL": "https://api.test.example.com" } 
+6
docker angular webpack nginx
Nov 02 '16 at 12:25
source share
3 answers

After a few discussions on this post and on Twitter, there seems to be no easy way to achieve what I want with Webpack. Files are used only as static files at run time, and it is impossible to exclude a file at build time and include it at run time.

So, I decided to go with a solution / workaround that I had in mind: changing static files when starting the docker container.

I create a docker image by doing

 npm run build:prod docker build -t angularapp . 

I am using the official nginx docker image as the main image, and the Docker file looks like

 FROM nginx:1.11.1 COPY dist /usr/share/nginx/html COPY run.sh /run.sh CMD ["bash", "/run.sh"] 

run.sh used to modify the configuration file through sed and to run nginx:

 #!/bin/sh /bin/sed -i "s|http://localhost:8080|${BASE_URL}|" /usr/share/nginx/html/api.config.chunk.js nginx -g 'daemon off;' 

This allows me to configure BASE_URL through the environment variable in my docker-compose.yml file (simplified):

 version: '2' services: api: image: restapi frontend: image: angularapp environment: BASE_URL: https://api.test.example.com 

With this solution / workaround, I can deploy the docker image created by my jenkins task to deploy a specific version in all my environments (development, creation, production) by setting the REST API endpoint used through the environment variable when launching the docker container,

+7
Nov 04 '16 at 20:39
source share
β€” -

The final solution here depends entirely on what your CI / CD toolchain looks like, but this solution can be molded into anything.

First step: add something like https://github.com/motdotla/dotenv to your dependencies , this will handle your configuration values. There are other options, and depending on your needs, renting your own is easy enough.

In the documents, load the configuration as early as possible in your application (the global app.module.ts is my personal choice, since we want it to be available globally).

Simple - based on process.env.NODE_ENV you are going to load different configurations for each stack and make DX simple, I always give default configuration values, so my developers do not need to worry about the file.

For TESTING, STAGING, PRODUCTION - As an example, you want to set BASE_URL_STAGING and BASE_URL_PRODUCTION in environment variables for any CI provider that you use.

As part of your CI run and based on the git branch, write your configuration values ​​to the .env file, and then add COPY to your Dockerfile || docker-compose.yml to pull out the environment file that you just wrote during docker build.

After checking when you click the new docker image, .env is part of your deployment package aimed at what you need. The specific endpoints of the environment that you need.

+1
Nov 02 '16 at 15:33
source share

I would be a little different, but in a similar approach to your sed -shellscript.

I like the idea of ​​a β€œtext configuration file” that you mentioned, like this:

Serve the configuration file from a known location, for example. ./config ? Since your JS is already loaded from the current site, at least there you should be able to rely on the relative path.

Step 1: running shellscript in the docker container writes configuration parameters from environment variables to the plaintext file and puts it in the same folder as the angular packed code.

Step 2. There is some initialization code in the main HTML file loading the application, for example:

 $(function() { $.get('./config') .then(function(res) { window.appConfig = res.data; // your bootstrapping call angular.bootstrap(....); }); }); 

Step 3: You use global variables in your angular application, for example. if you use OpaqueToken:

 import { OpaqueToken } from '@angular/core'; const CONFIG_TOKEN = new OpaqueToken('config'); export const THIRDPARTYLIBPROVIDERS = [ { provide: CONFIG_TOKEN, useValue: window.appConfig } ]; 

Yes, this is still a bit hacky, and in your dev-env node-proxy, which you use to serve the ng application, should also expose such a configuration endpoint. In addition, this requires an additional request, but this could be easily avoided by expanding the bit of the init code to cache the data in localStorage, for example (given that this data will not change over time).

But in general, I think this is a little more convenient than sed in some files that you really don't know about how they are laid out.

Let me know what you think!

0
Nov 06 '16 at 20:07
source share



All Articles