In this article, I will show you, A complete tutorial to build an Angular application to docker production-ready image with multi-stages. And I will also run this angular docker image in a docker container.
Final this project-related files and directories structure …
. ├── dist │ └── docker-angular-app ├── Dockerfile ├── nginx │ └── default.conf ├── package.json ├── package-lock.json ├── ... └── ...
Create a angular project
In this article, I am using the fresh new angular app. But If you have any existing angular then you skip this part and you can use your existing angular application.
ng new docker-angular-app cd docker-angular-app
In the project directory, Create Dockerfile with no extension and first latter capital.
# STAGE 1: Build app # Step 1: Pull node offical image FROM node:16.13.2-alpine as builder # Step 2: Define working dir for builder container WORKDIR /usr/local/app # Step 3: Copy package.json and package-lock.json files COPY package*.json ./ # Step 4: Install dependancy RUN npm install # Step 5: Copy all source code COPY . . # Step 6: Generate build of application RUN $(npm bin)/ng build --configuration=production --source-map=false # STAGE 2: Setup Server # Step 7: Pull nginx image FROM nginx:1.21.5-alpine # Step 8: Copy default nginx config COPY nginx/default.conf /etc/nginx/conf.d/default.conf # Step 9: Copy builded application source code COPY --from=builder /app/dist/docker-angular-app /usr/share/nginx/html # step 10: Expose container port 80 EXPOSE 80 # Step 11: Switch nginx deamon off # Note: If your container serve multiple service than don't daemon off. CMD nginx -g "daemon off;"
That is a docker snippet, I use to build for angular application to the docker image. This docker snippet has a multi-stage build.
Stage #1: Build this angular app to production ready code
FROM node:16.13.2-alpine as builder
Pulling node runtime image, Initialize the new build stage. In my case, I used node 16.13.2 alpine version. It’s better to use your machine node version which is the angular app developed. In the development case, some developers use the node’s latest version. Which is not for production.
In the snippet, I have used the alpine version, which is lightweight more than the row node version
Sets the default working directory for the present building container. After this instruction is executed, If this directory doesn’t exist, this directory will be created. the subsequent steps in the
The defined directory(usr/local/app) is inside the container which has its own independent file system
COPY package*.json ./
Copy the source application dependency files (package.json and package-lock.json) on the host machine to the specified working directory(usr/local/app)
RUN npm install
In the working directory run command, “
npm install” to install all application dependencies.
COPY . .
Copy all the current directory source codes excluding folder or directory which is defined on the .dockerigone file.
Multiple building dependencies install problem understanding*
Note: It’s solved in this snippet code.
imagine you are building the app for the first time, and it is ok to install all the dependencies. But you change a source code related to the angular app (not related to any dependencies) and then push again to build the image. and the run process installs all dependencies again. You probably don’t want to install the dependency unless some dependency is added or removed.
When your execution process copies all files and directories, Install dependency. that problem will be happen
This snippet code, step 3: copy package.json and package-lock.json which are application dependencies related. Then step 4: install dependencies and step 5: copy all source codes.This execution process solve multiple build install dependencies, that’s used
RUN $(npm bin)/ng build --configuration=production --source-map=false
Executes the angular build in a new layer on top of the base node image. After this instruction is executed, the build output is stored under
usr/local/app/dist/docker-angular-app and the compiled image will be used for the subsequent steps in the
Stage #2: Serving the angular production ready app to nginx server
Initialize final or secondary build stage. nginx:18.104.22.168-alpine image as the base image for executing subsequent instructions relevant to nginx configuration
COPY nginx/default.conf /etc/nginx/conf.d/default.conf
Copy our own Nginx configuration file for the angular application to the docker Nginx server image.
Note: make sure your Nginx file is “nginx” directory. Or If it is inside others directory, so make sure you use right your configuration path
Step 9: COPY –from=builder /app/dist/docker-angular-app /usr/share/nginx/html
Copies the build output generated production-ready static resource in stage 1 (
--from=builder) to replace the default Nginx HTML contents.
Important Note: Angular builds production-ready static resources into ./dist/[project name]. In this example, the project name is
docker-angular-app so the output directory is
docker-angular-app. So make sure! you use your project name.
Step 10: EXPOSE 80
Exposing ports is a way of documenting which ports are used, but does not actually map or open any ports
CMD nginx -g "daemon off;"
I use Nginx daemon off. Because for microservices, the directive tells Nginx to stay in the foreground. For the microservices, the best practice is for one container = one process. So one container server has only one service.
When normal production on a server, I use the default Nginx
daemon on; So the Nginx server will start in the background. In this way, Nginx and other services are running and talking to each other. In this case, one server runs many services.
If you had used git, then you are so familiar with the .gitignore file. The .dockerignore file is very similar to the .gitignore file. It allows specifying a list of files or directories that Docker is to ignore during the build process. Most importantly, the .dockerignore can help you reduce the size of the image and dramatically speed up the build process.
# compiled output /dist /tmp /out-tsc # dependencies /node_modules # IDEs and editors /.idea # IDE - VSCode .vscode/* # misc /.angular/cache /.sass-cache /connect.lock /coverage /libpeerconnection.log npm-debug.log yarn-error.log testem.log /typings
This is a custom Nginx configuration snippet for our production-ready angular app.
Make sure you are using the right root path, which is a copy production-ready static resource in the container nginx path.
Create docker-angular-app/nginx/default.conf file in nginx separate folder.
Docker build image
docker build -t image_name:tag . docker build -t angular-app:latest .
Check docker images
Run docker image
docker run --name container_name -d -p local_machine_port:container_port image_name:tag docker run --name docker-angular-container -d -p 4000:80 angular-app:latest
Note: nginx configuration file lister port(80) must be same of container port(80)
Check docker containers
The below command shows the running containers of docker
Below command shows all inactive containers
docker ps -aq