Przejdź do głównej zawartości

Wzorce Docker i kontenerów

Opanuj konteneryzację z Cursor i Claude Code. Ten przewodnik obejmuje budowy wieloetapowe, optymalizację kontenerów, orkiestrację Docker Compose, najlepsze praktyki bezpieczeństwa i przepływy pracy kontenerów gotowe do produkcji z pomocą AI.

  1. Inicjalizacja projektu Docker

    Okno terminala
    # Stwórz zoptymalizowany Dockerfile
    Agent: "Stwórz konfigurację Docker wieloetapową dla tej aplikacji Node.js z:
    - Etapem budowy dla zależności
    - Etapem produkcyjnym z minimalną powierzchnią ataku
    - Użytkownikiem nie-root
    - Kontrolami zdrowia"
  2. Instalacja serwera MCP Docker (opcjonalnie)

    Okno terminala
    # Claude Code
    # Uwaga: Brak bezpośredniego URL MCP - używaj Docker Hub MCP Server
    claude mcp add docker-hub -- npx -y @docker/hub-mcp
    # Dostęp do katalogu Docker MCP na: https://hub.docker.com/mcp
  3. Konfiguracja reguł AI

    # .cursorrules lub CLAUDE.md
    Najlepsze praktyki Docker:
    - Używaj konkretnych wersji obrazów podstawowych (nie :latest)
    - Minimalizuj warstwy i rozmiar obrazu
    - Uruchamiaj jako użytkownik nie-root
    - Używaj .dockerignore
    - Implementuj kontrole zdrowia
    - Przestrzegaj najlepszych praktyk bezpieczeństwa
    - Używaj efektywnie cache budowy
