How to Containerize Applications

Containerization Steps

  1. Create Dockerfile
  2. Build image
  3. Test locally
  4. Push to registry
  5. Deploy to production

Angular Application

# Multi-stage build
FROM node:18-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build --configuration production

FROM nginx:alpine
COPY --from=build /app/dist/my-app /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
# nginx.conf
server {
    listen 80;
    location / {
        root /usr/share/nginx/html;
        try_files $uri $uri/ /index.html;
    }
}

.NET Application

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["MyApp.csproj", "./"]
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app/publish

FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY --from=build /app/publish .
EXPOSE 80
EXPOSE 443
ENTRYPOINT ["dotnet", "MyApp.dll"]

Node.js Application

FROM node:18-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build

FROM node:18-alpine
WORKDIR /app
COPY --from=build /app/dist ./dist
COPY --from=build /app/node_modules ./node_modules
COPY package*.json ./

USER node
EXPOSE 3000
CMD ["node", "dist/index.js"]

Database Containers

PostgreSQL

FROM postgres:15
ENV POSTGRES_DB=myapp
ENV POSTGRES_USER=admin
COPY init.sql /docker-entrypoint-initdb.d/
EXPOSE 5432

MongoDB

FROM mongo:6
ENV MONGO_INITDB_DATABASE=myapp
COPY mongo-init.js /docker-entrypoint-initdb.d/
EXPOSE 27017

Docker Compose

version: '3.8'

services:
  # Angular Frontend
  frontend:
    build:
      context: ./frontend
      dockerfile: Dockerfile
    ports:
      - "4200:80"
    depends_on:
      - api
    environment:
      - API_URL=http://api:5000
  
  # .NET API
  api:
    build:
      context: ./api
      dockerfile: Dockerfile
    ports:
      - "5000:80"
    depends_on:
      - postgres
      - redis
    environment:
      - ConnectionStrings__DefaultConnection=Server=postgres;Database=myapp;User=admin;Password=password
      - Redis__ConnectionString=redis:6379
  
  # Node.js Service
  service:
    build:
      context: ./service
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    depends_on:
      - mongodb
      - redis
    environment:
      - MONGODB_URL=mongodb://mongodb:27017/myapp
      - REDIS_URL=redis://redis:6379
  
  # PostgreSQL
  postgres:
    image: postgres:15
    environment:
      - POSTGRES_DB=myapp
      - POSTGRES_USER=admin
      - POSTGRES_PASSWORD=password
    volumes:
      - postgres-data:/var/lib/postgresql/data
    ports:
      - "5432:5432"
  
  # MongoDB
  mongodb:
    image: mongo:6
    volumes:
      - mongo-data:/data/db
    ports:
      - "27017:27017"
  
  # Redis
  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"

volumes:
  postgres-data:
  mongo-data:

Build and Run

# Build images
docker-compose build

# Start all services
docker-compose up -d

# View logs
docker-compose logs -f

# Stop services
docker-compose down

# Remove volumes
docker-compose down -v

Best Practices

1. Use .dockerignore

node_modules
.git
.env
*.log
dist
coverage
.angular

2. Multi-stage Builds

# Build stage
FROM node:18 AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Production stage
FROM node:18-alpine
WORKDIR /app
COPY --from=build /app/dist ./dist
COPY --from=build /app/node_modules ./node_modules
CMD ["node", "dist/index.js"]

3. Security

# Don't run as root
FROM node:18-alpine
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nodejs -u 1001
USER nodejs

# Use specific versions
FROM node:18.17.0-alpine

# Scan for vulnerabilities
RUN npm audit

4. Health Checks

HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD node healthcheck.js || exit 1

CI/CD Integration

# GitHub Actions
name: Build and Push Docker

on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Login to Docker Hub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}
      
      - name: Build and push
        uses: docker/build-push-action@v4
        with:
          context: .
          push: true
          tags: |
            myapp:${{ github.sha }}
            myapp:latest

Interview Tips

  • Explain containerization: Package app with dependencies
  • Show Dockerfile: Multi-stage builds
  • Demonstrate Docker Compose: Multi-container setup
  • Discuss best practices: Security, multi-stage, .dockerignore
  • Mention databases: PostgreSQL, MongoDB, Redis
  • Show CI/CD: Automated builds and pushes

Summary

Containerization packages applications with dependencies for consistent deployment. Use multi-stage Dockerfiles for optimized images. Docker Compose orchestrates multi-container applications. Implement security best practices. Integrate with CI/CD for automated builds. Supports all tech stacks and databases.

Test Your Knowledge

Take a quick quiz to test your understanding of this topic.

Test Your Cicd Knowledge

Ready to put your skills to the test? Take our interactive Cicd quiz and get instant feedback on your answers.