第 19 篇、凌晨 2 点被喊起来扩容?Docker Compose 水平扩展+负载均衡,30分钟搞定,不用K8s

在这里插入图片描述

凌晨 2 点,部门群里:

“ @全员:测试压测把接口打崩了,单容器 QPS 到顶,用户访问直接 502,10 分钟内必须扩容恢复。”

你盯着屏幕,脑子一片空白。现在,真到要扩容的时候,可完全不知道从哪下手;

别慌,今天这篇文章,就带你用 Docker Compose 原生能力,30 分钟搞定水平扩展 + 负载均衡

不用 K8s 集群,不用付费 SLB。零基础复制粘贴就能跑通,连运维小白都能直接落地。

【本文适配 Docker Compose V2 官方最新版本】

本文是《Docker 实战》系列第 19篇,全系列文章覆盖 Docker 基础、容器、镜像、仓库、网络核心实战,再到数据持久化、Dockerfile、Docker Compose 全场景落地,全程保姆级实战教学。

文末还给大家准备了专属新手福利:我亲手整理的**《Docker Compose 生产级最佳实践手册》+ 《10 套开箱即用 Compose 配置文件》。**

先搞懂核心原理

很多新手搞不懂,为什么 Docker Compose 不用额外配置就能实现负载均衡?

核心就两个知识点,看完你就通透了。

1. 什么是水平扩展?

垂直扩展:给单容器加 CPU / 内存(相当于给电脑换更大的内存条),上限低、成本高,很容易触顶

水平扩展:增加服务的容器实例数(相当于多开几台电脑一起干活),弹性强、成本可控,也是本文要讲的核心能力

2. Docker Compose 负载均衡的底层逻辑:内置 DNS 服务发现

Docker Compose 会给同一个服务的所有容器,分配同一个服务名(比如 flask),内置的 DNS 服务器会把这个服务名,轮询解析到所有后端容器的 IP 上。

简单说:你只要访问服务名,Docker 会自动把请求分给不同的容器,天生就带负载均衡能力,不用额外装任何组件。

新手必踩的 8 个致命坑

坑 1:命令版本混用

错误写法:混用旧版docker-compose(带横杠)和新版docker compose(空格)

正确方案:统一用官方标准docker compose(空格),2023 年起 Docker 已彻底废弃 V1 旧版

⚠️ 风险说明:旧命令复制后直接报错,新手找不到问题根源,白白浪费时间

坑 2:scale 命令缺参数

