前言 在現代軟體開發中,容器化技術 已成為不可或缺的核心技能。Docker 作為容器化的領導者,不僅解決了「在我的電腦上可以運行」的經典問題,更為微服務架構、CI/CD 流程、雲端部署奠定了基礎。而 Docker Compose 則進一步簡化了多容器應用的管理與編排。
本文將深入探討 Docker 與 Docker Compose 的核心概念、設定檔語法、實際應用場景,並提供完整的實務範例。無論您是剛接觸容器化技術的開發者,還是希望深化 DevOps 技能的工程師,都能從中獲得實用的知識與技巧。
Docker 核心概念深度解析 容器化技術的本質 容器化 是一種作業系統層級的虛擬化技術,它將應用程式及其相依性封裝在一個輕量級、可移植的容器中。與傳統虛擬機器相比,容器共享主機的核心,因此具有更高的效能和資源利用率。
graph TD
A[物理主機] --> B[主機作業系統]
B --> C[Docker Engine]
C --> D[容器 1]
C --> E[容器 2]
C --> F[容器 3]
D --> D1[應用程式 A]
D --> D2[函式庫與相依性]
E --> E1[應用程式 B]
E --> E2[函式庫與相依性]
F --> F1[應用程式 C]
F --> F2[函式庫與相依性]
Docker 架構組成 Docker 採用客戶端-伺服器架構 ,主要包含以下組件:
Docker Client :使用者介面,負責與 Docker Daemon 通訊
Docker Daemon (dockerd) :核心服務,管理映像檔、容器、網路和儲存
Docker Registry :映像檔倉庫,如 Docker Hub、私有 Registry
Docker Objects :映像檔 (Images)、容器 (Containers)、網路 (Networks)、儲存卷 (Volumes)
Dockerfile 深度剖析 Dockerfile 基本結構 Dockerfile 是定義映像檔建置過程的純文字腳本 ,每個指令都會在映像檔中建立一個新的層 (Layer)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 FROM golang:1.21 -alpine AS builderWORKDIR /app COPY go.mod go.sum ./ RUN go mod download COPY . . RUN CGO_ENABLED=0 GOOS=linux go build -o main . FROM alpine:latestRUN apk --no-cache add ca-certificates tzdata RUN adduser -D -s /bin/sh appuser WORKDIR /root/ COPY --from=builder /app/main . RUN chown appuser:appuser main USER appuserEXPOSE 8080 HEALTHCHECK --interval=30s --timeout =3s --start-period=5s --retries=3 \ CMD curl -f http://localhost:8080/health || exit 1 CMD ["./main" ]
Dockerfile 最佳實踐解析 1. 多階段建置 (Multi-stage Build) 多階段建置可以顯著減少最終映像檔大小,提高安全性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 FROM node:18 -alpine AS buildWORKDIR /app COPY package*.json ./ RUN npm ci --only=production FROM node:18 -alpine AS runtimeRUN addgroup -g 1001 -S nodejs RUN adduser -S nextjs -u 1001 WORKDIR /app COPY --from=build --chown =nextjs:nodejs /app . USER nextjsEXPOSE 3000 CMD ["npm" , "start" ]
2. 層級優化策略 合理安排指令順序,最大化快取效益:
1 2 3 4 5 6 7 8 9 10 11 12 FROM python:3.11 -slimCOPY . /app WORKDIR /app RUN pip install -r requirements.txt FROM python:3.11 -slimWORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt COPY . .
Docker Compose 詳細解析 Docker Compose 的核心價值 Docker Compose 解決了多容器應用編排 的複雜性問題。在微服務架構中,一個完整的應用可能包含:
Web 伺服器容器
資料庫容器
快取容器
訊息佇列容器
監控容器
手動管理這些容器的啟動順序、網路連接、資料持久化是極其複雜的,Docker Compose 提供了宣告式配置 來簡化這個過程。
Docker Compose 檔案結構深度分析 基本語法結構 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 version: '3.8' services: service-name: networks: network-name: volumes: volume-name: configs: config-name: secrets: secret-name:
完整的 Web 應用範例 以下是一個包含前端、後端、資料庫、快取的完整範例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 version: '3.8' services: frontend: build: context: ./frontend dockerfile: Dockerfile target: production ports: - "3000:3000" environment: - NODE_ENV=production - REACT_APP_API_URL=http://backend:8080 depends_on: backend: condition: service_healthy networks: - app-network restart: unless-stopped healthcheck: test: ["CMD" , "curl" , "-f" , "http://localhost:3000" ] interval: 30s timeout: 10s retries: 3 backend: build: context: ./backend dockerfile: Dockerfile ports: - "8080:8080" environment: - DB_HOST=postgres - DB_PORT=5432 - DB_NAME=appdb - DB_USER=postgres - DB_PASSWORD_FILE=/run/secrets/db_password - REDIS_URL=redis://redis:6379 depends_on: postgres: condition: service_healthy redis: condition: service_started networks: - app-network - db-network secrets: - db_password restart: unless-stopped healthcheck: test: ["CMD" , "curl" , "-f" , "http://localhost:8080/health" ] interval: 30s timeout: 5s retries: 3 start_period: 10s postgres: image: postgres:15-alpine environment: - POSTGRES_DB=appdb - POSTGRES_USER=postgres - POSTGRES_PASSWORD_FILE=/run/secrets/db_password volumes: - postgres_data:/var/lib/postgresql/data - ./database/init.sql:/docker-entrypoint-initdb.d/init.sql:ro networks: - db-network secrets: - db_password restart: unless-stopped healthcheck: test: ["CMD-SHELL" , "pg_isready -U postgres" ] interval: 10s timeout: 5s retries: 5 redis: image: redis:7-alpine command: redis-server --requirepass myredispassword volumes: - redis_data:/data - ./redis/redis.conf:/usr/local/etc/redis/redis.conf:ro networks: - app-network restart: unless-stopped healthcheck: test: ["CMD" , "redis-cli" , "ping" ] interval: 10s timeout: 3s retries: 3 nginx: image: nginx:alpine ports: - "80:80" - "443:443" volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro - ./nginx/ssl:/etc/nginx/ssl:ro - static_files:/var/www/static:ro depends_on: - frontend - backend networks: - app-network restart: unless-stopped prometheus: image: prom/prometheus:latest ports: - "9090:9090" volumes: - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro - prometheus_data:/prometheus command: - '--config.file=/etc/prometheus/prometheus.yml' - '--storage.tsdb.path=/prometheus' - '--web.console.libraries=/etc/prometheus/console_libraries' - '--web.console.templates=/etc/prometheus/consoles' networks: - monitoring-network - app-network restart: unless-stopped elasticsearch: image: elasticsearch:8.8.0 environment: - discovery.type=single-node - "ES_JAVA_OPTS=-Xms512m -Xmx512m" - xpack.security.enabled=false volumes: - elasticsearch_data:/usr/share/elasticsearch/data networks: - elk-network restart: unless-stopped logstash: image: logstash:8.8.0 volumes: - ./elk/logstash/pipeline:/usr/share/logstash/pipeline:ro - ./elk/logstash/config:/usr/share/logstash/config:ro depends_on: - elasticsearch networks: - elk-network - app-network restart: unless-stopped kibana: image: kibana:8.8.0 ports: - "5601:5601" environment: - ELASTICSEARCH_HOSTS=http://elasticsearch:9200 depends_on: - elasticsearch networks: - elk-network restart: unless-stopped networks: app-network: driver: bridge ipam: config: - subnet: 172.20 .0 .0 /16 db-network: driver: bridge internal: true monitoring-network: driver: bridge elk-network: driver: bridge volumes: postgres_data: driver: local redis_data: driver: local static_files: driver: local prometheus_data: driver: local elasticsearch_data: driver: local secrets: db_password: file: ./secrets/db_password.txt
說明重點 :
每個服務都明確標註用途與核心設定。
使用 depends_on
與 healthcheck
確保服務啟動順序與健康狀態。
透過多網路與 internal: true
實現網路隔離,提升安全性。
密鑰與敏感資訊採用 Docker Secrets 管理,避免硬編碼。
所有資料持久化皆透過 volume 管理,確保資料安全。
監控與日誌聚合(Prometheus、ELK)納入同一編排,便於一站式運維。
1. 環境變數管理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 services: app: environment: - NODE_ENV=production - DB_HOST=localhost services: app: env_file: - .env - .env.production services: app: environment: - DB_PASSWORD_FILE=/run/secrets/db_password
2. 依賴關係與健康檢查 1 2 3 4 5 6 7 8 9 10 11 12 13 14 services: backend: depends_on: database: condition: service_healthy restart: true database: healthcheck: test: ["CMD-SHELL" , "pg_isready -U postgres" ] interval: 10s timeout: 5s retries: 5 start_period: 30s
3. 資源限制與約束 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 services: app: deploy: resources: limits: cpus: '2.0' memory: 1G reservations: cpus: '0.5' memory: 512M restart_policy: condition: on-failure delay: 5s max_attempts: 3 window: 120s
實際應用場景深度分析 場景一:微服務開發環境 在微服務架構開發中,開發者需要同時運行多個服務:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 version: '3.8' services: api-gateway: build: ./api-gateway ports: - "8080:8080" environment: - USER_SERVICE_URL=http://user-service:3001 - ORDER_SERVICE_URL=http://order-service:3002 - PAYMENT_SERVICE_URL=http://payment-service:3003# 付款服務 API 位址 depends_on: - user-service - order-service - payment-service user-service: build: ./services/user-service environment: - DB_HOST=user-db - REDIS_URL=redis://redis:6379 depends_on: - user-db - redis order-service: build: ./services/order-service environment: - DB_HOST=order-db - KAFKA_BROKERS=kafka:9092 depends_on: - order-db - kafka payment-service: build: ./services/payment-service environment: - DB_HOST=payment-db - KAFKA_BROKERS=kafka:9092 depends_on: - payment-db - kafka user-db: image: postgres:15 environment: POSTGRES_DB: users POSTGRES_USER: postgres POSTGRES_PASSWORD: password volumes: - user_db_data:/var/lib/postgresql/data order-db: image: postgres:15 environment: POSTGRES_DB: orders POSTGRES_USER: postgres POSTGRES_PASSWORD: password volumes: - order_db_data:/var/lib/postgresql/data payment-db: image: postgres:15 environment: POSTGRES_DB: payments POSTGRES_USER: postgres POSTGRES_PASSWORD: password volumes: - payment_db_data:/var/lib/postgresql/data kafka: image: confluentinc/cp-kafka:latest environment: KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092# 對外宣告的連接資訊 KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 depends_on: - zookeeper zookeeper: image: confluentinc/cp-zookeeper:latest environment: ZOOKEEPER_CLIENT_PORT: 2181 redis: image: redis:alpine volumes: - redis_data:/data volumes: user_db_data: order_db_data: payment_db_data:# 付款資料庫儲存卷 redis_data:
Docker Compose 在持續整合中的應用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 version: '3.8' services: app-test: build: context: . target: test environment: - NODE_ENV=test - DB_HOST=test-db - REDIS_URL=redis://test-redis:6379 depends_on: test-db: condition: service_healthy test-redis: condition: service_started volumes: - ./coverage:/app/coverage command: npm run test:ci test-db: image: postgres:15-alpine environment: POSTGRES_DB: test_db POSTGRES_USER: test_user POSTGRES_PASSWORD: test_password healthcheck: test: ["CMD-SHELL" , "pg_isready -U test_user" ] interval: 5s timeout: 5s retries: 5 tmpfs: - /var/lib/postgresql/data test-redis: image: redis:alpine tmpfs: - /data e2e-tests: build: context: ./e2e environment: - APP_URL=http://app-test:3000 depends_on: app-test: condition: service_healthy volumes: - ./e2e/reports:/app/reports command: npm run test:e2e
生產環境的 Docker Compose 配置注重安全性和穩定性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 version: '3.8' services: app: image: myapp:${APP_VERSION} deploy: replicas: 3 update_config: parallelism: 1 delay: 10s order: start-first restart_policy: condition: on-failure delay: 5s max_attempts: 3 resources: limits: cpus: '1.0' memory: 512M reservations: cpus: '0.5' memory: 256M environment: - NODE_ENV=production - DB_HOST=db - DB_PASSWORD_FILE=/run/secrets/db_password secrets: - db_password networks: - app-network logging: driver: "json-file" options: max-size: "10m" max-file: "3" nginx: image: nginx:alpine ports: - "80:80" - "443:443" volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro - ./ssl:/etc/nginx/ssl:ro - static_files:/var/www/static:ro depends_on: - app networks: - app-network deploy: restart_policy: condition: on-failure db: image: postgres:15-alpine environment: POSTGRES_DB: ${DB_NAME} POSTGRES_USER: ${DB_USER} POSTGRES_PASSWORD_FILE: /run/secrets/db_password volumes: - db_data:/var/lib/postgresql/data - ./backups:/backups secrets: - db_password networks: - db-network deploy: restart_policy: condition: on-failure placement: constraints: - node.role == manager node-exporter: image: prom/node-exporter:latest volumes: - /proc:/host/proc:ro - /sys:/host/sys:ro - /:/rootfs:ro command: - '--path.procfs=/host/proc' - '--path.sysfs=/host/sys' - '--collector.filesystem.ignored-mount-points=^/(sys|proc|dev|host|etc)($$|/)' networks: - monitoring-network deploy: mode: global networks: app-network: driver: overlay attachable: true db-network: driver: overlay internal: true monitoring-network: driver: overlay volumes: db_data: driver: local static_files: driver: local secrets: db_password: external: true configs: nginx_config: external: true
Docker Compose 常用指令與最佳實踐 基本操作指令 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 docker-compose up -d docker-compose up -d nginx postgres docker-compose down docker-compose down -v --remove-orphans docker-compose up -d --build docker-compose ps docker-compose logs -f backend docker-compose exec backend bash docker-compose up -d --scale backend=3 docker-compose config docker-compose build
環境管理最佳實踐 1. 多環境配置策略 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 project/ ├── docker-compose.yml ├── docker-compose.dev.yml ├── docker-compose.test.yml ├── docker-compose.prod.yml ├── .env.dev ├── .env.test └── .env.prod docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d docker-compose --env-file .env.dev up -d
2. 開發環境優化配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 version: '3.8' services: backend: build: target: development volumes: - ./src:/app/src:ro - ./node_modules:/app/node_modules environment: - NODE_ENV=development - DEBUG=app:* ports: - "9229:9229" frontend: volumes: - ./frontend/src:/app/src:ro - ./frontend/public:/app/public:ro environment: - FAST_REFRESH=true
效能優化與安全性考量 映像檔優化策略 1. 基礎映像檔選擇 1 2 3 4 5 6 7 8 9 10 11 12 FROM ubuntu:22.04 FROM alpine:3.18 FROM gcr.io/distroless/java17-debian11FROM golang:1.21 -alpine AS builderFROM scratch
2. 層級快取優化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 FROM node:18 -alpineRUN apk add --no-cache \ ca-certificates \ tzdata \ && rm -rf /var/cache/apk/* WORKDIR /app COPY package*.json ./ RUN npm ci --only=production && npm cache clean --force COPY . . RUN npm run build CMD ["npm" , "start" ]
安全性最佳實踐 1. 非 Root 使用者執行 1 2 3 4 5 6 7 8 9 10 11 12 RUN addgroup -g 1001 -S nodejs \ && adduser -S nextjs -u 1001 COPY --chown =nextjs:nodejs . . USER nextjsEXPOSE 3000
2. 密鑰管理 1 2 3 4 5 6 7 8 9 10 11 12 13 services: app: environment: - DB_PASSWORD_FILE=/run/secrets/db_password secrets: - db_password secrets: db_password: file: ./secrets/db_password.txt
3. 網路隔離 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 networks: frontend-network: driver: bridge backend-network: driver: bridge internal: true database-network: driver: bridge internal: true services: frontend: networks: - frontend-network - backend-network backend: networks: - backend-network - database-network database: networks: - database-network
監控與日誌管理 容器健康檢查 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 services: app: healthcheck: test: ["CMD-SHELL" , "curl -f http://localhost:3000/health || exit 1" ] interval: 30s timeout: 10s retries: 3 start_period: 60s database: healthcheck: test: ["CMD-SHELL" , "pg_isready -U $POSTGRES_USER -d $POSTGRES_DB" ] interval: 10s timeout: 5s retries: 5
日誌聚合配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 version: '3.8' services: app: logging: driver: "json-file" options: max-size: "10m" max-file: "3" labels: "service=app" logging: driver: fluentd options: fluentd-address: localhost:24224 tag: app.logs fluentd: image: fluentd:v1.16-1 volumes: - ./fluentd/conf:/fluentd/etc - ./logs:/var/log/fluentd ports: - "24224:24224" - "24224:24224/udp" elasticsearch: image: elasticsearch:8.8.0 environment: - discovery.type=single-node - "ES_JAVA_OPTS=-Xms512m -Xmx512m" volumes: - elasticsearch_data:/usr/share/elasticsearch/data kibana: image: kibana:8.8.0 ports: - "5601:5601" environment: - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
故障排除與偵錯技巧 常見問題診斷 1. 服務啟動失敗 1 2 3 4 5 6 7 8 9 10 11 12 13 14 docker-compose logs service-name docker-compose ps docker-compose exec service-name sh docker-compose exec service-name ping other-service docker-compose exec service-name env
2. 網路連接問題 1 2 3 4 5 6 7 8 9 10 11 docker network ls docker network inspect project_default docker-compose exec frontend wget -qO- http://backend:8080/health docker-compose port frontend 3000
3. 儲存卷問題 1 2 3 4 5 6 7 8 9 10 11 docker volume ls docker volume inspect project_db_data docker run --rm -v project_db_data:/data -v $(pwd ):/backup alpine tar czf /backup/backup.tar.gz /data docker run --rm -v project_db_data:/data -v $(pwd ):/backup alpine tar xzf /backup/backup.tar.gz -C /
效能監控指令 1 2 3 4 5 6 7 8 9 10 11 docker stats docker-compose exec backend top docker-compose exec backend df -h docker-compose exec backend cat /proc/meminfo
總結與最佳實踐建議 核心概念回顧
容器化思維 :將應用程式及其環境封裝為可移植的容器
多階段建置 :優化映像檔大小,分離建置與運行環境
服務編排 :使用 Docker Compose 管理複雜的多容器應用
配置管理 :合理使用環境變數、密鑰和配置檔案
網路隔離 :通過自定義網路提高安全性
資料持久化 :正確使用儲存卷管理應用資料
開發流程建議 1. 專案初始化階段
設計合理的目錄結構
建立多環境配置檔案
配置基礎的健康檢查和日誌
建立開發環境的熱重載機制
2. 開發階段最佳實踐
使用 .dockerignore
優化建置上下文
實施層級快取策略
配置適當的資源限制
建立統一的錯誤處理和日誌格式
3. 測試與CI/CD整合
建立專用的測試環境配置
實施自動化測試流程
配置健康檢查和服務依賴
建立映像檔版本控制策略
4. 生產部署考量
實施安全性最佳實踐
配置監控和告警機制
建立備份和災難恢復流程
規劃容量和擴展策略
進階學習方向 掌握 Docker 和 Docker Compose 的基礎後,建議深入學習:
容器編排平台 :Kubernetes、Docker Swarm
服務網格 :Istio、Linkerd
監控方案 :Prometheus + Grafana、ELK Stack
安全掃描 :Trivy、Clair
映像檔倉庫 :Harbor、Nexus
GitOps 流程 :ArgoCD、FluxCD
Docker 容器化技術已成為現代軟體開發的基石,熟練掌握 Docker 和 Docker Compose 不僅能提高開發效率,更是邁向 DevOps 和雲端原生架構的重要一步。透過不斷實踐和探索,您將能夠建構更穩定、可擴展、安全的容器化應用系統。
本文涵蓋了 Docker 和 Docker Compose 的核心概念與實際應用,希望能幫助您在容器化技術的學習路上更進一步。如有任何問題或建議,歡迎在評論區交流討論!