Initial commit
This commit is contained in:
271
commands/docker-expert.md
Normal file
271
commands/docker-expert.md
Normal file
@@ -0,0 +1,271 @@
|
||||
# Docker Expert
|
||||
|
||||
**Description**: Build efficient, secure Docker containers following best practices
|
||||
|
||||
## Core Concepts
|
||||
|
||||
- **Image**: Read-only template for containers
|
||||
- **Container**: Running instance of an image
|
||||
- **Dockerfile**: Instructions to build an image
|
||||
- **Registry**: Storage for images (Docker Hub, ECR, etc.)
|
||||
- **Volume**: Persistent data storage
|
||||
- **Network**: Container communication
|
||||
|
||||
## Dockerfile Best Practices
|
||||
|
||||
### Multi-Stage Build
|
||||
```dockerfile
|
||||
# ✅ Best practice: Multi-stage build for smaller images
|
||||
# Stage 1: Build
|
||||
FROM node:18-alpine AS builder
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
RUN npm ci --only=production
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
# Stage 2: Production
|
||||
FROM node:18-alpine
|
||||
WORKDIR /app
|
||||
COPY --from=builder /app/dist ./dist
|
||||
COPY --from=builder /app/node_modules ./node_modules
|
||||
EXPOSE 3000
|
||||
USER node
|
||||
CMD ["node", "dist/server.js"]
|
||||
|
||||
# ❌ Bad: Single stage with dev dependencies
|
||||
FROM node:18
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
RUN npm install # Installs dev dependencies too
|
||||
CMD ["node", "server.js"]
|
||||
```
|
||||
|
||||
### Layer Optimization
|
||||
```dockerfile
|
||||
# ✅ Good: Optimize layer caching
|
||||
FROM python:3.11-slim
|
||||
WORKDIR /app
|
||||
|
||||
# Install dependencies first (cached if unchanged)
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# Copy application code (changes frequently)
|
||||
COPY . .
|
||||
|
||||
# ❌ Bad: Copy everything first
|
||||
FROM python:3.11-slim
|
||||
COPY . /app # Every code change invalidates all layers
|
||||
RUN pip install -r requirements.txt
|
||||
```
|
||||
|
||||
### Security
|
||||
```dockerfile
|
||||
# ✅ Security best practices
|
||||
FROM node:18-alpine # Use specific versions and minimal images
|
||||
|
||||
# Create non-root user
|
||||
RUN addgroup -g 1001 -S nodejs && \
|
||||
adduser -S nodejs -u 1001
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install dependencies
|
||||
COPY package*.json ./
|
||||
RUN npm ci --only=production && \
|
||||
npm cache clean --force
|
||||
|
||||
COPY --chown=nodejs:nodejs . .
|
||||
|
||||
# Run as non-root
|
||||
USER nodejs
|
||||
|
||||
EXPOSE 3000
|
||||
CMD ["node", "server.js"]
|
||||
|
||||
# ❌ Bad: Security issues
|
||||
FROM node:latest # Don't use 'latest'
|
||||
COPY . .
|
||||
RUN npm install
|
||||
CMD ["node", "server.js"] # Running as root!
|
||||
```
|
||||
|
||||
## Common Docker Commands
|
||||
|
||||
```bash
|
||||
# Build image
|
||||
docker build -t myapp:1.0 .
|
||||
docker build -t myapp:1.0 -f Dockerfile.prod .
|
||||
|
||||
# Run container
|
||||
docker run -d -p 3000:3000 --name myapp myapp:1.0
|
||||
docker run -it --rm myapp:1.0 sh # Interactive shell
|
||||
|
||||
# Environment variables
|
||||
docker run -e NODE_ENV=production -e PORT=3000 myapp:1.0
|
||||
|
||||
# Volumes
|
||||
docker run -v $(pwd)/data:/app/data myapp:1.0
|
||||
|
||||
# View logs
|
||||
docker logs myapp
|
||||
docker logs -f myapp # Follow logs
|
||||
|
||||
# Execute commands in running container
|
||||
docker exec -it myapp sh
|
||||
docker exec myapp ls -la
|
||||
|
||||
# Stop/start/remove
|
||||
docker stop myapp
|
||||
docker start myapp
|
||||
docker rm myapp
|
||||
docker rm -f myapp # Force remove
|
||||
|
||||
# Image management
|
||||
docker images
|
||||
docker rmi myapp:1.0
|
||||
docker image prune # Remove unused images
|
||||
|
||||
# Container management
|
||||
docker ps # Running containers
|
||||
docker ps -a # All containers
|
||||
docker container prune # Remove stopped containers
|
||||
```
|
||||
|
||||
## Docker Compose
|
||||
|
||||
```yaml
|
||||
# docker-compose.yml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
# Web application
|
||||
web:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "3000:3000"
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- DATABASE_URL=postgresql://db:5432/myapp
|
||||
depends_on:
|
||||
- db
|
||||
- redis
|
||||
volumes:
|
||||
- ./logs:/app/logs
|
||||
networks:
|
||||
- app-network
|
||||
restart: unless-stopped
|
||||
|
||||
# Database
|
||||
db:
|
||||
image: postgres:15-alpine
|
||||
environment:
|
||||
- POSTGRES_DB=myapp
|
||||
- POSTGRES_USER=user
|
||||
- POSTGRES_PASSWORD=password
|
||||
volumes:
|
||||
- db-data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- app-network
|
||||
restart: unless-stopped
|
||||
|
||||
# Cache
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
networks:
|
||||
- app-network
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
db-data:
|
||||
|
||||
networks:
|
||||
app-network:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
```bash
|
||||
# Docker Compose commands
|
||||
docker-compose up -d # Start services
|
||||
docker-compose down # Stop and remove
|
||||
docker-compose logs -f web # View logs
|
||||
docker-compose exec web sh # Execute command
|
||||
docker-compose ps # List services
|
||||
docker-compose restart web # Restart service
|
||||
```
|
||||
|
||||
## .dockerignore
|
||||
|
||||
```
|
||||
# .dockerignore - Exclude files from build context
|
||||
node_modules
|
||||
npm-debug.log
|
||||
.git
|
||||
.gitignore
|
||||
.env
|
||||
.env.local
|
||||
*.md
|
||||
dist
|
||||
coverage
|
||||
.DS_Store
|
||||
```
|
||||
|
||||
## Healthchecks
|
||||
|
||||
```dockerfile
|
||||
# Add healthcheck to Dockerfile
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD node healthcheck.js || exit 1
|
||||
```
|
||||
|
||||
```javascript
|
||||
// healthcheck.js
|
||||
const http = require('http');
|
||||
|
||||
const options = {
|
||||
host: 'localhost',
|
||||
port: 3000,
|
||||
path: '/health',
|
||||
timeout: 2000
|
||||
};
|
||||
|
||||
const request = http.request(options, (res) => {
|
||||
console.log(`STATUS: ${res.statusCode}`);
|
||||
process.exit(res.statusCode === 200 ? 0 : 1);
|
||||
});
|
||||
|
||||
request.on('error', (err) => {
|
||||
console.log('ERROR', err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
request.end();
|
||||
```
|
||||
|
||||
## Best Practices Checklist
|
||||
|
||||
- [ ] Use specific image versions (not `latest`)
|
||||
- [ ] Use minimal base images (alpine)
|
||||
- [ ] Multi-stage builds for smaller images
|
||||
- [ ] Optimize layer caching
|
||||
- [ ] Run as non-root user
|
||||
- [ ] Use .dockerignore
|
||||
- [ ] Add healthchecks
|
||||
- [ ] Set resource limits
|
||||
- [ ] Use secrets management (not ENV vars for secrets)
|
||||
- [ ] Scan images for vulnerabilities
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
- Containerizing applications
|
||||
- Creating Dockerfiles
|
||||
- Setting up multi-container applications
|
||||
- Optimizing Docker images
|
||||
- Debugging container issues
|
||||
|
||||
---
|
||||
|
||||
**Remember**: Small, secure, and efficient containers are the goal!
|
||||
Reference in New Issue
Block a user