Amerigo Mancino
Posted on November 30, 2020
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:
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'
}
};
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"
}
],
},
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"
},
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
Run it with:
http-server ./dist
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"
What's important to notice here is the line
PROFILE: int
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
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
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;
}
}
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
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.
Posted on November 30, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.