7.4 Docker Compose 實戰:一鍵啟動 微服務 + Redis + MySQL + Nginx#
單個容器不夠:電商最小閉環要四個角色#
7.3 節把一個微服務裝進映像,但淘寶最小可用單元至少四件套:微服務(業務)+ MySQL(持久)+ Redis(快取)+ Nginx(入口)。逐個 docker run 再手工連網,順序錯一步就連不上。
Compose 的定位:用一個 YAML 聲明整個單機系統,up 一鍵拉起、down 一鍵銷毀。
flowchart TB
USER[用戶] --> NG[Nginx :80]
NG --> APP[shop-service :8080 x2]
APP --> DB[(MySQL :3306)]
APP --> CACHE[(Redis :6379)]完整 yaml:可直接執行的最小閉環#
# compose.yaml:與本書目錄同級存放,直接 docker compose up 可跑
services:
app:
build: ./shop-service
image: shop-service:v2
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://db:3306/shop?useSSL=false&serverTimezone=UTC
SPRING_DATASOURCE_USERNAME: shop
SPRING_DATASOURCE_PASSWORD: shop123
SPRING_DATA_REDIS_HOST: redis
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
networks: [shopnet]
db:
image: mysql:8.0
command: --default-authentication-plugin=mysql_native_password
environment:
MYSQL_DATABASE: shop
MYSQL_USER: shop
MYSQL_PASSWORD: shop123
MYSQL_ROOT_PASSWORD: root123
volumes: [db-data:/var/lib/mysql]
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
retries: 10
networks: [shopnet]
redis:
image: redis:7-alpine
command: redis-server --appendonly yes
volumes: [redis-data:/data]
networks: [shopnet]
nginx:
image: nginx:1.25-alpine
ports: ["80:80"]
volumes: ["./nginx.conf:/etc/nginx/conf.d/default.conf:ro"]
depends_on: [app]
networks: [shopnet]
volumes:
db-data:
redis-data:
networks:
shopnet:
# nginx.conf:與 compose.yaml 同目錄
upstream shop { server app:8080; }
server { listen 80; location / { proxy_pass http://shop; } }
操作步驟:從零到驗證#
# 1. 啟動(首次會自動 build app)
docker compose up -d --build
# 2. 看狀態與依賴順序
docker compose ps
docker compose logs -f app
# 3. 擴縮微服務實例
docker compose up -d --scale app=3
docker compose ps app
# 4. 驗證全鏈路
curl localhost/api/products
docker exec -it $(docker compose ps -q db) mysql -ushop -pshop123 -e "SHOW TABLES;" shop
docker exec -it $(docker compose ps -q redis) redis-cli ping
# 5. 銷毀(-v 連數據卷一起清,慎用於生產)
docker compose down -v
常見坑與排查#
| 現象 | 原因 | 修法 |
|---|---|---|
| app 連不上 db | 用了 localhost:3306,容器內 localhost 是自己 | 改用服務名 db:3306 |
| db 還沒好 app 就崩 | depends_on 預設只等啟動不等健康 | 加 condition: service_healthy |
| 改了代碼沒生效 | 忘了 --build,用的舊映像 | up -d --build |
| 端口衝突 | 本機 80 已被佔用 | 改 ports: ["8088:80"] |
# 除錯三板斧,可直接執行
docker compose config
docker network inspect $(basename $PWD)_shopnet
docker compose logs --tail=50 db
本章小結#
- Compose 是單機編排:一個 YAML 描述微服務 + 中介軟體 + 入口
- 服務名即 DNS:容器間用
db、redis、app互連,不用 IP depends_on + healthcheck保證啟動順序,volumes保證數據不丟- 全流程:
up -d --build→ps/logs→curl驗證 →down - 極限伏筆:Compose 只管單機,多機、故障自癒管不了(見 8.3 節)
想一想#
- 為什麼容器間要用服務名
db:3306而非localhost?畫出網路命名空間解釋。 depends_on不加健康檢查會有什麼競態?雙十一高併發啟動會放大什麼後果?- Compose 的
scale app=3與 Nginx 負載均衡,能替代 K8s 嗎?缺了哪三個能力?