docker images

Create Docker images and upload them to Docker Hub

In this article, I will show you how to create production-ready Docker images for a web application with Angular, NestJS, MySQL and Redis and then publish them on Docker Hub. The prerequisite is an installed Docker environment.

You might also be interested in this: Hosting NestJS on Vercel

Creation of the Docker Compose Yml

With Docker Compose, all components of an application can be defined via a single configuration file and built or started together.

version: '3.8'

services:
  frontend:
    build: ./frontend
    ports:
      - "80:80"
    depends_on:
      - backend

  backend:
    build: ./backend
    ports:
      - "3000:3000"
    depends_on:
      - mysql
      - redis
    environment:
      - DATABASE_URL=mysql://user:password@mysql:3306/db
      - SESSION_STORE=redis://redis:6379

  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: db
    ports:
      - "3306:3306"

  redis:
    image: redis:latest
    ports:
      - "6379:6379"

Creating the env file

To manage environment variables centrally, we create an .env file:

DATABASE_URL=mysql://user:password@mysql:3306/db 
SESSION_STORE=redis://redis:6379

Important: All ENV variables used in the code must also appear in docker-compose.yml!

Docker image for the frontend

The Angular frontend must be built for production. Here is an example Dockerfile:

FROM node:20 AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install
COPY . .
RUN npm run build --prod

FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf

Since we are dependent on nginx for the build, we also need a corresponding config file:

server {
  listen 80;
  server_name _;

  location / {
    root /usr/share/nginx/html;
    index index.html;
    try_files $uri $uri/ /index.html;
  }
}

Docker image for the backend

The NestJS backend also needs to be built. Here is an optimized Dockerfile.

# Build stage
FROM node:20 AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install
COPY . .
RUN npm run build

# Production stage
FROM node:20-alpine
WORKDIR /app

COPY --from=build /app/dist ./dist
COPY package.json package-lock.json ./
RUN npm install --only=production
CMD ["node", "dist/main.js"]

Building the app with Docker Compose

Once all the Dockerfiles have been configured, the images can now be built. The whole thing is really easy with Docker compose.

docker compose up -d --build

The images are then ready, the containers are built and the app can be tested locally! The last step is to upload the images to DockerHub so that they can be used more easily later for deployment on a server.

Uploading to Docker Hub

Uploading is explained step by step below:

  1. Create an account on Dockerhub
  2. Create a repository for the frontend and backend (1 private repo is currently free)
  3. Build the images and tag them:
    docker tag <image-id> dockerAccountName/frontend:latest
    docker tag <image-id> dockerAccountName/backend:latest
  4. Sign up and push the images:
    docker login
    docker push dockerAccountName/frontend:latest
    docker push dockerAccountName/backend:latest

Outlook: Deployment with Kubernetes

Now that the images are on Docker Hub, nothing stands in the way of deployment. I have opted for a Kubernetes cluster on a Hetzner VPS. More information here.

Leave a Reply

Your email address will not be published. Required fields are marked *


Cookie Consent with Real Cookie Banner