How to dockerize an Angular app for different environments

amerigom

Amerigo Mancino

Posted on November 30, 2020

How to dockerize an Angular app for different environments

Docker is an open-source tool designed to help programmers in development and deployment. It makes use of a structure called "container" which wraps the application and its dependencies together so that it can be executed on any machine. This is particularly important when have to deal with different servers - testing, integration, production - where the applications must run without any error or compatibility issue.

In this tutorial I will explain how to dockerize an Angular application for different target environments.

Set up custom environments in Angular

By default, Angular provides two different environment files, that can be found in the environments folder:

Alt Text

Let's add a couple more! Create two new files named environment.test.ts and environment.int.ts and replace in there your urls with the ones you want to use for the target environment. Here is my environment.int.ts:



export const environment = {
    production: false,
    name: 'int',
    functionUrls: {
        data1: 'my-data1-int-url',
        data2: 'my-data2-int-url'
    }
};


Enter fullscreen mode Exit fullscreen mode

Then we need to tell Angular that we have new build configurations: edit the angular.json file and create new entries under architect → build → configuration. As you can see, the production and local (serve) entries are already present.

When inserting a custom environment we only need to notify the framework to replace the default environment.ts with the one we want at build-time, so in principle it is sufficient to add the following:



"int": {
  "fileReplacements": [
     {
      "replace": "src/environments/environment.ts",
      "with": "src/environments/environment.int.ts"
     }
  ],
},


Enter fullscreen mode Exit fullscreen mode

We can customize the build options by adding extra settings. Refer to the official documentation for further details.

As a last step, let's edit the package.json and write some commands to build the app more easily:



"scripts": {
   "ng": "ng",
   "start": "ng serve",
   "build": "ng build",
   "build-test": "ng build --configuration=test",
   "build-int": "ng build --configuration=int",
   "build-prod": "ng build --prod",
   "test": "ng test",
   "lint": "ng lint",
   "e2e": "ng e2e"
},


Enter fullscreen mode Exit fullscreen mode

Let's build our app!

Open a terminal and from the main project folder run npm build-int. This will build the application for the int environment. Your output is located into the dist folder in your project, ready to be deployed on a server.

If you want, you can test it using http-server. Install it with:



npm install http-server -g


Enter fullscreen mode Exit fullscreen mode

Run it with:



http-server ./dist


Enter fullscreen mode Exit fullscreen mode

It will start serving your project from the dist folder.

Integrate Docker

Now that we can build a project for different environments, it's time to integrate Docker and run the application in a container. First, create a docker folder inside the project, which will contain all the docker-related files. Then create a docker-compose file for each environment: docker-compose.int.yml for integration , docker-compose.test.yml for testing and so on. These files look like the following:



version: '3.3'

services:
  myapp:
    image: myapp
    build:
      context: ../
      dockerfile: docker/Dockerfile
      args:
        PROFILE: int
    ports:
      - "8080:80"


Enter fullscreen mode Exit fullscreen mode

What's important to notice here is the line



PROFILE: int


Enter fullscreen mode Exit fullscreen mode

were we define the environment we want to use: we'll inject this variable in the Dockerfile in a moment.

Let's create the Dockerfile:



FROM node:12.16.1-alpine As builder

### STAGE 1: Build ###
WORKDIR /usr/src/app
COPY package.json package-lock.json ./

RUN npm install

COPY . .

ARG PROFILE
ENV PROFILE $PROFILE

RUN echo "Environment: ${PROFILE}"
RUN npm run build-${PROFILE}

### STAGE 2: Run ###
FROM nginx:1.15.8-alpine

COPY --from=builder /usr/src/app/dist/myapp/ /usr/share/nginx/html
COPY --from=builder /usr/src/app/docker/nginx.conf /etc/nginx/conf.d/default.conf

EXPOSE 80


Enter fullscreen mode Exit fullscreen mode

In stage one we build the application and restore the node_modules. As you can see, we use the PROFILE variable we defined above to retrieve the correct environment.

In stage two we run the application using nginx, which is an http and reverse proxy server. By default, nginx http server listens for incoming connection on port 80, which represents the standard web port. In the docker-compose we match that port with 8080.

In addition, note that here



COPY --from=builder /usr/src/app/docker/nginx.conf /etc/nginx/conf.d/default.conf


Enter fullscreen mode Exit fullscreen mode

we replace the default nginx configuration with ours. To do so, we need to create one last file in our docker folder, called nginx.conf:



server {
  listen 80;
  location / {
    root /usr/share/nginx/html;
    index index.html index.htm;
    try_files $uri $uri/ /index.html =404;
  }
}


Enter fullscreen mode Exit fullscreen mode

All games are done! Let's try to make this work.

If we want to build and run the configuration for integration, we only need to run the following commands in a terminal:



docker-compose -f docker/docker-compose-int.yml build
docker-compose -f docker/docker-compose-int.yml up


Enter fullscreen mode Exit fullscreen mode

The up command will append the console at a message saying Attaching to..., then it goes to print logs.
Navigate to localhost:8080 to check the outcome.

💖 💪 🙅 🚩
amerigom
Amerigo Mancino

Posted on November 30, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related