As containerization becomes crucial in modern development, here are essential Docker practices with real-world implementations:
- Use Multi-Stage Builds
# Build stage
FROM node:16 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# Production stage
FROM node:16-slim
COPY --from=builder /app/dist /app
EXPOSE 3000
CMD ["node", "app"]
Result: Production image size reduced by up to 90%!
- Leverage .dockerignore
node_modules
npm-debug.log
Dockerfile
.git
.env
*.md
Keep your builds clean and secure by excluding unnecessary files.
- Pick Specific Base Image Tags
# β Bad practice
FROM node:latest
# β
Good practice
FROM node:16.17.0-alpine3.16
Ensures consistency across environments and prevents unexpected breaks.
- One Container, One Process
# β
Good practice
FROM nginx:alpine
COPY ./web-app /usr/share/nginx/html
# Single process: nginx
CMD ["nginx", "-g", "daemon off;"]
- Optimize Layer Caching
# β
Good practice
COPY package.json package-lock.json ./
RUN npm install
# Source code changes don't trigger node_modules reinstall
COPY . .
- Use Non-Root Users
FROM node:16-alpine
# Create app directory and user
RUN mkdir /app && addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
# Switch to non-root user
USER appuser
COPY --chown=appuser:appgroup . .
- Scan for Vulnerabilities
# Using Trivy in CI/CD
trivy image your-image:tag
Set up automated scanning in your pipeline for continuous security.
- Keep Images Minimal
# β
Good practice: Using alpine
FROM python:3.9-alpine
RUN apk add --no-cache postgresql-libs
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
- Cache Dependencies Wisely
# β
Good practice
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile
COPY . .
- Set Resource Limits
# Docker run with limits
docker run -d \
--name myapp \
--memory="512m" \
--cpus="1.0" \
your-image:tag
Docker Compose version:
services:
web:
image: your-image:tag
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
π Bonus: Environment Variables Best Practices
# β Bad practice: Hardcoding
ENV API_KEY=1234567890
# β
Good practice: Using ARG for build-time variables
ARG BUILD_VERSION
ENV APP_VERSION=$BUILD_VERSION
# β
Better practice: Using docker-compose.yml
# docker-compose.yml
services:
app:
env_file:
- .env.production
π‘ Pro Tip: Always maintain a clear documentation for your Docker setup:
# Service Name
## Build
`docker build -t service-name .`
## Run
`docker run -p 3000:3000 service-name`
## Environment Variables
- `PORT`: Application port (default: 3000)
- `NODE_ENV`: Runtime environment
## Resource Requirements
- Memory: 512MB minimum
- CPU: 1 core recommended
What Docker practices have improved your development workflow? Share your experiences below!
Top comments (0)