# Prompt AI
Agent: "Stwórz zoptymalizowany Dockerfile wieloetapowy dla Node.js z:
- Cache'owaniem zależności
- Optymalizacją budowy produkcyjnej
- Zabezpieczeniami
- Minimalnym obrazem końcowym"
# Wygenerowany Dockerfile
# Etap budowy
FROM node:20-alpine AS builder
# Instaluj zależności budowy
RUN apk add --no-cache python3 make g++
WORKDIR /app
# Cache'uj zależności
COPY package*.json ./
RUN npm ci --only=production && \
cp -R node_modules prod_node_modules && \
npm ci
# Buduj aplikację
COPY . .
RUN npm run build
# Etap produkcyjny
FROM node:20-alpine AS production
# Instaluj dumb-init dla właściwej obsługi sygnałów
RUN apk add --no-cache dumb-init
# Stwórz użytkownika nie-root
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
WORKDIR /app
# Kopiuj zależności produkcyjne
COPY --from=builder --chown=nodejs:nodejs /app/prod_node_modules ./node_modules
# Kopiuj zbudowaną aplikację
COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist
COPY --from=builder --chown=nodejs:nodejs /app/package*.json ./
# Przełącz na użytkownika nie-root
USER nodejs
# Wyeksponuj port
EXPOSE 3000
# Kontrola zdrowia
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD node healthcheck.js
# Używaj dumb-init do właściwej obsługi sygnałów
ENTRYPOINT ["dumb-init", "--"]
CMD ["node", "dist/index.js"]
# Prompt AI: "Stwórz zoptymalizowaną budowę Docker Python z Poetry"
# Etap budowy
FROM python:3.12-slim AS builder
# Instaluj zależności budowy
RUN apt-get update && apt-get install -y \
build-essential \
curl \
&& rm -rf /var/lib/apt/lists/*
# Instaluj Poetry
ENV POETRY_VERSION=1.7.1
RUN curl -sSL https://install.python-poetry.org | python3 -
# Ustaw katalog roboczy
WORKDIR /app
# Kopiuj pliki zależności
COPY pyproject.toml poetry.lock ./
# Instaluj zależności
RUN ~/.local/bin/poetry config virtualenvs.create false && \
~/.local/bin/poetry install --no-interaction --no-ansi --only main
# Kopiuj aplikację
COPY . .
# Etap produkcyjny
FROM python:3.12-slim AS production
# Instaluj zależności środowiska uruchomieniowego
RUN apt-get update && apt-get install -y \
libpq5 \
&& rm -rf /var/lib/apt/lists/*
# Stwórz użytkownika nie-root
RUN useradd -m -u 1001 -s /bin/bash app
# Kopiuj pakiety Python z buildera
COPY --from=builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
COPY --from=builder /usr/local/bin /usr/local/bin
# Ustaw katalog roboczy
WORKDIR /app
# Kopiuj pliki aplikacji
COPY --from=builder --chown=app:app /app .
# Przełącz na użytkownika nie-root
USER app
# Kontrola zdrowia
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD python -c "import requests; requests.get('http://localhost:8000/health')"
# Uruchom aplikację
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "4", "app:application"]
# Prompt AI
Ask: "Optymalizuj ten Dockerfile pod kątem rozmiaru:
- Używaj Alpine lub distroless jako bazę
- Usuń niepotrzebne pliki
- Łącz komendy RUN
- Używaj flag --no-cache
- Czyść cache menedżera pakietów"
# Zoptymalizowana aplikacja Go
# Etap budowy
FROM golang:1.21-alpine AS builder
RUN apk add --no-cache git ca-certificates
WORKDIR /app
# Cache'uj zależności
COPY go.mod go.sum ./
RUN go mod download
# Buduj binarny
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build \
-ldflags="-w -s" \
-o server ./cmd/server
# Etap końcowy - distroless
FROM gcr.io/distroless/static:nonroot
# Kopiuj binarny
COPY --from=builder /app/server /server
# Kopiuj certyfikaty dla HTTPS
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
# Uruchom jako nie-root
USER nonroot:nonroot
EXPOSE 8080
ENTRYPOINT ["/server"]
1.4
# Prompt AI: "Optymalizuj wydajność budowy Docker z cache'owaniem"
FROM node:20-alpine AS builder
# Montuj cache dla menedżerów pakietów
RUN --mount=type=cache,target=/root/.npm \
npm config set cache /root/.npm
WORKDIR /app
# Kopiuj tylko pliki pakietów najpierw
COPY package*.json ./
# Instaluj zależności z montowaniem cache
RUN --mount=type=cache,target=/root/.npm \
npm ci
# Kopiuj pliki źródłowe (zmiany nie unieważniają cache npm)
COPY . .
# Buduj z montowaniem cache
RUN --mount=type=cache,target=/app/.next/cache \
npm run build
# Etap produkcyjny
FROM node:20-alpine
WORKDIR /app
# Kopiuj zbudowaną aplikację
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public
EXPOSE 3000
CMD ["node", "server.js"]
# Prompt AI
Agent: "Stwórz Docker Compose dla mikrousług z:
- API gateway
- Wieloma usługami backend
- PostgreSQL i Redis
- Service discovery
- Kontrolami zdrowia
- Overrides dla rozwoju"
# docker-compose.yml
version: '3.9'
services:
# API Gateway
gateway:
build:
context: ./gateway
target: ${BUILD_TARGET:-production}
ports:
- "8080:8080"
environment:
- SERVICE_DISCOVERY_URL=http://consul:8500
- LOG_LEVEL=${LOG_LEVEL:-info}
depends_on:
consul:
condition: service_healthy
auth-service:
condition: service_healthy
product-service:
condition: service_healthy
networks:
- app-network
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:8080/health"]
interval: 30s
timeout: 3s
retries: 3
# Usługa uwierzytelniania
auth-service:
build:
context: ./services/auth
cache_from:
- ${REGISTRY}/auth-service:cache
environment:
- DATABASE_URL=postgresql://postgres:postgres@postgres:5432/auth_db
- REDIS_URL=redis://redis:6379
- JWT_SECRET=${JWT_SECRET}
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
networks:
- app-network
deploy:
replicas: 2
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3001/health"]
interval: 30s
timeout: 3s
retries: 3
# Usługa produktów
product-service:
build:
context: ./services/product
environment:
- DATABASE_URL=postgresql://postgres:postgres@postgres:5432/product_db
- CACHE_URL=redis://redis:6379
- S3_BUCKET=${S3_BUCKET}
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
networks:
- app-network
volumes:
- product-images:/app/uploads
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3002/health"]
interval: 30s
timeout: 3s
retries: 3
# PostgreSQL
postgres:
image: postgres:16-alpine
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=${DB_PASSWORD:-postgres}
- POSTGRES_MULTIPLE_DATABASES=auth_db,product_db
volumes:
- postgres-data:/var/lib/postgresql/data
- ./scripts/init-db.sh:/docker-entrypoint-initdb.d/init-db.sh
networks:
- app-network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
# Redis
redis:
image: redis:7-alpine
command: redis-server --requirepass ${REDIS_PASSWORD:-redis}
volumes:
- redis-data:/data
networks:
- app-network
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
# Service Discovery
consul:
image: consul:1.17
command: agent -server -bootstrap -ui -client=0.0.0.0
ports:
- "8500:8500"
networks:
- app-network
healthcheck:
test: ["CMD", "consul", "members"]
interval: 10s
timeout: 5s
retries: 5
networks:
app-network:
driver: bridge
volumes:
postgres-data:
redis-data:
product-images:
docker-compose.dev.yml
# Prompt AI: "Stwórz Docker Compose dla rozwoju z hot reload"
version: '3.9'
services:
# Frontend z hot reload
frontend:
build:
context: ./frontend
target: development
volumes:
- ./frontend:/app
- /app/node_modules
environment:
- NODE_ENV=development
- REACT_APP_API_URL=http://localhost:8080
ports:
- "3000:3000"
command: npm run dev
# Backend z trybem watch
backend:
build:
context: ./backend
target: development
volumes:
- ./backend:/app
- /app/node_modules
environment:
- NODE_ENV=development
- DEBUG=app:*
ports:
- "8080:8080"
- "9229:9229" # Debugger Node.js
command: npm run dev:debug
# Baza danych z inicjalizacją
postgres:
ports:
- "5432:5432"
volumes:
- ./db/init:/docker-entrypoint-initdb.d
- ./db/seeds:/seeds
# Mailhog do testowania email
mailhog:
image: mailhog/mailhog
ports:
- "1025:1025" # SMTP
- "8025:8025" # Web UI
networks:
- app-network
# Adminer do zarządzania bazą danych
adminer:
image: adminer
ports:
- "8081:8080"
networks:
- app-network
# Prompt AI
Agent: "Zabezpiecz ten kontener Docker z:
- Skanowaniem bezpieczeństwa
- Minimalną powierzchnią ataku
- Systemem plików tylko do odczytu
- Usuniętymi uprawnieniami
- Politykami bezpieczeństwa"
# Przykład zabezpieczonego kontenera
FROM node:20-alpine AS production
# Instaluj aktualizacje bezpieczeństwa
RUN apk update && apk upgrade && rm -rf /var/cache/apk/*
# Stwórz użytkownika nie-root
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
# Skonfiguruj katalog aplikacji z właściwymi uprawnieniami
WORKDIR /app
RUN chown nodejs:nodejs /app
# Kopiuj pliki aplikacji
COPY --chown=nodejs:nodejs package*.json ./
RUN npm ci --only=production && npm cache clean --force
COPY --chown=nodejs:nodejs . .
# Konfiguracje bezpieczeństwa
USER nodejs
# Usuń wszystkie capabilities
RUN apk add --no-cache libcap && \
setcap -r /usr/local/bin/node || true
# System plików tylko do odczytu
RUN chmod -R a-w /app
# Etykiety bezpieczeństwa
LABEL security.scan="enabled" \
security.updates="auto"
# Kontrola zdrowia z timeout
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD node healthcheck.js || exit 1
# Uruchom z ograniczonymi zasobami
CMD ["node", "--max-old-space-size=512", "index.js"]
docker-compose.secrets.yml
# Prompt AI: "Implementuj bezpieczną obsługę sekretów w Docker"
version: '3.9'
services:
app:
build: .
secrets:
- db_password
- api_key
- jwt_secret
environment:
- DB_PASSWORD_FILE=/run/secrets/db_password
- API_KEY_FILE=/run/secrets/api_key
- JWT_SECRET_FILE=/run/secrets/jwt_secret
# Używaj skryptu init do ładowania sekretów
entrypoint: ["/app/docker-entrypoint.sh"]
command: ["node", "index.js"]
secrets:
db_password:
file: ./secrets/db_password.txt
api_key:
file: ./secrets/api_key.txt
jwt_secret:
file: ./secrets/jwt_secret.txt
# docker-entrypoint.sh
#!/bin/sh
set -e
# Ładuj sekrety z plików do zmiennych środowiskowych
if [ -f "$DB_PASSWORD_FILE" ]; then
export DB_PASSWORD=$(cat "$DB_PASSWORD_FILE")
fi
if [ -f "$API_KEY_FILE" ]; then
export API_KEY=$(cat "$API_KEY_FILE")
fi
if [ -f "$JWT_SECRET_FILE" ]; then
export JWT_SECRET=$(cat "$JWT_SECRET_FILE")
fi
# Wykonaj główną komendę
exec "$@"
.devcontainer/devcontainer.json
// Prompt AI: "Stwórz devcontainer dla full-stack rozwoju"
{
"name": "Kontener deweloperski Full Stack",
"dockerComposeFile": "docker-compose.yml",
"service": "dev",
"workspaceFolder": "/workspace",
"features": {
"ghcr.io/devcontainers/features/common-utils:2": {},
"ghcr.io/devcontainers/features/git:1": {},
"ghcr.io/devcontainers/features/node:1": {
"version": "20"
},
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
},
"customizations": {
"vscode": {
"extensions": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"ms-azuretools.vscode-docker",
"github.copilot",
"continue.continue"
],
"settings": {
"terminal.integrated.defaultProfile.linux": "zsh",
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}
},
"forwardPorts": [3000, 8080, 5432],
"postCreateCommand": "npm install && npm run db:migrate",
"remoteUser": "vscode"
}
# Prompt AI
Agent: "Stwórz przepływ pracy GitHub Actions dla Docker:
- Budowa i testowanie
- Skanowanie bezpieczeństwa
- Push do rejestru
- Wdrażanie na staging
- Optymalizacja cache"
# .github/workflows/docker-ci.yml
name: Docker CI/CD
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-test:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
security-events: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=sha
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
VERSION=${{ github.sha }}
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
format: 'sarif'
output: 'trivy-results.sarif'
- name: Upload Trivy scan results
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: 'trivy-results.sarif'
- name: Run integration tests
run: |
docker compose -f docker-compose.test.yml up --abort-on-container-exit
docker compose -f docker-compose.test.yml down -v
deploy-staging:
needs: build-and-test
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- name: Deploy to staging
uses: digitalocean/action-doctl@v2
with:
token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
run: |
doctl kubernetes cluster kubeconfig save staging-cluster
kubectl set image deployment/app app=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
kubectl rollout status deployment/app

Wytyczne rozwoju Docker

  1. Cache’owanie warstw - Uporządkuj komendy Dockerfile od najrzadziej do najczęściej zmieniających się
  2. Budowy wieloetapowe - Oddziel zależności budowy od środowiska uruchomieniowego
  3. Bezpieczeństwo na pierwszym miejscu - Uruchamiaj jako nie-root, skanuj luki
  4. Rozmiar ma znaczenie - Używaj minimalnych obrazów podstawowych, usuń niepotrzebne pliki
  5. Kontrole zdrowia - Zawsze implementuj endpointy kontroli zdrowia
  6. Sekrety - Nigdy nie koduj sekretów na stałe, używaj właściwego zarządzania sekretami
# AI: "Dodaj możliwości debugowania do kontenera produkcyjnego"
FROM app:production AS debug
# Instaluj narzędzia debugowania
USER root
RUN apk add --no-cache \
curl \
wget \
netcat-openbsd \
bind-tools \
strace
USER nodejs
# Włącz debugowanie Node.js
ENV NODE_OPTIONS="--inspect=0.0.0.0:9229"
EXPOSE 9229
Okno terminala
# Prompt AI: "Debuguj problemy budowy Docker"
# Analizuj wydajność budowy
docker build --progress=plain --no-cache .
# Debuguj rozmiary warstw
docker history --human --format "table {{.CreatedBy}}\t{{.Size}}" image:tag
# Sprawdź cache budowy
docker buildx du --verbose
# Skanowanie bezpieczeństwa
docker scout cves image:tag
# Użycie zasobów
docker stats --no-stream