
Docker Containerization
- 1k installs
- 432 repo stars
- Updated November 11, 2025
- ailabs-393/ai-labs-claude-skills
Docker Containerization is an agent skill that containerizes Next.js applications with separate development and production environments using Docker Compose, Dockerfiles, and a tailored .dockerignore.
About
Docker Containerization is an AI Labs Claude skill for packaging Next.js apps with distinct development and production Docker setups. It generates Dockerfile.development, production Dockerfiles, docker-compose.yml using Compose file format 3.8, and a .dockerignore that excludes node_modules, .next, env files, IDE folders, and CI configs from build context. Developers reach for Docker Containerization when they need reproducible local dev containers and production-ready images without hand-writing every Compose service block. The skill targets Next.js-specific build output paths such as .next, out, and dist.
- Multi-stage Docker setup with dedicated development and production services
- Volume mounting for live reload during development while excluding node_modules
- Healthcheck configured on production service with HTTP endpoint monitoring
- Isolated networking via custom app-network with restart policies
- Environment-specific Dockerfiles referenced for dev versus prod builds
Docker Containerization by the numbers
- 1,002 all-time installs (skills.sh)
- +24 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #182 of 1,438 DevOps & CI/CD skills by installs in the Skillselion catalog
- Security screen: HIGH risk (skills.sh audit)
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/ailabs-393/ai-labs-claude-skills --skill docker-containerizationAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1k |
|---|---|
| repo stars | ★ 432 |
| Security audit | 2 / 3 scanners passed |
| Last updated | November 11, 2025 |
| Repository | ailabs-393/ai-labs-claude-skills ↗ |
How do you dockerize a Next.js app for dev and prod?
Containerize Next.js applications with separate development and production environments using Docker Compose.
Who is it for?
Developers shipping Next.js apps who need separate Docker development and production environments with Compose orchestration.
Skip if: Teams on serverless-only Vercel deploys without containers should skip Docker Containerization.
When should I use this skill?
A developer asks to dockerize Next.js, add Docker Compose dev and prod services, or generate Dockerfiles for a Next app.
What you get
Dockerfile.development, production Dockerfile, docker-compose.yml, and .dockerignore for Next.js services.
- Dockerfile.development
- docker-compose.yml
- .dockerignore
By the numbers
- Uses Docker Compose file format version 3.8
- Defines separate app-dev and production Compose services
Files
Docker Containerization Skill
Overview
Generate production-ready Docker configurations for modern web applications, particularly Next.js and Node.js projects. This skill provides Dockerfiles, docker-compose setups, bash scripts for container management, and comprehensive deployment guides for various orchestration platforms.
Core Capabilities
1. Dockerfile Generation
Create optimized Dockerfiles for different environments:
Production (assets/Dockerfile.production):
- Multi-stage build reducing image size by 85%
- Alpine Linux base (~180MB final image)
- Non-root user execution for security
- Health checks and resource limits
Development (assets/Dockerfile.development):
- Hot reload support
- All dev dependencies included
- Volume mounts for live code updates
Nginx Static (assets/Dockerfile.nginx):
- Static export optimization
- Nginx reverse proxy included
- Smallest possible footprint
2. Docker Compose Configuration
Multi-container orchestration with assets/docker-compose.yml:
- Development and production services
- Network and volume management
- Health checks and logging
- Restart policies
3. Bash Scripts for Container Management
docker-build.sh - Build images with comprehensive options:
./docker-build.sh -e prod -t v1.0.0
./docker-build.sh -n my-app --no-cache --platform linux/amd64docker-run.sh - Run containers with full configuration:
./docker-run.sh -i my-app -t v1.0.0 -d
./docker-run.sh -p 8080:3000 --env-file .env.productiondocker-push.sh - Push to registries (Docker Hub, ECR, GCR, ACR):
./docker-push.sh -n my-app -t v1.0.0 --repo username/my-app
./docker-push.sh -r gcr.io/project --repo my-app --also-tag stabledocker-cleanup.sh - Free disk space:
./docker-cleanup.sh --all --dry-run # Preview cleanup
./docker-cleanup.sh --containers --images # Clean specific resources4. Configuration Files
- `.dockerignore`: Excludes unnecessary files (node_modules, .git, logs)
- `nginx.conf`: Production-ready Nginx configuration with compression, caching, security headers
5. Reference Documentation
docker-best-practices.md covers:
- Multi-stage builds explained
- Image optimization techniques (50-85% size reduction)
- Security best practices (non-root users, vulnerability scanning)
- Performance optimization
- Health checks and logging
- Troubleshooting guide
container-orchestration.md covers deployment to:
- Docker Compose (local development)
- Kubernetes (enterprise scale with auto-scaling)
- Amazon ECS (AWS-native orchestration)
- Google Cloud Run (serverless containers)
- Azure Container Instances
- Digital Ocean App Platform
Includes configuration examples, commands, auto-scaling setup, and monitoring.
Workflow Decision Tree
1. What environment?
- Development →
Dockerfile.development(hot reload, all dependencies) - Production →
Dockerfile.production(minimal, secure, optimized) - Static Export →
Dockerfile.nginx(smallest footprint)
2. Single or Multi-container?
- Single → Generate Dockerfile only
- Multi → Generate
docker-compose.yml(app + database, microservices)
3. Which registry?
- Docker Hub →
docker.io/username/image - AWS ECR →
123456789012.dkr.ecr.region.amazonaws.com/image - Google GCR →
gcr.io/project-id/image - Azure ACR →
registry.azurecr.io/image
4. Deployment platform?
- Kubernetes → See
references/container-orchestration.mdK8s section - ECS → See ECS task definition examples
- Cloud Run → See deployment commands
- Docker Compose → Use provided compose file
5. Optimizations needed?
- Image size → Multi-stage builds, Alpine base
- Build speed → Layer caching, BuildKit
- Security → Non-root user, vulnerability scanning
- Performance → Resource limits, health checks
Usage Examples
Example 1: Containerize Next.js App for Production
User: "Containerize my Next.js app for production"
Steps: 1. Copy assets/Dockerfile.production to project root as Dockerfile 2. Copy assets/.dockerignore to project root 3. Build: ./docker-build.sh -e prod -n my-app -t v1.0.0 4. Test: ./docker-run.sh -i my-app -t v1.0.0 -p 3000:3000 -d 5. Push: ./docker-push.sh -n my-app -t v1.0.0 --repo username/my-app
Example 2: Development with Docker Compose
User: "Set up Docker Compose for local development"
Steps: 1. Copy assets/Dockerfile.development and assets/docker-compose.yml to project 2. Customize services in docker-compose.yml 3. Start: docker-compose up -d 4. Logs: docker-compose logs -f app-dev
Example 3: Deploy to Kubernetes
User: "Deploy my containerized app to Kubernetes"
Steps: 1. Build and push image to registry 2. Review references/container-orchestration.md Kubernetes section 3. Create K8s manifests (deployment, service, ingress) 4. Apply: kubectl apply -f deployment.yaml 5. Verify: kubectl get pods && kubectl logs -f deployment/app
Example 4: Deploy to AWS ECS
User: "Deploy to AWS ECS Fargate"
Steps: 1. Build and push to ECR 2. Review references/container-orchestration.md ECS section 3. Create task definition JSON 4. Register: aws ecs register-task-definition --cli-input-json file://task-def.json 5. Create service: aws ecs create-service --cluster my-cluster --service-name app --desired-count 3
Best Practices
Security
✅ Use multi-stage builds for production ✅ Run as non-root user ✅ Use specific image tags (not latest) ✅ Scan for vulnerabilities ✅ Never hardcode secrets ✅ Implement health checks
Performance
✅ Optimize layer caching order ✅ Use Alpine images (~85% smaller) ✅ Enable BuildKit for parallel builds ✅ Set resource limits ✅ Use compression
Maintainability
✅ Add comments for complex steps ✅ Use build arguments for flexibility ✅ Keep Dockerfiles DRY ✅ Version control all configs ✅ Document environment variables
Troubleshooting
Image too large (>500MB) → Use multi-stage builds, Alpine base, comprehensive .dockerignore
Build is slow → Optimize layer caching, use BuildKit, review dependencies
Container exits immediately → Check logs: docker logs container-name → Verify CMD/ENTRYPOINT, check port conflicts
Changes not reflecting → Rebuild without cache, check .dockerignore, verify volume mounts
Quick Reference
# Build
./docker-build.sh -e prod -t latest
# Run
./docker-run.sh -i app -t latest -d
# Logs
docker logs -f app
# Execute
docker exec -it app sh
# Cleanup
./docker-cleanup.sh --all --dry-run # Preview
./docker-cleanup.sh --all # ExecuteIntegration with CI/CD
GitHub Actions
- run: |
chmod +x docker-build.sh docker-push.sh
./docker-build.sh -e prod -t ${{ github.sha }}
./docker-push.sh -n app -t ${{ github.sha }} --repo username/appGitLab CI
build:
script:
- chmod +x docker-build.sh
- ./docker-build.sh -e prod -t $CI_COMMIT_SHAResources
Scripts (scripts/)
Production-ready bash scripts with comprehensive features:
docker-build.sh- Build images (400+ lines, colorized output)docker-run.sh- Run containers (400+ lines, auto conflict resolution)docker-push.sh- Push to registries (multi-registry support)docker-cleanup.sh- Clean resources (dry-run mode, selective cleanup)
References (references/)
Detailed documentation loaded as needed:
docker-best-practices.md- Comprehensive Docker best practices (~500 lines)container-orchestration.md- Deployment guides for 6+ platforms (~600 lines)
Assets (assets/)
Ready-to-use templates:
Dockerfile.production- Multi-stage production DockerfileDockerfile.development- Development DockerfileDockerfile.nginx- Static export with Nginxdocker-compose.yml- Multi-container orchestration.dockerignore- Optimized exclusion rulesnginx.conf- Production Nginx configuration
# Dependencies
node_modules
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# Testing
coverage
*.lcov
.nyc_output
# Next.js
.next/
out/
build
dist
# Production
.vercel
.netlify
# Misc
.DS_Store
*.pem
.env*.local
.env.development
.env.test
.env.production
# Debug
logs
*.log
# Git
.git
.gitignore
.gitattributes
# IDE
.vscode
.idea
*.swp
*.swo
*~
# Documentation
README.md
docs/
*.md
# CI/CD
.github/
.gitlab-ci.yml
.circleci/
# Docker
Dockerfile*
docker-compose*.yml
.dockerignore
# Temporary files
tmp/
temp/
version: '3.8'
services:
# Next.js Application - Development
app-dev:
build:
context: .
dockerfile: Dockerfile.development
container_name: nextjs-app-dev
ports:
- "3000:3000"
volumes:
- .:/app
- /app/node_modules
- /app/.next
environment:
- NODE_ENV=development
- PORT=3000
networks:
- app-network
restart: unless-stopped
# Next.js Application - Production
app-prod:
build:
context: .
dockerfile: Dockerfile.production
container_name: nextjs-app-prod
ports:
- "3001:3000"
environment:
- NODE_ENV=production
- PORT=3000
networks:
- app-network
restart: unless-stopped
healthcheck:
test: ["CMD", "node", "-e", "require('http').get('http://localhost:3000/api/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"]
interval: 30s
timeout: 3s
retries: 3
start_period: 10s
# Nginx Reverse Proxy (optional)
nginx:
image: nginx:alpine
container_name: nginx-proxy
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
- ./ssl:/etc/nginx/ssl:ro
depends_on:
- app-prod
networks:
- app-network
restart: unless-stopped
networks:
app-network:
driver: bridge
# Dockerfile for Next.js Development
# Optimized for fast rebuilds and hot reloading
FROM node:18-alpine
LABEL maintainer="your-email@example.com"
LABEL description="Next.js Application - Development"
# Install dependencies for native modules
RUN apk add --no-cache libc6-compat python3 make g++
WORKDIR /app
# Copy package files
COPY package.json package-lock.json* ./
# Install all dependencies (including devDependencies)
RUN npm install && \
npm cache clean --force
# Copy application source
COPY . .
# Expose port for dev server
EXPOSE 3000
ENV PORT=3000
ENV NODE_ENV=development
# Start development server with hot reload
CMD ["npm", "run", "dev"]
# Multi-stage Dockerfile for Next.js with Nginx
# For static export deployment with Nginx reverse proxy
# Stage 1: Build the Next.js application
FROM node:18-alpine AS builder
WORKDIR /app
# Copy package files
COPY package.json package-lock.json* ./
# Install dependencies
RUN npm ci && npm cache clean --force
# Copy application source
COPY . .
# Build static export
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
RUN npm run build
# Stage 2: Nginx server
FROM nginx:alpine AS runner
LABEL maintainer="your-email@example.com"
LABEL description="Next.js Application - Nginx Static"
# Copy built files from builder
COPY --from=builder /app/out /usr/share/nginx/html
# Copy nginx configuration
COPY nginx.conf /etc/nginx/conf.d/default.conf
# Expose port
EXPOSE 80
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --quiet --tries=1 --spider http://localhost:80/ || exit 1
# Start nginx
CMD ["nginx", "-g", "daemon off;"]
# Multi-stage Dockerfile for Next.js Production
# Optimized for minimal image size and security
# Stage 1: Dependencies
FROM node:18-alpine AS deps
LABEL stage=deps
# Install dependencies only when needed
RUN apk add --no-cache libc6-compat
WORKDIR /app
# Copy package files
COPY package.json package-lock.json* ./
# Install dependencies with clean install
RUN npm ci --only=production && \
npm cache clean --force
# Stage 2: Builder
FROM node:18-alpine AS builder
LABEL stage=builder
WORKDIR /app
# Copy dependencies from deps stage
COPY --from=deps /app/node_modules ./node_modules
# Copy application source
COPY . .
# Set environment variables for build
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
# Build the application
RUN npm run build
# Stage 3: Runner (Production)
FROM node:18-alpine AS runner
LABEL maintainer="your-email@example.com"
LABEL description="Next.js Application - Production"
WORKDIR /app
# Don't run production as root
RUN addgroup --system --gid 1001 nodejs && \
adduser --system --uid 1001 nextjs
# Set environment
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
# Copy necessary files from builder
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
# Change ownership to nextjs user
RUN chown -R nextjs:nodejs /app
# Switch to non-root user
USER nextjs
# Expose port
EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD node -e "require('http').get('http://localhost:3000/api/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})" || exit 1
# Start the application
CMD ["node", "server.js"]
server {
listen 80;
server_name localhost;
# Gzip compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/json;
# 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;
# Root location - serve static files
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ $uri.html /index.html;
# Cache static assets
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
# API proxy (if needed)
location /api/ {
proxy_pass http://app-prod:3000/api/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Health check endpoint
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
# Error pages
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
export default async function docker_containerization(input) {
console.log("🧠 Running skill: docker-containerization");
// TODO: implement actual logic for this skill
return {
message: "Skill 'docker-containerization' executed successfully!",
input
};
}
{
"name": "@ai-labs-claude-skills/docker-containerization",
"version": "1.0.0",
"description": "Claude AI skill: docker-containerization",
"main": "index.js",
"files": [
"."
],
"license": "MIT",
"author": "AI Labs"
}Container Orchestration Guide
This document covers deploying Dockerized Next.js applications to various orchestration platforms.
Docker Compose
Basic Setup
Docker Compose is ideal for:
- Local development environments
- Small-scale deployments
- Testing multi-container setups
Production Example
version: '3.8'
services:
app:
image: nextjs-app:latest
container_name: nextjs-prod
restart: unless-stopped
ports:
- "3000:3000"
environment:
- NODE_ENV=production
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
networks:
- app-network
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
networks:
app-network:
driver: bridgeCommands
# Start services
docker-compose up -d
# View logs
docker-compose logs -f
# Scale services
docker-compose up -d --scale app=3
# Stop services
docker-compose down
# Rebuild and restart
docker-compose up -d --buildKubernetes (K8s)
When to Use Kubernetes
Use Kubernetes for:
- Large-scale deployments (100+ containers)
- High availability requirements
- Complex microservices architectures
- Auto-scaling needs
- Multi-cloud deployments
Deployment Configuration
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nextjs-app
labels:
app: nextjs-app
spec:
replicas: 3
selector:
matchLabels:
app: nextjs-app
template:
metadata:
labels:
app: nextjs-app
spec:
containers:
- name: nextjs
image: nextjs-app:latest
ports:
- containerPort: 3000
env:
- name: NODE_ENV
value: "production"
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /api/health
port: 3000
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /api/health
port: 3000
initialDelaySeconds: 5
periodSeconds: 5Service Configuration
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: nextjs-service
spec:
selector:
app: nextjs-app
ports:
- protocol: TCP
port: 80
targetPort: 3000
type: LoadBalancerIngress Configuration
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nextjs-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
tls:
- hosts:
- app.example.com
secretName: nextjs-tls
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nextjs-service
port:
number: 80Kubernetes Commands
# Apply configurations
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
kubectl apply -f ingress.yaml
# Check status
kubectl get deployments
kubectl get pods
kubectl get services
# View logs
kubectl logs -f deployment/nextjs-app
# Scale deployment
kubectl scale deployment nextjs-app --replicas=5
# Update image
kubectl set image deployment/nextjs-app nextjs=nextjs-app:v2.0.0
# Rollback
kubectl rollout undo deployment/nextjs-app
# Delete resources
kubectl delete -f deployment.yamlAmazon ECS (Elastic Container Service)
Task Definition
{
"family": "nextjs-app",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "512",
"memory": "1024",
"containerDefinitions": [
{
"name": "nextjs",
"image": "123456789012.dkr.ecr.us-east-1.amazonaws.com/nextjs-app:latest",
"portMappings": [
{
"containerPort": 3000,
"protocol": "tcp"
}
],
"environment": [
{
"name": "NODE_ENV",
"value": "production"
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/nextjs-app",
"awslogs-region": "us-east-1",
"awslogs-stream-prefix": "ecs"
}
},
"healthCheck": {
"command": [
"CMD-SHELL",
"curl -f http://localhost:3000/api/health || exit 1"
],
"interval": 30,
"timeout": 5,
"retries": 3,
"startPeriod": 60
}
}
]
}ECS Commands
# Register task definition
aws ecs register-task-definition --cli-input-json file://task-definition.json
# Create service
aws ecs create-service \
--cluster my-cluster \
--service-name nextjs-service \
--task-definition nextjs-app:1 \
--desired-count 3 \
--launch-type FARGATE \
--network-configuration "awsvpcConfiguration={subnets=[subnet-12345],securityGroups=[sg-12345]}"
# Update service
aws ecs update-service \
--cluster my-cluster \
--service nextjs-service \
--task-definition nextjs-app:2
# Scale service
aws ecs update-service \
--cluster my-cluster \
--service nextjs-service \
--desired-count 5Google Cloud Run
Deployment
# Build and push to GCR
gcloud builds submit --tag gcr.io/PROJECT_ID/nextjs-app
# Deploy to Cloud Run
gcloud run deploy nextjs-app \
--image gcr.io/PROJECT_ID/nextjs-app \
--platform managed \
--region us-central1 \
--allow-unauthenticated \
--memory 512Mi \
--cpu 1 \
--max-instances 10 \
--set-env-vars NODE_ENV=productionCloud Run YAML
# service.yaml
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: nextjs-app
spec:
template:
metadata:
annotations:
autoscaling.knative.dev/maxScale: '10'
autoscaling.knative.dev/minScale: '1'
spec:
containers:
- image: gcr.io/PROJECT_ID/nextjs-app
ports:
- containerPort: 3000
env:
- name: NODE_ENV
value: production
resources:
limits:
memory: 512Mi
cpu: '1'Azure Container Instances (ACI)
Deployment
# Create resource group
az group create --name myResourceGroup --location eastus
# Create container
az container create \
--resource-group myResourceGroup \
--name nextjs-app \
--image myregistry.azurecr.io/nextjs-app:latest \
--cpu 1 \
--memory 1 \
--registry-login-server myregistry.azurecr.io \
--registry-username <username> \
--registry-password <password> \
--dns-name-label nextjs-app-unique \
--ports 3000Digital Ocean App Platform
App Spec
# .do/app.yaml
name: nextjs-app
services:
- name: web
github:
repo: username/nextjs-app
branch: main
deploy_on_push: true
dockerfile_path: Dockerfile.production
http_port: 3000
instance_count: 3
instance_size_slug: basic-s
env_vars:
- key: NODE_ENV
value: "production"
health_check:
http_path: /api/health
initial_delay_seconds: 30
period_seconds: 10
timeout_seconds: 5
success_threshold: 1
failure_threshold: 3Comparison Matrix
| Platform | Best For | Complexity | Cost | Auto-Scaling |
|---|---|---|---|---|
| Docker Compose | Dev/Small deployments | Low | Very Low | No |
| Kubernetes | Enterprise/Large scale | High | Medium | Yes |
| ECS | AWS ecosystem | Medium | Medium | Yes |
| Cloud Run | Serverless/Pay-per-use | Low | Low | Yes |
| ACI | Simple Azure deployments | Low | Medium | Limited |
| DO App Platform | Simple deployments | Low | Low | Yes |
Auto-Scaling Configuration
Kubernetes HPA
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: nextjs-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nextjs-app
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80ECS Auto Scaling
# Register scalable target
aws application-autoscaling register-scalable-target \
--service-namespace ecs \
--resource-id service/my-cluster/nextjs-service \
--scalable-dimension ecs:service:DesiredCount \
--min-capacity 2 \
--max-capacity 10
# Create scaling policy
aws application-autoscaling put-scaling-policy \
--policy-name cpu-scaling-policy \
--service-namespace ecs \
--resource-id service/my-cluster/nextjs-service \
--scalable-dimension ecs:service:DesiredCount \
--policy-type TargetTrackingScaling \
--target-tracking-scaling-policy-configuration \
"TargetValue=70.0,PredefinedMetricSpecification={PredefinedMetricType=ECSServiceAverageCPUUtilization}"Load Balancing
Nginx Load Balancer
upstream nextjs_backend {
least_conn;
server app1:3000 weight=3;
server app2:3000 weight=2;
server app3:3000 weight=1;
}
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://nextjs_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}Monitoring & Logging
Prometheus + Grafana (Kubernetes)
# servicemonitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: nextjs-app
spec:
selector:
matchLabels:
app: nextjs-app
endpoints:
- port: metrics
interval: 30sELK Stack (Elasticsearch, Logstash, Kibana)
# docker-compose.yml
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.5.0
environment:
- discovery.type=single-node
ports:
- "9200:9200"
logstash:
image: docker.elastic.co/logstash/logstash:8.5.0
volumes:
- ./logstash.conf:/usr/share/logstash/pipeline/logstash.conf
kibana:
image: docker.elastic.co/kibana/kibana:8.5.0
ports:
- "5601:5601"Disaster Recovery
Backup Strategies
1. Container Images: Store in multiple registries 2. Data Volumes: Regular snapshots 3. Configuration: Version control (Git) 4. Secrets: Encrypted backups
High Availability
# Kubernetes with pod anti-affinity
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- nextjs-app
topologyKey: kubernetes.io/hostname---
Last Updated: November 2025 Version: 1.0.0
Docker Best Practices for Next.js Applications
This document outlines best practices for Docker containerization of Next.js applications.
Multi-Stage Builds
Why Use Multi-Stage Builds?
Multi-stage builds create smaller, more secure images by:
- Separating build dependencies from runtime dependencies
- Reducing final image size (often 50-70% smaller)
- Improving security by excluding build tools from production
- Faster deployments due to smaller images
Stage Structure
Stage 1: Dependencies
- Install production dependencies only
- Use
npm cifor reproducible builds - Cache dependencies for faster rebuilds
Stage 2: Builder
- Copy dependencies from Stage 1
- Build the application
- Generate optimized production assets
Stage 3: Runner
- Copy only necessary files (public, .next)
- Run as non-root user
- Minimal runtime dependencies
Image Optimization
1. Base Image Selection
# ✅ Good: Alpine images (smallest)
FROM node:18-alpine
# ⚠️ Okay: Slim images (small)
FROM node:18-slim
# ❌ Avoid: Full images (large)
FROM node:18Comparison:
- Alpine: ~170MB
- Slim: ~250MB
- Full: ~900MB
2. Layer Caching
Order Dockerfile instructions from least to most frequently changing:
# 1. System dependencies (rarely changes)
RUN apk add --no-cache libc6-compat
# 2. Package files (changes occasionally)
COPY package.json package-lock.json ./
# 3. Dependencies (changes when package files change)
RUN npm ci
# 4. Source code (changes frequently)
COPY . .
# 5. Build (changes with source)
RUN npm run build3. .dockerignore
Always include a .dockerignore file to exclude:
node_modules/.next/.git/*.log- Development files
- Documentation
Benefits:
- Faster builds (less data to copy)
- Smaller images
- Better security (no secrets)
Security Best Practices
1. Run as Non-Root User
# Create user and group
RUN addgroup --system --gid 1001 nodejs && \
adduser --system --uid 1001 nextjs
# Change ownership
RUN chown -R nextjs:nodejs /app
# Switch to non-root user
USER nextjsWhy: Root users can compromise the host system if container is breached.
2. Use Specific Image Tags
# ✅ Good: Specific version
FROM node:18.17.0-alpine
# ❌ Bad: Latest (unpredictable)
FROM node:latest3. Scan for Vulnerabilities
# Scan image for vulnerabilities
docker scan nextjs-app:latest
# Use Trivy
trivy image nextjs-app:latest4. Minimize Attack Surface
- Use minimal base images (Alpine)
- Include only necessary dependencies
- Remove package managers if not needed
- Disable unnecessary services
Performance Optimization
1. Build Cache
Use BuildKit for better caching:
# Enable BuildKit
export DOCKER_BUILDKIT=1
# Build with cache
docker build --build-arg BUILDKIT_INLINE_CACHE=1 -t app:latest .2. Parallel Builds
# Use experimental syntax for parallel operations
# syntax=docker/dockerfile:1.4
FROM node:18-alpine AS deps
RUN --mount=type=cache,target=/root/.npm \
npm ci3. Compression
Enable compression in Next.js:
// next.config.js
module.exports = {
compress: true,
}Environment Variables
Build-time vs Runtime
Build-time (--build-arg):
ARG NODE_ENV=production
ENV NODE_ENV=$NODE_ENVRuntime (docker run -e):
docker run -e API_URL=https://api.example.com app:latestSecrets Management
# ❌ Never do this
ENV API_SECRET=my-secret-key
# ✅ Use secrets
docker run --env-file .env.production app:latest
# ✅ Or use Docker secrets (Swarm)
docker secret create api_key ./api_key.txtHealth Checks
Application Health Check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD node -e "require('http').get('http://localhost:3000/api/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"Health Check Endpoint
// app/api/health/route.ts
export async function GET() {
return Response.json({ status: 'healthy' }, { status: 200 });
}Logging
Container Logs
# View logs
docker logs -f container-name
# Follow logs from multiple containers
docker-compose logs -f
# Last 100 lines
docker logs --tail 100 container-nameLogging Best Practices
1. Log to STDOUT/STDERR: Docker captures these automatically 2. Structured Logging: Use JSON format for easy parsing 3. Log Levels: Use appropriate levels (error, warn, info, debug) 4. Avoid Sensitive Data: Never log secrets or PII
Networking
Container Communication
# docker-compose.yml
networks:
app-network:
driver: bridge
services:
app:
networks:
- app-network
db:
networks:
- app-networkPort Mapping
# Single port
docker run -p 3000:3000 app:latest
# Multiple ports
docker run -p 3000:3000 -p 9229:9229 app:latest
# Random host port
docker run -p 3000 app:latestPersistent Data
Volumes
# Named volume (managed by Docker)
docker run -v app-data:/app/data app:latest
# Bind mount (host directory)
docker run -v $(pwd)/data:/app/data app:latest
# Anonymous volume
docker run -v /app/data app:latestVolume Best Practices
1. Use named volumes for production data 2. Use bind mounts for development (hot reload) 3. Backup volumes regularly 4. Set permissions correctly
Development vs Production
Development Configuration
# Dockerfile.development
FROM node:18-alpine
# Install all dependencies (including dev)
RUN npm install
# Enable hot reload
CMD ["npm", "run", "dev"]Production Configuration
# Dockerfile.production
FROM node:18-alpine AS runner
# Install production dependencies only
RUN npm ci --only=production
# Build and optimize
RUN npm run build
# Start production server
CMD ["node", "server.js"]CI/CD Integration
GitHub Actions
- name: Build Docker image
run: docker build -t app:${{ github.sha }} .
- name: Push to registry
run: docker push app:${{ github.sha }}Automated Testing
- name: Run tests in container
run: |
docker build -t app:test -f Dockerfile.test .
docker run app:test npm testMonitoring
Resource Limits
# Limit memory
docker run -m 512m app:latest
# Limit CPU
docker run --cpus=".5" app:latest
# Both
docker run -m 512m --cpus=".5" app:latestStats
# Real-time stats
docker stats
# Specific container
docker stats container-name
# No streaming
docker stats --no-streamTroubleshooting
Common Issues
1. Image too large
- Use multi-stage builds
- Use Alpine base images
- Add .dockerignore file
2. Slow builds
- Optimize layer caching
- Use BuildKit
- Parallelize operations
3. Container exits immediately
- Check logs:
docker logs container-name - Run interactively:
docker run -it app:latest sh - Check CMD/ENTRYPOINT
4. Port already in use
- Find process:
lsof -i :3000 - Use different port:
-p 3001:3000 - Stop conflicting container
Size Comparison
Before Optimization
Repository Tag Size
nextjs-app latest 1.2GBAfter Optimization
Repository Tag Size
nextjs-app latest 180MBSavings: 85% reduction in image size
Checklist
Before deploying to production, ensure:
- ✅ Using multi-stage builds
- ✅ Running as non-root user
- ✅ Using specific image tags (not latest)
- ✅ .dockerignore file present
- ✅ Health checks configured
- ✅ Resource limits set
- ✅ Logging to STDOUT/STDERR
- ✅ Secrets not hardcoded
- ✅ Image scanned for vulnerabilities
- ✅ Tested in staging environment
---
Last Updated: November 2025 Version: 1.0.0
#!/bin/bash
# Docker Build Script for Next.js Applications
# Builds Docker images with various configurations
set -e # Exit on error
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Default values
IMAGE_NAME="nextjs-app"
TAG="latest"
DOCKERFILE="Dockerfile.production"
BUILD_ARGS=""
NO_CACHE=false
PLATFORM=""
# Print usage
usage() {
echo -e "${BLUE}Usage:${NC} $0 [OPTIONS]"
echo ""
echo "Options:"
echo " -n, --name NAME Image name (default: nextjs-app)"
echo " -t, --tag TAG Image tag (default: latest)"
echo " -f, --file DOCKERFILE Dockerfile to use (default: Dockerfile.production)"
echo " -e, --env ENV Environment (dev|prod|nginx)"
echo " -b, --build-arg ARG Build argument (can be used multiple times)"
echo " --no-cache Build without cache"
echo " --platform PLATFORM Target platform (e.g., linux/amd64, linux/arm64)"
echo " -h, --help Show this help message"
echo ""
echo "Examples:"
echo " $0 -e prod -t v1.0.0"
echo " $0 -n my-app -e dev --no-cache"
echo " $0 --platform linux/amd64 -e prod"
}
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
-n|--name)
IMAGE_NAME="$2"
shift 2
;;
-t|--tag)
TAG="$2"
shift 2
;;
-f|--file)
DOCKERFILE="$2"
shift 2
;;
-e|--env)
ENV="$2"
case $ENV in
dev|development)
DOCKERFILE="Dockerfile.development"
;;
prod|production)
DOCKERFILE="Dockerfile.production"
;;
nginx)
DOCKERFILE="Dockerfile.nginx"
;;
*)
echo -e "${RED}Error: Invalid environment: $ENV${NC}"
echo "Valid options: dev, prod, nginx"
exit 1
;;
esac
shift 2
;;
-b|--build-arg)
BUILD_ARGS="$BUILD_ARGS --build-arg $2"
shift 2
;;
--no-cache)
NO_CACHE=true
shift
;;
--platform)
PLATFORM="$2"
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
echo -e "${RED}Error: Unknown option: $1${NC}"
usage
exit 1
;;
esac
done
# Build the command
DOCKER_CMD="docker build"
DOCKER_CMD="$DOCKER_CMD -t ${IMAGE_NAME}:${TAG}"
DOCKER_CMD="$DOCKER_CMD -f ${DOCKERFILE}"
if [ "$NO_CACHE" = true ]; then
DOCKER_CMD="$DOCKER_CMD --no-cache"
fi
if [ -n "$PLATFORM" ]; then
DOCKER_CMD="$DOCKER_CMD --platform $PLATFORM"
fi
if [ -n "$BUILD_ARGS" ]; then
DOCKER_CMD="$DOCKER_CMD $BUILD_ARGS"
fi
DOCKER_CMD="$DOCKER_CMD ."
# Print configuration
echo -e "${BLUE}╔═══════════════════════════════════════╗${NC}"
echo -e "${BLUE}║ Docker Build Configuration ║${NC}"
echo -e "${BLUE}╠═══════════════════════════════════════╣${NC}"
echo -e "${BLUE}║${NC} Image Name: ${GREEN}${IMAGE_NAME}${NC}"
echo -e "${BLUE}║${NC} Tag: ${GREEN}${TAG}${NC}"
echo -e "${BLUE}║${NC} Dockerfile: ${GREEN}${DOCKERFILE}${NC}"
echo -e "${BLUE}║${NC} No Cache: ${GREEN}${NO_CACHE}${NC}"
if [ -n "$PLATFORM" ]; then
echo -e "${BLUE}║${NC} Platform: ${GREEN}${PLATFORM}${NC}"
fi
echo -e "${BLUE}╚═══════════════════════════════════════╝${NC}"
echo ""
# Check if Dockerfile exists
if [ ! -f "$DOCKERFILE" ]; then
echo -e "${RED}Error: Dockerfile not found: $DOCKERFILE${NC}"
exit 1
fi
# Execute build
echo -e "${YELLOW}Building Docker image...${NC}"
echo -e "${BLUE}Command:${NC} $DOCKER_CMD"
echo ""
if eval $DOCKER_CMD; then
echo ""
echo -e "${GREEN}✓ Build successful!${NC}"
echo ""
echo -e "${BLUE}Image details:${NC}"
docker images | grep "$IMAGE_NAME" | grep "$TAG"
echo ""
echo -e "${BLUE}Next steps:${NC}"
echo " Run: docker run -p 3000:3000 ${IMAGE_NAME}:${TAG}"
echo " Push: docker push ${IMAGE_NAME}:${TAG}"
echo " Inspect: docker inspect ${IMAGE_NAME}:${TAG}"
else
echo ""
echo -e "${RED}✗ Build failed!${NC}"
exit 1
fi
#!/bin/bash
# Docker Cleanup Script
# Removes unused Docker resources to free up disk space
set -e # Exit on error
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Flags
DRY_RUN=false
FORCE=false
ALL=false
CONTAINERS=false
IMAGES=false
VOLUMES=false
NETWORKS=false
# Print usage
usage() {
echo -e "${BLUE}Usage:${NC} $0 [OPTIONS]"
echo ""
echo "Options:"
echo " --all Clean all unused resources"
echo " --containers Remove stopped containers"
echo " --images Remove dangling images"
echo " --volumes Remove unused volumes"
echo " --networks Remove unused networks"
echo " --dry-run Show what would be removed without actually removing"
echo " -f, --force Force removal without confirmation"
echo " -h, --help Show this help message"
echo ""
echo "Examples:"
echo " $0 --all # Clean everything"
echo " $0 --containers --images # Clean containers and images"
echo " $0 --all --dry-run # Preview cleanup without removing"
}
# Parse arguments
if [ $# -eq 0 ]; then
usage
exit 0
fi
while [[ $# -gt 0 ]]; do
case $1 in
--all)
ALL=true
shift
;;
--containers)
CONTAINERS=true
shift
;;
--images)
IMAGES=true
shift
;;
--volumes)
VOLUMES=true
shift
;;
--networks)
NETWORKS=true
shift
;;
--dry-run)
DRY_RUN=true
shift
;;
-f|--force)
FORCE=true
shift
;;
-h|--help)
usage
exit 0
;;
*)
echo -e "${RED}Error: Unknown option: $1${NC}"
usage
exit 1
;;
esac
done
# If --all is specified, enable all cleanup options
if [ "$ALL" = true ]; then
CONTAINERS=true
IMAGES=true
VOLUMES=true
NETWORKS=true
fi
# Show current disk usage
echo -e "${BLUE}╔═══════════════════════════════════════╗${NC}"
echo -e "${BLUE}║ Current Docker Disk Usage ║${NC}"
echo -e "${BLUE}╚═══════════════════════════════════════╝${NC}"
docker system df
echo ""
# Confirmation prompt (unless --force or --dry-run)
if [ "$FORCE" = false ] && [ "$DRY_RUN" = false ]; then
echo -e "${YELLOW}This will remove unused Docker resources.${NC}"
read -p "Continue? (y/n) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo -e "${RED}Aborted.${NC}"
exit 0
fi
fi
# Cleanup functions
cleanup_containers() {
echo -e "${BLUE}Cleaning up stopped containers...${NC}"
if [ "$DRY_RUN" = true ]; then
STOPPED=$(docker ps -aq -f status=exited)
if [ -n "$STOPPED" ]; then
echo -e "${YELLOW}Would remove:${NC}"
docker ps -a -f status=exited --format "table {{.ID}}\t{{.Names}}\t{{.Status}}"
else
echo -e "${GREEN}No stopped containers to remove.${NC}"
fi
else
REMOVED=$(docker container prune -f 2>&1 | grep "Total reclaimed space" || echo "")
if [ -n "$REMOVED" ]; then
echo -e "${GREEN}✓ $REMOVED${NC}"
else
echo -e "${GREEN}✓ No stopped containers to remove.${NC}"
fi
fi
echo ""
}
cleanup_images() {
echo -e "${BLUE}Cleaning up dangling images...${NC}"
if [ "$DRY_RUN" = true ]; then
DANGLING=$(docker images -f "dangling=true" -q)
if [ -n "$DANGLING" ]; then
echo -e "${YELLOW}Would remove:${NC}"
docker images -f "dangling=true" --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}\t{{.Size}}"
else
echo -e "${GREEN}No dangling images to remove.${NC}"
fi
else
REMOVED=$(docker image prune -f 2>&1 | grep "Total reclaimed space" || echo "")
if [ -n "$REMOVED" ]; then
echo -e "${GREEN}✓ $REMOVED${NC}"
else
echo -e "${GREEN}✓ No dangling images to remove.${NC}"
fi
fi
echo ""
}
cleanup_volumes() {
echo -e "${BLUE}Cleaning up unused volumes...${NC}"
if [ "$DRY_RUN" = true ]; then
UNUSED=$(docker volume ls -qf dangling=true)
if [ -n "$UNUSED" ]; then
echo -e "${YELLOW}Would remove:${NC}"
docker volume ls -f dangling=true --format "table {{.Name}}\t{{.Driver}}\t{{.Mountpoint}}"
else
echo -e "${GREEN}No unused volumes to remove.${NC}"
fi
else
REMOVED=$(docker volume prune -f 2>&1 | grep "Total reclaimed space" || echo "")
if [ -n "$REMOVED" ]; then
echo -e "${GREEN}✓ $REMOVED${NC}"
else
echo -e "${GREEN}✓ No unused volumes to remove.${NC}"
fi
fi
echo ""
}
cleanup_networks() {
echo -e "${BLUE}Cleaning up unused networks...${NC}"
if [ "$DRY_RUN" = true ]; then
UNUSED=$(docker network ls -qf "dangling=true")
if [ -n "$UNUSED" ]; then
echo -e "${YELLOW}Would remove:${NC}"
docker network ls -f "dangling=true" --format "table {{.ID}}\t{{.Name}}\t{{.Driver}}"
else
echo -e "${GREEN}No unused networks to remove.${NC}"
fi
else
REMOVED=$(docker network prune -f 2>&1 | grep "Total reclaimed space" || echo "")
if [ -n "$REMOVED" ]; then
echo -e "${GREEN}✓ $REMOVED${NC}"
else
echo -e "${GREEN}✓ No unused networks to remove.${NC}"
fi
fi
echo ""
}
# Execute cleanup operations
if [ "$CONTAINERS" = true ]; then
cleanup_containers
fi
if [ "$IMAGES" = true ]; then
cleanup_images
fi
if [ "$VOLUMES" = true ]; then
cleanup_volumes
fi
if [ "$NETWORKS" = true ]; then
cleanup_networks
fi
# Show final disk usage
echo -e "${BLUE}╔═══════════════════════════════════════╗${NC}"
echo -e "${BLUE}║ Final Docker Disk Usage ║${NC}"
echo -e "${BLUE}╚═══════════════════════════════════════╝${NC}"
docker system df
echo ""
if [ "$DRY_RUN" = true ]; then
echo -e "${YELLOW}Dry run complete. No resources were removed.${NC}"
echo -e "${BLUE}Run without --dry-run to actually remove resources.${NC}"
else
echo -e "${GREEN}✓ Cleanup complete!${NC}"
fi
#!/bin/bash
# Docker Push Script for Next.js Applications
# Pushes Docker images to registries (Docker Hub, ECR, GCR, etc.)
set -e # Exit on error
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Default values
IMAGE_NAME="nextjs-app"
TAG="latest"
REGISTRY=""
REPOSITORY=""
ADDITIONAL_TAGS=""
# Print usage
usage() {
echo -e "${BLUE}Usage:${NC} $0 [OPTIONS]"
echo ""
echo "Options:"
echo " -n, --name NAME Image name (default: nextjs-app)"
echo " -t, --tag TAG Image tag (default: latest)"
echo " -r, --registry REG Registry URL (e.g., docker.io, gcr.io, 123456789012.dkr.ecr.us-east-1.amazonaws.com)"
echo " --repo REPO Repository name (e.g., mycompany/myapp)"
echo " --also-tag TAG Additional tags to create and push (can be used multiple times)"
echo " -h, --help Show this help message"
echo ""
echo "Examples:"
echo " $0 -n my-app -t v1.0.0 --repo username/my-app"
echo " $0 -r gcr.io/my-project --repo my-app -t latest --also-tag stable"
echo " $0 -r 123456789012.dkr.ecr.us-east-1.amazonaws.com --repo my-app"
}
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
-n|--name)
IMAGE_NAME="$2"
shift 2
;;
-t|--tag)
TAG="$2"
shift 2
;;
-r|--registry)
REGISTRY="$2"
shift 2
;;
--repo)
REPOSITORY="$2"
shift 2
;;
--also-tag)
ADDITIONAL_TAGS="$ADDITIONAL_TAGS $2"
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
echo -e "${RED}Error: Unknown option: $1${NC}"
usage
exit 1
;;
esac
done
# Check if image exists locally
if ! docker images --format '{{.Repository}}:{{.Tag}}' | grep -q "^${IMAGE_NAME}:${TAG}$"; then
echo -e "${RED}Error: Image not found: ${IMAGE_NAME}:${TAG}${NC}"
echo -e "${YELLOW}Available images:${NC}"
docker images | grep "$IMAGE_NAME" || echo "No images found for $IMAGE_NAME"
exit 1
fi
# Build the target image name
if [ -n "$REGISTRY" ] && [ -n "$REPOSITORY" ]; then
TARGET_IMAGE="${REGISTRY}/${REPOSITORY}:${TAG}"
elif [ -n "$REPOSITORY" ]; then
TARGET_IMAGE="${REPOSITORY}:${TAG}"
else
TARGET_IMAGE="${IMAGE_NAME}:${TAG}"
fi
# Print configuration
echo -e "${BLUE}╔═══════════════════════════════════════╗${NC}"
echo -e "${BLUE}║ Docker Push Configuration ║${NC}"
echo -e "${BLUE}╠═══════════════════════════════════════╣${NC}"
echo -e "${BLUE}║${NC} Source Image: ${GREEN}${IMAGE_NAME}:${TAG}${NC}"
echo -e "${BLUE}║${NC} Target Image: ${GREEN}${TARGET_IMAGE}${NC}"
if [ -n "$ADDITIONAL_TAGS" ]; then
echo -e "${BLUE}║${NC} Also pushing: ${GREEN}${ADDITIONAL_TAGS}${NC}"
fi
echo -e "${BLUE}╚═══════════════════════════════════════╝${NC}"
echo ""
# Tag the image if source and target are different
if [ "${IMAGE_NAME}:${TAG}" != "$TARGET_IMAGE" ]; then
echo -e "${YELLOW}Tagging image...${NC}"
if docker tag "${IMAGE_NAME}:${TAG}" "$TARGET_IMAGE"; then
echo -e "${GREEN}✓ Tagged successfully${NC}"
else
echo -e "${RED}✗ Failed to tag image${NC}"
exit 1
fi
echo ""
fi
# Push the main image
echo -e "${YELLOW}Pushing image: ${TARGET_IMAGE}${NC}"
if docker push "$TARGET_IMAGE"; then
echo -e "${GREEN}✓ Pushed successfully: ${TARGET_IMAGE}${NC}"
else
echo -e "${RED}✗ Failed to push image${NC}"
exit 1
fi
echo ""
# Push additional tags
for EXTRA_TAG in $ADDITIONAL_TAGS; do
if [ -n "$REGISTRY" ] && [ -n "$REPOSITORY" ]; then
EXTRA_IMAGE="${REGISTRY}/${REPOSITORY}:${EXTRA_TAG}"
elif [ -n "$REPOSITORY" ]; then
EXTRA_IMAGE="${REPOSITORY}:${EXTRA_TAG}"
else
EXTRA_IMAGE="${IMAGE_NAME}:${EXTRA_TAG}"
fi
echo -e "${YELLOW}Tagging and pushing: ${EXTRA_IMAGE}${NC}"
if docker tag "${IMAGE_NAME}:${TAG}" "$EXTRA_IMAGE"; then
if docker push "$EXTRA_IMAGE"; then
echo -e "${GREEN}✓ Pushed successfully: ${EXTRA_IMAGE}${NC}"
else
echo -e "${RED}✗ Failed to push: ${EXTRA_IMAGE}${NC}"
fi
else
echo -e "${RED}✗ Failed to tag: ${EXTRA_IMAGE}${NC}"
fi
echo ""
done
echo -e "${GREEN}✓ All images pushed successfully!${NC}"
echo ""
echo -e "${BLUE}Pushed images:${NC}"
echo " - ${TARGET_IMAGE}"
for EXTRA_TAG in $ADDITIONAL_TAGS; do
if [ -n "$REGISTRY" ] && [ -n "$REPOSITORY" ]; then
echo " - ${REGISTRY}/${REPOSITORY}:${EXTRA_TAG}"
elif [ -n "$REPOSITORY" ]; then
echo " - ${REPOSITORY}:${EXTRA_TAG}"
else
echo " - ${IMAGE_NAME}:${EXTRA_TAG}"
fi
done
#!/bin/bash
# Docker Run Script for Next.js Applications
# Runs Docker containers with various configurations
set -e # Exit on error
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Default values
IMAGE_NAME="nextjs-app"
TAG="latest"
CONTAINER_NAME="nextjs-container"
HOST_PORT="3000"
CONTAINER_PORT="3000"
DETACHED=false
ENV_FILE=""
VOLUMES=""
NETWORK=""
RESTART_POLICY=""
# Print usage
usage() {
echo -e "${BLUE}Usage:${NC} $0 [OPTIONS]"
echo ""
echo "Options:"
echo " -n, --name NAME Container name (default: nextjs-container)"
echo " -i, --image IMAGE Image name (default: nextjs-app)"
echo " -t, --tag TAG Image tag (default: latest)"
echo " -p, --port HOST:CONT Port mapping (default: 3000:3000)"
echo " -d, --detach Run in detached mode"
echo " -e, --env-file FILE Environment file"
echo " -v, --volume VOL Volume mount (can be used multiple times)"
echo " --network NETWORK Docker network to use"
echo " --restart POLICY Restart policy (no|on-failure|always|unless-stopped)"
echo " -h, --help Show this help message"
echo ""
echo "Examples:"
echo " $0 -i my-app -t v1.0.0 -d"
echo " $0 -p 8080:3000 --env-file .env.production"
echo " $0 -v ./data:/app/data --restart unless-stopped"
}
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
-n|--name)
CONTAINER_NAME="$2"
shift 2
;;
-i|--image)
IMAGE_NAME="$2"
shift 2
;;
-t|--tag)
TAG="$2"
shift 2
;;
-p|--port)
IFS=':' read -r HOST_PORT CONTAINER_PORT <<< "$2"
shift 2
;;
-d|--detach)
DETACHED=true
shift
;;
-e|--env-file)
ENV_FILE="$2"
shift 2
;;
-v|--volume)
VOLUMES="$VOLUMES -v $2"
shift 2
;;
--network)
NETWORK="$2"
shift 2
;;
--restart)
RESTART_POLICY="$2"
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
echo -e "${RED}Error: Unknown option: $1${NC}"
usage
exit 1
;;
esac
done
# Build the command
DOCKER_CMD="docker run"
DOCKER_CMD="$DOCKER_CMD --name ${CONTAINER_NAME}"
DOCKER_CMD="$DOCKER_CMD -p ${HOST_PORT}:${CONTAINER_PORT}"
if [ "$DETACHED" = true ]; then
DOCKER_CMD="$DOCKER_CMD -d"
fi
if [ -n "$ENV_FILE" ]; then
if [ -f "$ENV_FILE" ]; then
DOCKER_CMD="$DOCKER_CMD --env-file $ENV_FILE"
else
echo -e "${YELLOW}Warning: Environment file not found: $ENV_FILE${NC}"
fi
fi
if [ -n "$VOLUMES" ]; then
DOCKER_CMD="$DOCKER_CMD $VOLUMES"
fi
if [ -n "$NETWORK" ]; then
DOCKER_CMD="$DOCKER_CMD --network $NETWORK"
fi
if [ -n "$RESTART_POLICY" ]; then
DOCKER_CMD="$DOCKER_CMD --restart $RESTART_POLICY"
fi
DOCKER_CMD="$DOCKER_CMD ${IMAGE_NAME}:${TAG}"
# Check if container already exists
if docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
echo -e "${YELLOW}Container ${CONTAINER_NAME} already exists.${NC}"
read -p "Do you want to remove it and create a new one? (y/n) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo -e "${BLUE}Removing existing container...${NC}"
docker rm -f "$CONTAINER_NAME"
else
echo -e "${RED}Aborted.${NC}"
exit 1
fi
fi
# Check if image exists
if ! docker images --format '{{.Repository}}:{{.Tag}}' | grep -q "^${IMAGE_NAME}:${TAG}$"; then
echo -e "${RED}Error: Image not found: ${IMAGE_NAME}:${TAG}${NC}"
echo -e "${YELLOW}Available images:${NC}"
docker images | grep "$IMAGE_NAME" || echo "No images found for $IMAGE_NAME"
exit 1
fi
# Print configuration
echo -e "${BLUE}╔═══════════════════════════════════════╗${NC}"
echo -e "${BLUE}║ Docker Run Configuration ║${NC}"
echo -e "${BLUE}╠═══════════════════════════════════════╣${NC}"
echo -e "${BLUE}║${NC} Container: ${GREEN}${CONTAINER_NAME}${NC}"
echo -e "${BLUE}║${NC} Image: ${GREEN}${IMAGE_NAME}:${TAG}${NC}"
echo -e "${BLUE}║${NC} Port: ${GREEN}${HOST_PORT}:${CONTAINER_PORT}${NC}"
echo -e "${BLUE}║${NC} Detached: ${GREEN}${DETACHED}${NC}"
if [ -n "$ENV_FILE" ]; then
echo -e "${BLUE}║${NC} Env File: ${GREEN}${ENV_FILE}${NC}"
fi
if [ -n "$NETWORK" ]; then
echo -e "${BLUE}║${NC} Network: ${GREEN}${NETWORK}${NC}"
fi
if [ -n "$RESTART_POLICY" ]; then
echo -e "${BLUE}║${NC} Restart: ${GREEN}${RESTART_POLICY}${NC}"
fi
echo -e "${BLUE}╚═══════════════════════════════════════╝${NC}"
echo ""
# Execute run
echo -e "${YELLOW}Starting Docker container...${NC}"
echo -e "${BLUE}Command:${NC} $DOCKER_CMD"
echo ""
if eval $DOCKER_CMD; then
echo ""
echo -e "${GREEN}✓ Container started successfully!${NC}"
echo ""
if [ "$DETACHED" = true ]; then
echo -e "${BLUE}Container is running in background.${NC}"
echo ""
echo -e "${BLUE}Container details:${NC}"
docker ps --filter "name=${CONTAINER_NAME}" --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}"
echo ""
echo -e "${BLUE}Access application:${NC}"
echo " URL: http://localhost:${HOST_PORT}"
echo ""
echo -e "${BLUE}Useful commands:${NC}"
echo " Logs: docker logs -f ${CONTAINER_NAME}"
echo " Stop: docker stop ${CONTAINER_NAME}"
echo " Restart: docker restart ${CONTAINER_NAME}"
echo " Remove: docker rm -f ${CONTAINER_NAME}"
echo " Exec: docker exec -it ${CONTAINER_NAME} sh"
else
echo -e "${BLUE}Container running in foreground. Press Ctrl+C to stop.${NC}"
fi
else
echo ""
echo -e "${RED}✗ Failed to start container!${NC}"
exit 1
fi
Related skills
How it compares
Choose Docker Containerization over generic Docker skills when the stack is Next.js and you need dev/prod Compose splits with Next-specific ignore rules.
FAQ
What files does Docker Containerization generate for Next.js?
Docker Containerization generates Dockerfile.development, a production Dockerfile, docker-compose.yml at format 3.8, and a .dockerignore tailored to Next.js paths like .next, out, dist, and node_modules.
Does Docker Containerization separate dev and production?
Docker Containerization creates separate development and production Docker services in Compose, including an app-dev service with Dockerfile.development for local workflows and production-oriented image builds.
Is Docker Containerization safe to install?
skills.sh reports 2 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.