Docker and Kubernetes for Frontend Developers
1/12/2024
15 min read
Tridip Dutta
DevOps

Docker and Kubernetes for Frontend Developers

Learn containerization and orchestration concepts specifically tailored for frontend developers, including deployment strategies and best practices.

Docker
Kubernetes
DevOps
Deployment

Docker and Kubernetes for Frontend Developers

As a frontend developer, you might think Docker and Kubernetes are backend concerns. However, understanding containerization and orchestration can significantly improve your development workflow, deployment process, and collaboration with DevOps teams. This guide covers everything you need to know about Docker and Kubernetes from a frontend perspective.

Why Frontend Developers Should Care About Docker

Problems Docker Solves for Frontend:

  1. "It works on my machine" syndrome
  2. Environment consistency across development, staging, and production
  3. Simplified deployment processes
  4. Easier collaboration with backend teams
  5. Reproducible builds and testing environments

Docker Fundamentals

What is Docker?

Docker is a containerization platform that packages your application and its dependencies into lightweight, portable containers.

Key Concepts:

  • Image: A blueprint for creating containers
  • Container: A running instance of an image
  • Dockerfile: Instructions for building an image
  • Registry: A repository for storing images (Docker Hub, etc.)

Dockerizing a React Application

Basic Dockerfile for React App:

# Use official Node.js runtime as base image
FROM node:18-alpine

# Set working directory in container
WORKDIR /app

# Copy package files
COPY package*.json ./

# Install dependencies
RUN npm ci --only=production

# Copy source code
COPY . .

# Build the application
RUN npm run build

# Install serve to run the application
RUN npm install -g serve

# Expose port 3000
EXPOSE 3000

# Command to run the application
CMD ["serve", "-s", "build", "-l", "3000"]

Multi-stage Build for Optimization:

# Build stage
FROM node:18-alpine AS builder

WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Production stage
FROM nginx:alpine

# Copy built assets from builder stage
COPY --from=builder /app/build /usr/share/nginx/html

# Copy custom nginx config (optional)
COPY nginx.conf /etc/nginx/nginx.conf

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]

Custom Nginx Configuration:

# nginx.conf
events {
    worker_connections 1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    server {
        listen 80;
        server_name localhost;
        root /usr/share/nginx/html;
        index index.html;

        # Handle client-side routing
        location / {
            try_files $uri $uri/ /index.html;
        }

        # Cache static assets
        location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
            expires 1y;
            add_header Cache-Control "public, immutable";
        }

        # Security headers
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-Content-Type-Options "nosniff" always;
        add_header X-XSS-Protection "1; mode=block" always;
    }
}

Docker Commands for Frontend Development

Building and Running:

# Build image
docker build -t my-react-app .

# Run container
docker run -p 3000:3000 my-react-app

# Run with volume mounting for development
docker run -p 3000:3000 -v $(pwd):/app my-react-app

# Run in background
docker run -d -p 3000:3000 my-react-app

Development with Docker Compose:

# docker-compose.yml
version: '3.8'

services:
  frontend:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - .:/app
      - /app/node_modules
    environment:
      - NODE_ENV=development
    command: npm start

  backend:
    image: my-backend-api
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=postgresql://user:pass@db:5432/myapp

  db:
    image: postgres:13
    environment:
      - POSTGRES_DB=myapp
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=pass
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:
# Start all services
docker-compose up

# Start in background
docker-compose up -d

# Stop services
docker-compose down

Introduction to Kubernetes

What is Kubernetes?

Kubernetes (K8s) is a container orchestration platform that automates deployment, scaling, and management of containerized applications.

Key Kubernetes Concepts:

  • Pod: Smallest deployable unit (usually one container)
  • Deployment: Manages replica sets and rolling updates
  • Service: Exposes pods to network traffic
  • Ingress: Manages external access to services
  • ConfigMap: Stores configuration data
  • Secret: Stores sensitive data

Kubernetes for Frontend Applications

Basic Deployment Configuration:

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: react-app
  labels:
    app: react-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: react-app
  template:
    metadata:
      labels:
        app: react-app
    spec:
      containers:
      - name: react-app
        image: my-react-app:latest
        ports:
        - containerPort: 80
        resources:
          requests:
            memory: "64Mi"
            cpu: "250m"
          limits:
            memory: "128Mi"
            cpu: "500m"

Service Configuration:

# service.yaml
apiVersion: v1
kind: Service
metadata:
  name: react-app-service
spec:
  selector:
    app: react-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: ClusterIP

Ingress Configuration:

# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: react-app-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: myapp.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: react-app-service
            port:
              number: 80

Environment-Specific Configurations

