Deploy an Angular app to Docker

Getting Angular building inside Docker was actually pretty straightforward. Let’s jump straight in with a basic Angular build and release to nginx:

FROM nginx:alpine as env

fetch dependencies

RUN apk add --no-cache nodejs nodejs-npm &&
apk upgrade --no-cache --available &&
npm config set unsafe-perm true &&
npm install -g @angular/cli npm-snapshot &&
npm cache clean --force

build step

FROM env as dev
COPY . src
WORKDIR src
RUN npm install &&
npm rebuild node-sass &&
ng build

release stage

FROM nginx:latest AS release
COPY --from=dev src/dist/ /usr/share/nginx/html/

OK, now let’s break this down:

Pre-build

FROM nginx:alpine as env

fetch dependencies

RUN apk add --no-cache nodejs nodejs-npm &&
apk upgrade --no-cache --available &&
npm config set unsafe-perm true &&
npm install -g @angular/cli npm-snapshot &&
npm cache clean --force

Here I am using the nginx:alpine base image — our Angular application is to be eventually served via a nginx server.

We are trying to standardise containers across all our microservices hence we are using alpine (linux) base image.

You could switch ngnix:alpine out for node:latest then you wouldn’t need the RUN apk add steps, which brings me on nicely to fetching our dependencies…

Since we are base-ing from alpine we don’t have npm or nodejs installed inside the container, so we must fetch and install them before installing the Angular CLI.

Note: if you’re basing from node you won’t need to fetch nodejs or npm, something like this should work:

FROM node:latest as env

RUN npm config set unsafe-perm true &&
npm install -g @angular/cli npm-snapshot &&
npm cache clean --force

Build

Once we have got our dependencies installed, now let’s build our Angular application inside our container:

# build step

FROM env as dev
COPY . src
WORKDIR src
RUN npm install &&
npm rebuild node-sass &&
ng build

Here we are copying all our files inside a /src folder, then install our project dependencies from npm using npm install.

Note: I have included a npm rebuild node-sass step here, as node-sass is generally bound to your OS so unless you you’re developing locally inside alpine, you might run into diffs without it as your package-lock.json will be locking to the version of your local OS.

Finally we can run our build step using ng build which should build our project into a /src/dist folder.

Release

Now we are ready to release our built files to a ngnix server by copying them to the root of the ngnix as below.

# release stage

FROM nginx:latest AS releaseCOPY --from=dev src/dist/<project>/ /usr/share/nginx/html/

Note: dependant on the build setup of your Angular application, you may need to specify which folder your files are built to.

Lint / unit tests

Now, wouldn’t it be nice to be able to run our lint and unit tests inside Docker?

To do this, we first need to fetch chrome drivers required for alpine, change the RUN apk add line to the following:

RUN apk add --no-cache nodejs nodejs-npm bash chromium nss chromium-chromedriver && 

Getting the unit tests to run in Chrome headless was a little tricky. In short, Docker doesn’t like Chrome headless too much unless you’re running your container in privileged mode. Assuming you’re not, we need to tell Karma (Angular’s unit test runner) to run ChromeHeadless with the–no-sandboxflag.

The easiest way I found was to add a customLauncher to your src/karma.conf.js as below:

customLaunchers: {
ChromeHeadless_without_sandox: {
base: ‘ChromeHeadless’,
flags: [‘–no-sandbox’]
}
},
browsers: [‘ChromeHeadless_without_sandox’]

Now can add lint and unit test step, as below:

# lint and unit test

FROM dev as test
RUN ng lint &&
ng test --watch=false

That’s it! Now you should be able to build, test and release inside Docker.

Here’s a full working example with unit testing:

module.exports = function(config) {
config.set({
customLaunchers: {
Chrome_without_sandox: {
base: ‘ChromeHeadless’,
flags: [‘–no-sandbox’]
}
},
browsers: [‘Chrome’]
});
};

Add custom launcher to karma.config.js

FROM nginx:alpine as env

RUN apk add --no-cache nodejs nodejs-npm bash chromium nss chromium-chromedriver &amp;&amp; \
    apk upgrade --no-cache --available &amp;&amp; \
    npm config set unsafe-perm true &amp;&amp; \
    npm install -g @angular/cli npm-snapshot &amp;&amp; \
    npm cache clean --force


ENV CHROME_BIN=/usr/bin/chromium-browser
ENV CHROME_DRIVER=/usr/bin/chromedriver


# build step
FROM env as dev
COPY . src
WORKDIR src
RUN   npm install &amp;&amp; \
      npm rebuild node-sass &amp;&amp; \
      ng build


# lint and unit test
FROM dev as test
RUN   ng lint &amp;&amp; \
      ng test --watch=false --browsers=Chrome_without_sandox


# release stage
FROM nginx:latest AS release
COPY --from=dev src/dist/ /usr/share/nginx/html/

Thank you for taking the time to read my article. If you liked this post, share it with all of your programming buddies!


#angular #angular-js #docker #javascript #web-development

Deploy an Angular app to Docker
2 Likes48.15 GEEK