Your Angular apps as Docker containers

In this article, I will show you how to create a Docker image from your Angular application, publish and consume it from the Docker Hub.

EDIT: You can find updated version of this article on my new blog here: https://denys.dev/2018-03-02/your-angular-apps-as-docker-containers/

“A large number of shipping containers in a busy cargo port” by chuttersnap on Unsplash

Creating new Angular application

Creating a Docker image from your Angular application is easy.

You can use images for internal purposes, for example, testing on different machines, operating systems and browsers.

You can also use Docker images for external use. It becomes possible to try your application without installing node.js, running npm install to “download entire internet”, or avoid troubleshooting environment setup.

Before we start, let’s generate a new application using the following Angular CLI command:

ng new my-angular-app
cd my-angular-app

Try running the application to ensure it compiles correctly and displays in the browser:

ng serve --open

By default, the browser should open with the “http://localhost:4200" address. Note the port 4200; later in the article, we are going to use port 3000 to ensure we are running from the Docker container and not the local folder.

Creating a Docker Image

Now as we got the base application up and running, let’s create a new Dockerfile to build an image.

In this article, I am going to use Nginx to serve the compiled application. To get a minimal output let’s take the “alpine” version:

Dockerfile example

As you can see from the example above, we are going to copy the “dist” folder inside the image, together with the nginx.conf configuration file.

A straightforward configuration implementation can look like in the next example:

nginx configuration

Next, we need to get the “dist” folder, containing the compiled application. It can be either development or production build. Let’s create the optimised production one:

ng build --prod

Never try to run npm install or yarn install inside the image. When it comes to scaling and creating multiple containers, the last thing you want is hundreds of images downloading lots of data at startup. You should always aim to serve the final production builds inside your Docker images.

Now, let’s build the image and call it my-angular-app:

docker image build -t my-angular-app .

The Docker should produce an output similar to the following one but with different hash codes:

Sending build context to Docker daemon  313.8MB
Step 1/4 : FROM nginx:alpine
---> 537527661905
Step 2/4 : COPY nginx.conf /etc/nginx/nginx.conf
---> Using cache
---> d7869159eb38
Step 3/4 : WORKDIR /usr/share/nginx/html
---> Using cache
---> c916b558f370
Step 4/4 : COPY dist/ .
---> b24c9dfec8a7
Successfully built b24c9dfec8a7
Successfully tagged my-angular-app:latest

The process should be relatively fast. Once it is complete, feel free to test the image is there, by running the next command:

docker image ls

You should see a list of available images, including the “my-angular-app” one with the tag “latest” and about 18 MB size.

It is now time to test the image. Run the command below to create a container and map it to the port 3000:

docker run -p 3000:80 --rm my-angular-app

If you now navigate to the “http://localhost:3000", you should get your initial Angular application up and running there. Moreover, the Nginx logs are redirected to your console output, so that you can see what’s happening inside the container:

Nginx log output in the console

That is all you need to build an image on your local machine! Let’s now proceed to provide support for multi-container Docker setup.

Docker Compose

At some point, you will most probably end up with multiple containers each serving a particular need, for example, a separate backend server, a database server and so forth.

Here’s a simple docker-compose.yml file you can prepare as a template for your Angular application:

docker-compose.yml

Note the build entry provided for development purposes. That means we are always going to build the local image if it is not available. You can remove this line later on once you start publishing images to Docker Hub.

Now use the next command to build the image and run it in a container:

docker-compose up

As before, navigate to “http://localhost:3000" to ensure the application runs as expected.

Once you are done playing with the application, you can clean up everything using the next command:

docker-compose down

If you want to remove everything, including the image created earlier, use the following command:

docker-compose down --rmi all

Next time when you run the docker-compose up command, you may see the following message:

WARNING: Image for service app was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.

That is a proof that Docker tool automatically builds a new image if it is not available.

Now, let’s try to publish our image to Docker Hub so that other users can use it.

Publishing to Docker Hub

You should have a Docker Hub account to publish images. The account is free, and you can create it here: https://hub.docker.com/

Once you have an account, run the login command in the terminal app and fill the username and password to be able publishing images:

docker login

Publishing your image is easy. Just run the following command in the root folder of your project, and replace the account value with your Docker Hub username.

docker image build -t account/my-angular-app:1.0 .

That creates a new image, ready to be deployed for your account. Use the next command to publish it, and don’t forget to use your Docker Hub username instead of the account value.

docker push account/my-angular-app:1.0

The process should be high-speed, and in a few seconds, your image is going to be public and available for use.

Running from Docker Hub

Now, as you project is published, you or any other person can run it locally by utilising the following command:

docker run -p 3000:80 account/my-angular-app:1.0

To quickly test the container and automatically clean everything up once it got stopped, you can add the--rm switch:

docker run -p 3000:80 --rm account/my-angular-app:1.0

Finally, to use the docker-compose.yml file with your published image, just remove the “build” option and point the image value to the published version:

image: 'account/my-angular-app'

Summary

Running your Angular applications with Docker containers can significantly reduce your development and testing efforts, especially if you intend frequently sharing your application either internally or with external users.

One of the most excellent benefits is that people who test or use your application do not need to use development tools to compile your project from the source code or configure a web server to run the compiled output. Everything comes with a container and runs on all operating systems without extra overhead.

You can find the source code for the article in the following GitHub repository: