DevOps
Docker Advanced
Advanced Docker concepts: multi-stage builds, Docker networks, volumes, security, and Docker Compose for multi-container applications.
By TechCoder TeamLast updated: 2026-06-02
In a Nutshell
Advanced Docker concepts: multi-stage builds, Docker networks, volumes, security, and Docker Compose for multi-container applications. This hands-on tutorial focuses on practical implementation of docker advanced concepts.
Docker Advanced
Building on Docker fundamentals, let's explore advanced concepts for production-grade containerization.
Advanced Dockerfile Techniques
Build Arguments and Variables
# Build arguments (passed at build time)
ARG NODE_VERSION=18
ARG APP_VERSION=1.0.0
FROM node:${NODE_VERSION}-alpine
# Labels with build info
LABEL maintainer="devops@example.com"
LABEL version="${APP_VERSION}"
LABEL build_date="${BUILD_DATE}"
# Environment variables (available at runtime)
ENV NODE_ENV=production
ENV APP_VERSION=${APP_VERSION}
ENV PORT=3000
WORKDIR /app
# Use ARG for conditional logic
ARG INSTALL_DEV=false
RUN if [ "$INSTALL_DEV" = "true" ]; then npm ci; else npm ci --only=production; fi
# Build with arguments
docker build --build-arg NODE_VERSION=20 --build-arg APP_VERSION=2.0.0 -t myapp:2.0 .
Advanced Multi-stage Patterns
# Dependencies stage - cache npm install
FROM node:18-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
# Build stage
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Development stage
FROM node:18-alpine AS development
WORKDIR /app
COPY /app/node_modules ./node_modules
COPY . .
CMD ["npm", "run", "dev"]
# Production stage
FROM node:18-alpine AS production
WORKDIR /app
ENV NODE_ENV=production
# Copy only necessary artifacts
COPY /app/node_modules ./node_modules
COPY /app/dist ./dist
COPY /app/package.json ./
# Security: Run as non-root
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001 && \
chown -R nodejs:nodejs /app
USER nodejs
EXPOSE 3000
CMD ["node", "dist/main.js"]
ONBUILD Triggers
# Base image with ONBUILD
FROM node:18-alpine AS base
WORKDIR /app
ONBUILD COPY package*.json ./
ONBUILD RUN npm ci --only=production
ONBUILD COPY . .
# Usage: FROM mybase
# Triggers execute when building the child image
Docker Security
Running as Non-Root
# Create non-root user
FROM node:18-alpine
RUN addgroup -g 1001 -S appgroup && \
adduser -u 1001 -S appuser -G appgroup
WORKDIR /app
COPY . .
USER appuser
EXPOSE 3000
CMD ["node", "server.js"]
# Run with security options
docker run --user 1000:1000 nginx
docker run --read-only --tmpfs /tmp --tmpfs /var/cache/nginx nginx
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE nginx
docker run --security-opt=no-new-privileges:true nginx
Content Trust and Signing
# Enable Docker Content Trust
export DOCKER_CONTENT_TRUST=1
# Sign images when pushing
docker trust sign registry.example.com/myapp:1.0
# View signatures
docker trust inspect registry.example.com/myapp:1.0
# Add signers
docker trust signer add --key signer.pub alice registry.example.com/myapp
Scanning for Vulnerabilities
# Docker Scout (Docker Desktop)
docker scout quickstart
docker scout cves myapp:latest
# Trivy
trivy image myapp:latest
# Snyk
docker scan myapp:latest
# Grype
grype myapp:latest
Docker Networks Deep Dive
Custom Network Drivers
# Bridge network (default)
docker network create --driver bridge my-bridge
# Overlay network (multi-host)
docker network create --driver overlay my-overlay
# Macvlan (direct MAC)
docker network create -d macvlan \
--subnet=192.168.1.0/24 \
--gateway=192.168.1.1 \
-o parent=eth0 my-macvlan
# IPvlan (L2/L3)
docker network create -d ipvlan \
--subnet=192.168.1.0/24 \
-o parent=eth0 my-ipvlan
Container DNS and Service Discovery
# Custom DNS
docker run --dns 8.8.8.8 --dns 8.8.4.4 nginx
# DNS search domain
docker run --dns-search example.com nginx
# Hosts file entries
docker run --add-host myhost:192.168.1.100 nginx
# Use container name as DNS
docker run --name web --network mynet nginx
docker run --name api --network mynet node # can ping 'web'
Network Troubleshooting
# Inspect network
docker network inspect bridge
# Container network info
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' container
# Execute network commands
docker exec container ping google.com
docker exec container nslookup api
docker exec container netstat -tlnp
# Packet capture
docker run --rm --net=container:target nicolaka/netshoot tcpdump -i eth0
Advanced Docker Compose
Profiles and Environment Overrides
# docker-compose.yml
version: '3.8'
services:
web:
build: ./web
ports:
- "80:80"
profiles:
- frontend
- full
api:
build: ./api
profiles:
- backend
- full
db:
image: postgres:15
profiles:
- backend
- full
test:
build:
context: ./api
target: test
profiles:
- test
command: npm test
# Start with profile
docker-compose --profile full up -d
docker-compose --profile test run --rm test
# docker-compose.override.yml (automatically merged)
version: '3.8'
services:
web:
volumes:
- ./web/src:/app/src # Hot reload in dev
environment:
- DEBUG=true
db:
ports:
- "5432:5432" # Expose for local access
# docker-compose.prod.yml
version: '3.8'
services:
web:
restart: always
deploy:
replicas: 3
resources:
limits:
cpus: '0.5'
memory: 512M
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
db:
volumes:
- db-data-prod:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
# Production deployment
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
Health Checks and Restart Policies
services:
app:
image: myapp:latest
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
start_interval: 5s
restart: unless-stopped
# Options: "no", "always", "on-failure", "unless-stopped"
Secrets and Configs
services:
api:
image: myapi:latest
secrets:
- source: api_key
target: /run/secrets/api_key
mode: 0400
- db_password
configs:
- source: app_config
target: /app/config.json
secrets:
api_key:
external: true # Created with docker secret create
db_password:
file: ./secrets/db_password.txt
configs:
app_config:
file: ./config/app.json
Docker Swarm (Orchestration)
Initialization and Services
# Initialize swarm
docker swarm init --advertise-addr 192.168.1.10
# Join as worker
docker swarm join --token SWMTKN-1-xxx 192.168.1.10:2377
# Create service
docker service create \
--name web \
--replicas 3 \
--publish 80:80 \
--mount type=volume,source=web-data,target=/data \
nginx
# Scale service
docker service scale web=5
# Update service (rolling update)
docker service update --image nginx:alpine web
# Rolling update with delay
docker service update \
--image myapp:2.0 \
--update-delay 10s \
--update-parallelism 1 \
--update-failure-action rollback \
myapp
Stack Deployment
# docker-stack.yml
version: '3.8'
services:
web:
image: nginx:alpine
ports:
- "80:80"
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 10s
failure_action: rollback
order: start-first
rollback_config:
parallelism: 1
delay: 10s
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
placement:
constraints:
- node.role == worker
preferences:
- spread: node.availability.zone
networks:
- frontend
- backend
api:
image: myapi:latest
deploy:
replicas: 2
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M
environment:
- DB_HOST=db
networks:
- backend
db:
image: postgres:15
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
volumes:
- type: volume
source: db-data
target: /var/lib/postgresql/data
networks:
- backend
deploy:
placement:
constraints:
- node.labels.storage == ssd
networks:
frontend:
driver: overlay
backend:
driver: overlay
internal: true
volumes:
db-data:
driver: rexray/ebs # AWS EBS
secrets:
db_password:
external: true
# Deploy stack
docker stack deploy -c docker-stack.yml myapp
# List services
docker stack ps myapp
docker service ls
# View logs
docker service logs myapp_web -f
# Remove stack
docker stack rm myapp
Production Deployment Patterns
Blue-Green with Docker
# Green deployment
docker-compose -f docker-compose.yml -f docker-compose.green.yml up -d
# Health check
curl -f http://green.example.com/health || exit 1
# Switch traffic (update load balancer or DNS)
# Rollback if needed:
docker-compose -f docker-compose.yml -f docker-compose.blue.yml up -d
Database Migrations
# docker-compose.yml
services:
migrate:
build:
context: ./api
target: migration
command: npx prisma migrate deploy
environment:
- DATABASE_URL=postgresql://user:pass@db:5432/mydb
depends_on:
db:
condition: service_healthy
restart: on-failure
deploy:
restart_policy:
max_attempts: 3
api:
build: ./api
depends_on:
migrate:
condition: service_completed_successfully
Quiz
Quiz
Question 1 of 5What is the purpose of Docker secrets?
To encrypt Docker images
To securely manage sensitive data like passwords and API keys
To lock Docker containers
To hide Dockerfiles from view
Next Steps
Now let's explore Kubernetes—the industry-standard container orchestration platform.