Docker Guide
This guide explains the Docker setup for the Clean Architecture Full-Stack application. It covers all Dockerfiles, docker-compose configurations, and environment variables.
Table of Contents
Overview
The application uses Docker to containerize all services for consistent development and deployment. The Docker setup includes:
- Frontend container (Angular 19)
- Backend API container (.NET 9)
- Database container (PostgreSQL)
- Nginx container (Reverse proxy)
Dockerfiles
Frontend Dockerfile
Located at frontend/Dockerfile
, this file builds the Angular application:
# Build stage
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Production stage
FROM nginx:alpine
COPY --from=build /app/dist/browser /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
This is a multi-stage build that:
- Uses Node.js to build the Angular application
- Copies the built files to an Nginx container
- Uses a custom Nginx configuration
- Exposes port 80
Backend Dockerfile
Located at backend/src/Dockerfile
, this file builds the .NET API:
# Build stage
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
WORKDIR /src
COPY ["Contact.Api/Contact.Api.csproj", "Contact.Api/"]
COPY ["Contact.Application/Contact.Application.csproj", "Contact.Application/"]
COPY ["Contact.Domain/Contact.Domain.csproj", "Contact.Domain/"]
COPY ["Contact.Infrastructure/Contact.Infrastructure.csproj", "Contact.Infrastructure/"]
RUN dotnet restore "Contact.Api/Contact.Api.csproj"
COPY . .
WORKDIR "/src/Contact.Api"
RUN dotnet build "Contact.Api.csproj" -c Release -o /app/build
# Publish stage
FROM build AS publish
RUN dotnet publish "Contact.Api.csproj" -c Release -o /app/publish
# Final stage
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Contact.Api.dll"]
This uses a multi-stage build to:
- Restore NuGet packages
- Build the .NET application
- Publish the application
- Create a lightweight runtime image
Nginx Dockerfile
Located at loadbalancer/Dockerfile
, this serves as the entry point for all requests:
FROM nginx:alpine
COPY nginx.conf /etc/nginx/conf.d/default.conf
This simple Dockerfile:
- Uses the official Nginx Alpine image
- Replaces the default configuration with our custom one
Docker Compose Configuration
The primary docker-compose file is docker-compose.yml
:
version: '3.8'
services:
frontend:
build:
context: ./frontend
dockerfile: Dockerfile
container_name: contact-frontend
restart: always
depends_on:
- api
networks:
- contact-network
api:
build:
context: ./backend/src
dockerfile: Dockerfile
container_name: contact-api
restart: always
depends_on:
- postgres
environment:
- ASPNETCORE_ENVIRONMENT=Production
- ConnectionStrings__DefaultConnection=${POSTGRES_CONNECTION_STRING}
- JwtSettings__SecretKey=${JWT_SECRET_KEY}
- JwtSettings__Issuer=${JWT_ISSUER}
- JwtSettings__Audience=${JWT_AUDIENCE}
- JwtSettings__ExpiryMinutes=${JWT_EXPIRY_MINUTES}
networks:
- contact-network
postgres:
image: postgres:16-alpine
container_name: contact-postgres
restart: always
environment:
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=${POSTGRES_DB}
volumes:
- postgres-data:/var/lib/postgresql/data
- ./backend/db/init.sql:/docker-entrypoint-initdb.d/init.sql
networks:
- contact-network
nginx:
build:
context: ./loadbalancer
dockerfile: Dockerfile
container_name: contact-nginx
restart: always
ports:
- "80:80"
depends_on:
- frontend
- api
networks:
- contact-network
networks:
contact-network:
driver: bridge
volumes:
postgres-data:
This configuration:
- Defines all four services (frontend, api, postgres, nginx)
- Establishes service dependencies
- Sets environment variables from the
.env
file - Configures networking
- Creates a persistent volume for PostgreSQL data
Environment Variables (.env file)
The application uses a .env
file (copied from .env.example
) to configure various settings. Here’s an explanation of each variable: