We will be using:

Docker version 19.03.1, build 74b1e89

docker-compose version 1.24.1, build 4667896b

MacOS

Contents

Project Setup

Create a new folder for angular application:

$ mkdir myApp

Create a docker compose file:

$ touch docker-compose.yml

Add the following yml configuration to docker-compose file. We will use an open-source angular CLI docker image for the creation and running of the new angular application:

version: '3'

services:

angular_cli:

image: trion/ng-cli:latest

container_name: 'angular_cli'

volumes:

- .:/usr/app/

working_dir: /usr/app/

command: >

bash -c "ng new myApp --directory ./"

command key in configuration has the command which will run after container starts. In this case, it will create a new project via Angular CLI.

Start the container via the following command.

$ docker-compose up

By completing this step, we created a new angular project with hot reloading feature enabled on our local environment. This may take 2–3 minutes to complete. Next tap, we will add testing services and spin up all the services together.

Setting up a Karma and Protractor Containers

Since the project has already been created, we need to make little changes on existing service in docker compose file. This time we don't want the command to create a new project, we just want to run it in the container. Also, we need to publish related ports to be able to access it through the browser. Which will look like this:

version: '3'

services:

angular_cli:

image: trion/ng-cli:latest

container_name: 'angular_cli'

volumes:

- .:/usr/app/

working_dir: /usr/app/

ports:

- 4200:4200

command: >

bash -c "npm install && ng serve --host 0.0.0.0"

We need to add two more services in our docker-compose.yml file. One is going to be Karma. For this, we will use ng-cli-karma image which has build-in chromium.

You will be able to access it through your browser and ‘auto running tests on change' feature is already enabled. Add the following code block to your docker-compose file. Be careful about the indentation of the service name.

angular_karma:

image: trion/ng-cli-karma:latest

container_name: 'angular_karma'

volumes:

- .:/usr/app/

working_dir: /usr/app/

ports:

- 9876:9876

command: >

bash -c "ng test"

When this service starts, it will be kept on running and watching file changes on our tests files. You can access Karma UI by visiting http://localhost:9876/

Next tap, we will add another image for running e2e tests via Protractor in the docker container. Add the following code block to docker-compose.yml file.

angular_e2e:

image: trion/ng-cli-e2e:latest

container_name: "angular_e2e"

volumes:

- .:/usr/app/

working_dir: /usr/app/

command: >

bash -c "ng e2e"

Once the end-to-end test container runs and finishes the tests, it will stop.

Finally, we can run containers on our local machine. We can run all containers at once like this with logs:

$ docker-compose up

Or we can run individual service from our docker-compose.yml file like this:

$ docker-compose up angular_cli angular_karma angular_e2e

Production Build

Usually, the configuration of the production docker is different from the development docker. So, the best way to isolate and the easiest way to archive this is to create new Dockerfile in the project root:

$ touch Dockerfile

This time, we don’t want Angular CLI capabilities and other tools for improving the developer experience. We just want to ship the project lightweight and as performant as possible to the production.

We will archive this in two steps:

Build: Build the app using Node alpine image

Serve: By using artefacts after build process and Nginx configs, we will serve the app.

Add the following configuration to Dockerfile which you just created:

### STAGE 1: Build ### # We label our stage as ‘builder’

FROM node:alpine as builder COPY package.json package-lock.json ./ ## Storing node modules on a separate layer will prevent unnecessary npm installs at each build RUN npm ci && mkdir /ng-app && mv ./node_modules ./ng-app WORKDIR /ng-app COPY . . ## Build the angular app in production mode and store the artifacts in dist folder RUN npm run ng build -- --prod --output-path=dist ### STAGE 2: Setup ### FROM nginx:alpine ## Copy our default nginx config

COPY nginx/default.conf /etc/nginx/conf.d/ ## Remove default nginx website

RUN rm -rf /usr/share/nginx/html/* ## From ‘builder’ stage copy over the artifacts in dist folder to default nginx public folder

COPY --from=builder /ng-app/dist /usr/share/nginx/html CMD ["nginx", "-g", "daemon off;"]

Then, you can build our production image like this:

$ docker build -t myapp:prod .

To test it out, you can run that image with the following command and visit http://localhost:8080/ :

$ docker run -p 8080:80 myapp:prod

The size of this app is a lot smaller then the development images, in this case it is ~21.6 MB

You can see the entire example on github: https://github.com/ersah123/angular-docker-karma-protractor

Cheers!