29
Handling multiple Angular environments with Docker and Nginx
Before we get started, here is a quick summary of what this post is about. Imagine you have an angular project with multiple environments, and for each environment you will need to have separate Nginx templates/configs, separate Dockerfiles and, on top of that, more often than not your environmental variables will be duplicated. If this is something you would like to improve, then you are in the right place. π Setting up dockerfiles and nginx configurations is not in the scope of this article, so keep in mind that some knowledge of docker and nginx is required, as we will not dive into these topics.
angularapp
βββ config
β βββ nginx
β β βββ default.conf.template
β β βββ start-nginx.sh
β βββ ssl
β β βββ cert-name.crt
β β βββ cert-name.key
β βββ tools
β β βββ set-env.ts
β βββ Dockerfile
βββ docker-compose.yml
βββ package.json
βββ src
...
Inside our dockerfile, beside installing dependencies and building the angular project, we will RUN
:
npm run set-env
which will substitute environment.prod.ts
with a new file where we define apiUrl and production variables.
sh -c usr/bin/start-nginx.sh
which will substitute from default.conf.template
NGINX_SSL_CERT_PATH variable and replace the nginx default config.
#####################
### Angular/Nginx ###
#####################
# ---------------- ANGULAR SETUP START ----------------
FROM node:12 as builder
ARG api_url
ENV API_URL=${api_url}
ENV PRODUCTION=true
RUN mkdir /ng-app
WORKDIR /ng-app
COPY . .
RUN npm set progress=false && npm config set depth 0 && npm cache clean --force
RUN npm install
RUN npm run set-env
RUN node --max_old_space_size=8192 ./node_modules/@angular/cli/bin/ng build --subresource-integrity --aot --output-hashing=all
# ---------------- ANGULAR SETUP END ----------------
# ---------------- NGINX SETUP START ----------------
FROM nginx:alpine
RUN apk add gettext
ARG ssl_cert_name
ENV NGINX_SSL_CERT_PATH="/app/ssl/${ssl_cert_name}"
COPY config/ssl/${ssl_cert_name}.crt config/ssl/${ssl_cert_name}.key /app/ssl/
COPY config/nginx/start-nginx.sh /usr/bin/start-nginx.sh
COPY config/nginx/default.conf.template /etc/nginx/nginx.conf.template
RUN chmod +x /usr/bin/start-nginx.sh
# ---------------- NGINX SETUP END ----------------
# 1. Copy build files to nginx html folder
# 2. Substitute ENV variables & Start nginx
COPY /ng-app/dist/angularapp/ /usr/share/nginx/html/
CMD /bin/sh -c "usr/bin/start-nginx.sh"
const { writeFile } = require('fs');
const colors = require('colors');
const envConfigFile = `export const environment = {
apiURL: '${process.env.API_URL}',
production: '${process.env.PRODUCTION}',
};
`;
const targetPath = `./src/environments/environment${production === 'false' ? '' : '.prod'}.ts`;
console.log(colors.magenta(`The file ${targetPath} will be written with the following content: \n`));
console.log(colors.grey(envConfigFile));
writeFile(targetPath, envConfigFile, (err) => {
if (err) {
throw console.error(err);
} else {
console.log(colors.magenta(`Angular environment was generated correctly at ${targetPath} \n`));
}
});
server {
listen 80;
sendfile off;
gzip on;
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
location / {
alias /usr/share/nginx/html/;
try_files $uri /index.html;
}
}
server {
listen 443 ssl;
sendfile off;
ssl on;
ssl_certificate ${NGINX_SSL_CERT_PATH}.crt;
ssl_certificate_key ${NGINX_SSL_CERT_PATH}.key;
gzip on;
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
location / {
alias /usr/share/nginx/html/;
try_files $uri /index.html;
}
}
Here we first replace the variables defined as a first argument '$$VAR_1'
in our /etc/nginx/nginx.conf.template
then we replace our default nginx default config template with the new config template.
#!/bin/sh
set -e
echo "NGINX_VARS: $NGINX_SSL_CERT_PATH"
envsubst '$$NGINX_SSL_CERT_PATH' < /etc/nginx/nginx.conf.template > /etc/nginx/conf.d/default.conf
nginx -g 'daemon off;'
{
"name": "angularapp",
"version": "0.0.0",
"private": true,
"scripts": {
"set-env": "ts-node ./config/tools/set-env.ts",
...
},
}
version: '3.6'
services:
angularapp:
container_name: angularapp
build:
context: .
dockerfile: ./config/Dockerfile
args:
api_url: https://example.com
ssl_cert_name: cert-name
ports:
- 4200:80
Now that we have created all the necessary files, we can build our docker container.
We can do this two ways:
docker-compose -f .\docker-compose.web.yml up --build angularapp
docker build -t angularapp --build-arg ssl_cert_name=cert-name --build-arg api_url=https://example.com ./config/Dockerfile
docker run -p 4200:80 angularapp
version: '3.6'
services:
example:
container_name: example
build:
context: .
dockerfile: ./config/Dockerfile
args:
api_url: https://example.com
ssl_cert_name: cert-name
ports:
- 4200:443
example2:
container_name: example2
build:
context: .
dockerfile: ./config/Dockerfile
args:
api_url: https://example2.com
ssl_cert_name: cert-name2
ports:
- 5200:443
Ready!
Your project can now host multiple environments. All you need to do is add a new container for each environment in your docker-compose.web.yml file.
Thank you for reading this post, feel free to leave a comment if you have any questions.
29