错误写法docker compose up scale flask=3(少了--

正确方案docker compose up --scale 服务名=实例数 -d(比如--scale flask=3

⚠️ 风险说明:语法错误导致命令执行失败,以为是环境问题,实则只是少个符号

坑 3:清理命令太暴力

错误写法docker container rm -f $(docker container ps -aq)(删除所有容器)

正确方案:仅清理当前项目:docker compose down -v --rmi local

⚠️ 风险说明:会删除主机上所有容器(不管是不是当前项目的),新手执行直接 “翻车”,误删其他服务

坑 4:Nginx 缺 DNS 配置

错误写法:Nginx 直接写proxy_pass http://flask:5000;,不配置 DNS

正确方案:加 Docker 内置 DNS 配置:resolver 127.0.0.11 valid=5s;(5 秒刷新解析)

⚠️ 风险说明:Nginx 默认永久缓存 DNS,扩容新容器后不更新 IP,负载均衡完全不生效

很多朋友反馈:加了 resolver,负载均衡还是失效。

核心是没做动态上游 + 故障自动剔除,扩容新容器不识别、宕机还在转发请求,最终还是用户 502、线上背锅。

📌 【付费专属内容】给你 100 + 项目验证过的 Nginx 动态上游完整配置,复制即用,彻底解决这个生产死穴。

👉 这个方案的完整踩坑笔记和更新动态,我会同步更新,有需要可以文末找我。

坑 5:服务网络隔离错

错误写法:Nginx 和业务服务分属不同网络,业务服务没加双网络

正确方案:被 Nginx 访问的服务,需同时加入 “前端网络” 和 “后端网络”(比如 flask 加frontend-network+backend-network

⚠️ 风险说明:Nginx 访问不到业务容器,用户访问直接返回 502,排查半天找不到网络问题

坑 6:启动依赖没配条件

错误写法:只写depends_on: - flask,不配置启动条件

正确方案:补充健康检查依赖:depends_on: {flask: {condition: service_healthy}}

⚠️ 风险说明:只会等容器启动,不会等服务就绪(比如 flask 还没跑起来,Nginx 就启动了),直接返回 502

坑 7:没加健康检查

错误写法:服务配置里完全没有healthcheck字段

正确方案:给所有服务加健康检查,比如 flask:

healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost:5000"]
  interval: 5s
  timeout: 2s
  retries: 3

⚠️ 风险说明:Docker 会把请求转发到已挂掉的容器,用户频繁看到 502,还以为是负载均衡配置错了

**提醒大家:**基础健康检查,只能识别容器状态,没法自动重启、异常告警

凌晨容器崩了没人管,等用户投诉到老板那,你才被叫醒救火,太被动。

📌 【付费专属内容】给你生产级高可用自愈方案,自动重启 + 多平台告警配置,不用 24 小时人工盯守。

👉 这个方案的完整踩坑笔记和更新动态,我会同步更新,有需要可以文末找我。

坑 8:build 和 image 配置混淆

错误写法:以为buildimage二选一,写了image就删build

正确方案:同时写是 “构建后打标签”,必须保留build(比如构建 flask 镜像并标为flask-demo:latest

⚠️ 风险说明:没build字段会跳过镜像构建,直接拉取同名公共镜像,服务启动后完全不是自己要的功能

实战 1(极简版):内置 DNS 轮询,无 Nginx

关于 Docker 基础、容器、镜像、仓库、网络核心实战,再到数据持久化、Dockerfile、Docker Compose 全场景落地的更多高频坑,我都整理在了《Docker 实战》系列文章里。

关注 我「王二哥的技术笔记」:

  1. 查看往期全系列文章。
  2. 及时接收最新更新文章。

私信我,发送关键词【Compose】,即可直接领取全套资料。

适合内网测试、快速验证扩容效果,零额外依赖,复制就能跑。

步骤 1:环境准备

确保安装官方最新版本:

  • Docker Engine ≥ 20.10
  • Docker Compose V2

验证命令:

docker --version
docker compose version
步骤 2:项目结构与配置文件

创建项目目录,结构如下:

compose-scale-demo/
├── docker-compose.yml
└── flask/
    ├── Dockerfile
    └── app.py
  1. 先写flask/app.py(用来返回容器 ID,验证负载均衡效果)
from flask import Flask
from redis import Redis
import os

app = Flask(__name__)
redis = Redis(host=os.environ.get('REDIS_HOST', 'redis-server'), port=6379)

@app.route('/')
def hello():
    count = redis.incr('hits')
    hostname = os.uname()[1]  # 获取容器ID(容器的hostname就是容器ID)
    return f'Hello World! 我被访问了 {count} 次,当前处理容器ID:{hostname}\n'

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000, debug=True)
  1. 再写flask/Dockerfile(业务镜像构建文件)
FROM python:3.9.5-slim

RUN pip install flask redis && \
    groupadd -r flask && useradd -r -g flask flask && \
    mkdir /src && \
    chown -R flask:flask /src

USER flask

COPY app.py /src/app.py

WORKDIR /src

ENV FLASK=app.py REDIS_HOST=redis

EXPOSE 5000

CMD ["flask", "run", "-h", "0.0.0.0"]
  1. 核心docker-compose.yml

services:
  flask:
    build:
      context: ./flask
      dockerfile: Dockerfile
    image: flask-demo:latest
    environment:
      - REDIS_HOST=redis-server

  redis-server:
    image: redis:latest

  client:
    image: xiaopeng163/net-box:latest
    command: sh -c "while true; do sleep 3600; done;"

步骤 3:启动服务,验证基础状态
# 进入项目目录
cd compose-scale-demo

# 构建镜像+后台启动服务
docker compose up -d --build

# 查看服务状态,确保所有服务都是healthy状态
docker compose ps
步骤 4:水平扩展服务
# 把flask服务从1个实例,一键扩展到3个实例
docker compose up --scale flask=3 -d

# 再次查看状态,会看到3个flask容器,全部为healthy
docker compose ps
步骤 5:验证负载均衡效果

进入 client 容器,多次访问 flask 服务,观察返回的容器 ID:

# 进入client容器终端
docker compose exec client bash

# 多次访问,验证负载均衡
curl http://flask:5000

✅ 预期结果:每次返回的容器 ID 都不一样,说明 Docker 内置 DNS 已经实现了轮询负载均衡,水平扩展成功!

步骤 6:缩容服务
# 把flask服务一键缩容到1个实例
docker compose up --scale flask=1 -d

实战 2(Nginx 版):添加 Nginx 反向代理

适合对外暴露服务、需要高级负载策略的场景,适用于生产环境。

步骤 1:更新项目结构
compose-scale-demo/
├── docker-compose.yml
├── flask/
│   ├── Dockerfile
│   └── app.py
└── nginx/
    └── nginx.conf
步骤 2:更新 docker-compose.yml(添加 Nginx )
services:
  # 省略其他。。。
  
  # 添加Nginx反向代理:对外入口,七层负载均衡
  nginx:
    image: nginx:stable-alpine
    ports:
      - "8000:80"  # 对外暴露8000端口,可自行修改为80
    volumes:
      # 只读挂载配置文件,提升安全性
      - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro
    networks:
      - frontend-network
    # 启动依赖:等flask服务完全就绪,再启动nginx,避免启动时502
    depends_on:
      flask:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "wget", "-q", "--spider", "http://localhost:80/health"]
      interval: 10s
      timeout: 5s
      retries: 3

步骤 3:添加 Nginx 配置

nginx/nginx.conf

server {
  listen  80 default_server;
  location / {
    proxy_pass http://flask:5000;
  }
}
步骤 4:启动服务,验证效果
# 启动服务
docker compose up -d --build

# 一键扩展flask到3个实例
docker compose up --scale flask=3 -d

# 查看服务状态,确保所有服务healthy
docker compose ps

✅ 验证方式:

  1. 浏览器访问 http://你的服务器IP:8000,多次刷新,页面显示的容器 ID 会不断变化

  2. 本地多次执行 curl 命令验证:curl http://localhost:8000

  3. 查看 Nginx 日志,确认请求被分发到不同容器:docker compose logs -f nginx

现在,你能手动扩容了,但生产更新镜像 / 改代码,一重启就 502,用户流失、老板问责。

不用硬上复杂的 K8s,Docker Compose 原生就能搞定。

📌 【付费专属内容】带你 1 分钟实现零停机滚动更新,含完整配置 + 失败回滚兜底方案,中小项目直接落地。

👉 这个方案的完整踩坑笔记和更新动态,我会同步更新,有需要可以文末找我。

写在最后

新手专属福利

为了帮大家更快上手 Docker,我给大家整理了专属资料,都是我自己生产环境在用、新手能直接抄的实战内容:

  1. 《Docker Compose 生产级最佳实践》:包含了生产部署核心原则、官方标准做法、避坑红线,零基础也能直接落地
  2. Docker官方维护**《10套开箱即用Compose配置文件》**:覆盖 Python / NGINX / MySQL等主流技术栈,可直接复制到生产环境使用
  3. **《Docker 实战》**全系列避坑指南合集:覆盖网络、数据卷、镜像、编排全模块的 30 + 个新手高频坑,帮你少走半年弯路
资料领取方式:

私信我,发送关键词【Compose】,自动给你资料领取详情。

我会持续更新 Docker、云原生、Python 后端的实战干货,把我踩过的坑、总结的实战经验全部分享给你,帮你从入门到精通,少走弯路。

我们下期再见。

其他疑问

第 18 篇、凌晨 3 点还在排查 Docker 网络故障?Compose 容器通信玄学,90% 的坑都在这了

第 17 篇、凌晨 2 点还在更新 Docker 服务?Compose 越更越崩,90% 的坑都在这了

第 16 篇、90% Docker 新手都栽在这!Compose 镜像构建的 5 个致命坑,新手直接抄

第 15 篇、90% 的 Docker 新手都踩过的 8 个 Compose 坑!一文讲透核心逻辑,新手直接抄

Docker多容器环境,别瞎部署了!搞懂Compose,少走 90% 的弯路

相关内容我都给大家做好了,感兴趣的朋友来「我的主页」找一找,直接就可以看到。

欢迎关注 「王二哥的技术笔记」,每天分享「Docker」、「Python」、「FastAPI」、「Flask」有趣干货,千万不要错过!

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