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:
- Create an account on Dockerhub
- Create a repository for the frontend and backend (1 private repo is currently free)
- Build the images and tag them:
docker tag <image-id> dockerAccountName/frontend:latest docker tag <image-id> dockerAccountName/backend:latest
- 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.