Loading...
Loading...
Marco Franssen

In this tutorial, you'll learn how to package a static Angular app in a Docker container running Nginx. Packaging the app this way gives us an immutable image we can deploy consistently. Immutability has many benefits when maintaining a platform: things that cannot change state are less likely to surprise us later. It's also a familiar concept in functional programming languages. I won't list all the advantages here, but I encourage you to learn more about immutability in software development. It will teach you to look at software from a different perspective.
For the rest of this article, I assume you have a running Docker environment. If you don't, check out this article, which describes how to set up your Docker development environment.
Since this article isn't about writing an Angular app, we're going to clone an existing sample application from github.com.
git clone https://github.com/AngularShowcase/angular2-sample-app.gitWe'll add a Dockerfile to the root of the repository to define a ready-to-deploy image. A Dockerfile contains instructions that define your image.
FROM nginx
COPY nginx.conf /etc/nginx/nginx.conf
COPY dist/prod /usr/share/nginx/htmlAs you can see, we're copying all the files from our dist/prod folder and replacing the Nginx configuration with our own. In nginx.conf, we could configure custom caching policies for our web app, for example. I won't go into detail about configuring Nginx here. If you're unfamiliar with it, just remove that last line and use the default configuration. This is an example of how we can tune our infrastructure configuration for the app we're going to run. You should now have that special feeling in your veins called DevOps. ;-) Do you feel it?
To improve build performance, we can also include a .dockerignore file in the root of the project. Like .gitignore, this file specifies patterns for files you want to exclude from the build context.
Have a look at the Dockerfile reference docs to learn more about the available instructions and how to use .dockerignore.
To package the static web app as a Docker image, we first build it using npm run build.prod, a command already available in the sample project (see the scripts section in package.json). This outputs the static assets to dist/prod. Next, we use docker build to build the image from our Dockerfile. Remember how we copy the static assets into /usr/share/nginx/html?
npm run build.prod
docker build -t angular2-sample-app-nginx .We now have an immutable image that we can deploy to our servers or publish to a registry. Imagine our continuous integration server publishing the built image to our Docker registry. The infrastructure team can then deploy the desired version to production or test, either manually or through a continuous delivery server. For more information on docker build, see the Docker build reference docs.
Of course, we can also run the container ourselves using the following command.
docker run --name angular2-sample-app-nginx -v /nginx-logs:/var/log/nginx -p 8080:80 -d angular2-sample-app1Let's break down this command to understand what's happening.
--name angular2-sample-app-nginx runs the image we built in the previous step. Note that we gave it this name when building the image.-v /nginx-logs:/var/log/nginx maps /nginx-logs on the host to /var/log/nginx in the container, giving us access to the logs from our host.-p 8080:80 maps port 8080 on our host to port 80 in the container, where Nginx runs. We can then access the web app from our host on port 8080.-d runs the container in detached mode: it runs in the background until its main process (Nginx) exits.angular2-sample-app1 is the name of the running container instance. We could, for example, run multiple instances and put a load balancer in front of them.For more information on the docker run command, have a look at the Docker run reference docs.
By adding a Dockerfile to our project, we can package our app as an immutable image and deploy it as is. Port mapping lets us choose which host port exposes the service (8080 in our example). We also used a volume mapping to access the container's logs from the host.
You now know the basics of using a container. To dig deeper into Docker, here are the resources mentioned earlier in this article:
Thanks for reading this article. I'm looking forward to your feedback.
Marco Franssen
Follow my Raspberry Pi upgrade from Raspbian Jessie to Stretch, including backups, firmware updates, APT sources, Bluetooth audio changes, and cleanup.
Marco Franssen
Learn how to use Docker Compose to build and run a multi-container application, connect services, and organize development with Git submodules.
Marco Franssen
Set up a Docker development environment on Windows or Mac using Docker Machine and VirtualBox, then configure your shell and run a test container.
Marco Franssen
Learn how to replace Node.js error-first callbacks with Promises, flatten nested asynchronous code, and wrap callback APIs with practical examples.