# Docker 容器化部署完整指南
Docker已經成為現代軟體開發和部署的標準工具。本文將帶你從零開始掌握Docker的核心概念和實戰應用。
## 1. Docker 基礎概念
### 什麼是Docker?
Docker是一個開源的容器化平台,允許開發者將應用程式和其依賴項打包到輕量級的容器中,確保在任何環境中都能一致運行。
### 核心概念
- **映像檔(Image)**:包含應用程式和運行環境的唯讀模板
- **容器(Container)**:映像檔的運行實例
- **Dockerfile**:定義映像檔內容的腳本
- **Registry**:儲存和分發映像檔的服務
## 2. Docker 安裝與設置
### 安裝Docker
bash
# Ubuntu/Debian
sudo apt-get update
sudo apt-get install docker.io
sudo systemctl start docker
sudo systemctl enable docker
# macOS
brew install --cask docker
# Windows
# 下載並安裝 Docker Desktop
### 驗證安裝
bash
docker --version
docker run hello-world
## 3. 基本Docker命令
### 映像檔管理
bash
# 搜尋映像檔
docker search nginx
# 拉取映像檔
docker pull nginx:latest
docker pull ubuntu:20.04
# 列出本地映像檔
docker images
docker image ls
# 刪除映像檔
docker rmi nginx:latest
docker image rm ubuntu:20.04
# 強制刪除映像檔
docker rmi -f nginx:latest
### 容器管理
bash
# 運行容器
docker run nginx
docker run -d nginx # 背景運行
docker run -p 8080:80 nginx # 端口映射
docker run -v /host/path:/container/path nginx # 卷掛載
docker run --name my-nginx nginx # 指定容器名稱
# 列出運行中的容器
docker ps
# 列出所有容器
docker ps -a
# 停止容器
docker stop container_id
docker stop container_name
# 啟動容器
docker start container_id
# 重啟容器
docker restart container_id
# 刪除容器
docker rm container_id
docker rm -f container_id # 強制刪除運行中的容器
# 查看容器日誌
docker logs container_id
docker logs -f container_id # 即時查看日誌
# 進入容器
docker exec -it container_id /bin/bash
docker exec -it container_id /bin/sh
## 4. Dockerfile 實戰
### 基本Dockerfile
dockerfile
# 使用官方Node.js映像檔作為基礎
FROM node:16-alpine
# 設置工作目錄
WORKDIR /app
# 複製package.json和package-lock.json
COPY package*.json ./
# 安裝依賴
RUN npm ci --only=production
# 複製應用程式程式碼
COPY . .
# 暴露端口
EXPOSE 3000
# 定義環境變數
ENV NODE_ENV=production
# 啟動應用程式
CMD ["npm", "start"]
### 多階段建置
dockerfile
# 建置階段
FROM node:16-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# 生產階段
FROM node:16-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY --from=builder /app/dist ./dist
EXPOSE 3000
CMD ["npm", "start"]
### 最佳實踐
dockerfile
# 使用特定版本標籤
FROM node:16.20-alpine
# 創建非root用戶
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nodejs -u 1001
# 設置工作目錄
WORKDIR /app
# 複製依賴檔案
COPY package*.json ./
# 安裝依賴
RUN npm ci --only=production && npm cache clean --force
# 切換到非root用戶
USER nodejs
# 複製應用程式
COPY --chown=nodejs:nodejs . .
# 健康檢查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
EXPOSE 3000
CMD ["npm", "start"]
## 5. 建置和運行自定義映像檔
### 建置映像檔
bash
# 基本建置
docker build -t my-app .
# 指定標籤
docker build -t my-app:v1.0.0 .
# 指定Dockerfile路徑
docker build -f Dockerfile.prod -t my-app:prod .
# 建置時傳遞參數
docker build --build-arg NODE_ENV=production -t my-app:prod .
### 運行自定義映像檔
bash
# 基本運行
docker run -d -p 3000:3000 my-app
# 指定環境變數
docker run -d -p 3000:3000 -e NODE_ENV=production my-app
# 掛載卷
docker run -d -p 3000:3000 -v /app/logs:/app/logs my-app
# 指定網路
docker run -d -p 3000:3000 --network my-network my-app
## 6. Docker Compose
### 基本docker-compose.yml
yaml
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://user:password@db:5432/mydb
depends_on:
- db
volumes:
- ./logs:/app/logs
networks:
- app-network
db:
image: postgres:13
environment:
- POSTGRES_DB=mydb
- POSTGRES_USER=user
- POSTGRES_PASSWORD=password
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- app-network
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
depends_on:
- app
networks:
- app-network
volumes:
postgres_data:
networks:
app-network:
driver: bridge
### 進階配置
yaml
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile
args:
NODE_ENV: production
image: my-app:latest
container_name: my-app
restart: unless-stopped
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://user:password@db:5432/mydb
- REDIS_URL=redis://redis:6379
env_file:
- .env
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
volumes:
- ./logs:/app/logs
- ./uploads:/app/uploads
networks:
- app-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
db:
image: postgres:13-alpine
container_name: postgres-db
restart: unless-stopped
environment:
- POSTGRES_DB=mydb
- POSTGRES_USER=user
- POSTGRES_PASSWORD=password
volumes:
- postgres_data:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
ports:
- "5432:5432"
networks:
- app-network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user -d mydb"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:6-alpine
container_name: redis-cache
restart: unless-stopped
command: redis-server --appendonly yes
volumes:
- redis_data:/data
ports:
- "6379:6379"
networks:
- app-network
nginx:
image: nginx:alpine
container_name: nginx-proxy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./ssl:/etc/nginx/ssl
depends_on:
- app
networks:
- app-network
volumes:
postgres_data:
driver: local
redis_data:
driver: local
networks:
app-network:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/16
### Compose命令
bash
# 啟動服務
docker-compose up
docker-compose up -d # 背景運行
# 停止服務
docker-compose down
# 重新建置並啟動
docker-compose up --build
# 查看服務狀態
docker-compose ps
# 查看服務日誌
docker-compose logs
docker-compose logs app
docker-compose logs -f app
# 執行命令
docker-compose exec app npm run test
docker-compose exec db psql -U user -d mydb
# 清理
docker-compose down -v # 刪除卷
docker-compose down --rmi all # 刪除映像檔
## 7. 網路和儲存
### Docker網路
bash
# 列出網路
docker network ls
# 創建網路
docker network create my-network
# 連接容器到網路
docker run --network my-network nginx
# 查看網路詳情
docker network inspect my-network
# 刪除網路
docker network rm my-network
### Docker卷
bash
# 創建卷
docker volume create my-volume
# 列出卷
docker volume ls
# 查看卷詳情
docker volume inspect my-volume
# 使用卷
docker run -v my-volume:/app/data nginx
# 刪除卷
docker volume rm my-volume
## 8. 生產環境部署
### 安全最佳實踐
dockerfile
# 使用最小基礎映像檔
FROM node:16-alpine
# 創建非root用戶
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
# 設置工作目錄
WORKDIR /app
# 複製依賴檔案
COPY package*.json ./
# 安裝依賴並清理快取
RUN npm ci --only=production && \
npm cache clean --force && \
rm -rf /tmp/*
# 切換到非root用戶
USER nodejs
# 複製應用程式
COPY --chown=nodejs:nodejs . .
# 設置檔案權限
RUN chmod -R 755 /app
# 健康檢查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
EXPOSE 3000
CMD ["npm", "start"]
### 多環境配置
yaml
# docker-compose.yml
version: '3.8'
services:
app:
build: .
environment:
- NODE_ENV=${NODE_ENV:-development}
env_file:
- .env.${NODE_ENV:-development}
# docker-compose.prod.yml
version: '3.8'
services:
app:
restart: unless-stopped
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
deploy:
resources:
limits:
cpus: '0.50'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M
### 監控和日誌
yaml# 添加監控服務
services:
prometheus:
image: prom/prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
networks:
- app-network
grafana:
image: grafana/grafana
ports:
- "3001:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
- grafana_data:/var/lib/grafana
networks:
- app-network
volumes:
grafana_data:
## 9. CI/CD整合
### GitHub Actions範例
yaml# .github/workflows/docker.yml
name: Docker Build and Deploy
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Login to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v2
with:
context: .
push: true
tags: |
my-app:latest
my-app:${{ github.sha }}
cache-from: type=registry,ref=my-app:buildcache
cache-to: type=registry,ref=my-app:buildcache,mode=max
## 10. 故障排除
### 常見問題
bash# 查看容器資源使用情況
docker stats
# 查看容器詳細資訊
docker inspect container_id
# 查看映像檔歷史
docker history image_name
# 清理未使用的資源
docker system prune -a
# 查看Docker守護程序日誌
sudo journalctl -u docker.service
# 重啟Docker服務
sudo systemctl restart docker
### 效能優化
dockerfile# 使用多階段建置減少映像檔大小
FROM node:16-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:16-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY --from=builder /app/dist ./dist
EXPOSE 3000
CMD ["npm", "start"]
# 使用.dockerignore減少建置上下文
node_modules
npm-debug.log
.git
.gitignore
README.md
.env
.nyc_output
coverage
## 總結
Docker容器化部署提供了:
1. **一致性**:確保開發、測試和生產環境的一致性
2. **可移植性**:在任何支援Docker的環境中運行
3. **隔離性**:應用程式和依賴項的完全隔離
4. **可擴展性**:輕鬆的水平擴展
5. **版本控制**:映像檔版本管理和回滾
6. **資源效率**:比虛擬機器更輕量級
掌握Docker技術,將大大提升應用程式的部署效率和可維護性。