ConfigMap for Environment Variables:

# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: react-app-config
data:
  REACT_APP_API_URL: "https://api.example.com"
  REACT_APP_ENVIRONMENT: "production"
  REACT_APP_VERSION: "1.0.0"

Using ConfigMap in Deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: react-app
spec:
  template:
    spec:
      containers:
      - name: react-app
        image: my-react-app:latest
        envFrom:
        - configMapRef:
            name: react-app-config

CI/CD Pipeline with Docker and Kubernetes

GitHub Actions Example:

# .github/workflows/deploy.yml
name: Build and Deploy

on:
  push:
    branches: [main]

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v2
    
    - name: Build Docker image
      run: |
        docker build -t my-react-app:${{ github.sha }} .
        docker tag my-react-app:${{ github.sha }} my-react-app:latest
    
    - name: Push to registry
      run: |
        echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
        docker push my-react-app:${{ github.sha }}
        docker push my-react-app:latest
    
    - name: Deploy to Kubernetes
      run: |
        echo "${{ secrets.KUBE_CONFIG }}" | base64 -d > kubeconfig
        export KUBECONFIG=kubeconfig
        kubectl set image deployment/react-app react-app=my-react-app:${{ github.sha }}
        kubectl rollout status deployment/react-app

Development Workflow Best Practices

1. Local Development with Docker:

# Dockerfile.dev
FROM node:18-alpine

WORKDIR /app
COPY package*.json ./
RUN npm install

COPY . .

EXPOSE 3000

CMD ["npm", "start"]

2. Hot Reloading Setup:

# docker-compose.dev.yml
version: '3.8'

services:
  frontend:
    build:
      context: .
      dockerfile: Dockerfile.dev
    ports:
      - "3000:3000"
    volumes:
      - .:/app
      - /app/node_modules
    environment:
      - CHOKIDAR_USEPOLLING=true

3. Testing in Containers:

# Dockerfile.test
FROM node:18-alpine

WORKDIR /app
COPY package*.json ./
RUN npm ci

COPY . .

CMD ["npm", "test"]

Monitoring and Debugging

Kubernetes Debugging Commands:

# Get pod status
kubectl get pods

# Describe pod details
kubectl describe pod <pod-name>

# View pod logs
kubectl logs <pod-name>

# Execute commands in pod
kubectl exec -it <pod-name> -- /bin/sh

# Port forward for local access
kubectl port-forward pod/<pod-name> 3000:80

Health Checks:

apiVersion: apps/v1
kind: Deployment
spec:
  template:
    spec:
      containers:
      - name: react-app
        image: my-react-app:latest
        livenessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 5
          periodSeconds: 5

Security Best Practices

1. Non-root User in Docker:

FROM node:18-alpine

# Create non-root user
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001

WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

COPY . .
RUN npm run build

# Change ownership to non-root user
RUN chown -R nextjs:nodejs /app
USER nextjs

EXPOSE 3000
CMD ["npm", "start"]

2. Kubernetes Security Context:

apiVersion: apps/v1
kind: Deployment
spec:
  template:
    spec:
      securityContext:
        runAsNonRoot: true
        runAsUser: 1001
        fsGroup: 1001
      containers:
      - name: react-app
        securityContext:
          allowPrivilegeEscalation: false
          readOnlyRootFilesystem: true
          capabilities:
            drop:
            - ALL

Common Pitfalls and Solutions

1. Large Image Sizes:

# Use multi-stage builds
FROM node:18-alpine AS builder
# ... build steps

FROM nginx:alpine
COPY --from=builder /app/build /usr/share/nginx/html
# Final image only contains built assets

2. Environment Variable Handling:

# Build-time variables
docker build --build-arg REACT_APP_API_URL=https://api.prod.com .

# Runtime variables (for server-side rendering)
docker run -e REACT_APP_API_URL=https://api.prod.com my-app

3. Caching Dependencies:

# Copy package files first for better caching
COPY package*.json ./
RUN npm ci

# Copy source code after dependencies
COPY . .

Conclusion

Docker and Kubernetes provide powerful tools for frontend developers to create consistent, scalable, and maintainable deployment pipelines. Start with basic Docker containerization, then gradually adopt Kubernetes for orchestration as your applications grow in complexity.

The investment in learning these tools pays off through improved development workflows, easier collaboration with DevOps teams, and more reliable deployments.

Resources


Containerization and orchestration are no longer just backend concerns. Frontend developers who understand these tools are better equipped to build and deploy modern web applications.

TD

About Tridip Dutta

Creative Developer passionate about creating innovative digital experiences and exploring AI. I love sharing knowledge to help developers build better apps.