You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Docker Compose中通过单服务实现Nginx动态扩容反向代理?

问题描述

现有nginx.conf配置如下:

worker_processes auto;
events {
    worker_connections 1024;
}
http {
    upstream wordSearcherApi {
        least_conn;
        server api1:61370 max_fails=3 fail_timeout=30s;
        server api2:61370 max_fails=3 fail_timeout=30s;
        server api3:61370 max_fails=3 fail_timeout=30s;
    }
    server {
        listen 80;
        server_name 0.0.0.0;
        location / {
            proxy_pass http://wordSearcherApi;
        }
    }
}

想知道是否可以在docker-compose.yml中仅创建一个服务,当执行docker-compose --scale命令扩容时,让Nginx自动识别新增的服务实例并更新反向代理配置?

解答

当然可以实现,但原生Nginx本身不支持Docker服务的自动发现——它的upstream配置是静态的,启动后不会自动监听容器的变化。不过咱们有几个成熟的方案来解决这个问题:

方案1:使用docker-gen自动生成Nginx配置

docker-gen是一个轻量工具,能监听Docker容器的启停、扩容事件,根据预设模板自动更新Nginx配置,还能触发Nginx重新加载配置。具体步骤如下:

  • 把你的静态Nginx配置改成模板文件,用docker-gen的变量动态填充upstream节点
  • 在docker-compose里同时部署Nginx和docker-gen服务,让docker-gen盯着你的应用容器变化

给你一个简化的docker-compose示例:

version: '3'
services:
  word-searcher-api:
    image: your-api-image:latest
    # 只定义这一个服务,后续用scale命令扩容
    networks:
      - app-network

  nginx:
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - ./nginx.tmpl:/etc/docker-gen/templates/nginx.tmpl
      - ./nginx.conf:/etc/nginx/nginx.conf
    networks:
      - app-network
    depends_on:
      - docker-gen

  docker-gen:
    image: jwilder/docker-gen
    # 监听容器变化,更新配置后通知Nginx重载
    command: -notify-sighup nginx -watch /etc/docker-gen/templates/nginx.tmpl /etc/nginx/nginx.conf
    volumes:
      # 挂载Docker sock来获取容器事件
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - ./nginx.tmpl:/etc/docker-gen/templates/nginx.tmpl
      - ./nginx.conf:/etc/nginx/nginx.conf
    networks:
      - app-network

对应的nginx.tmpl模板示例:

worker_processes auto;
events {
    worker_connections 1024;
}
http {
    upstream wordSearcherApi {
        least_conn;
        {{ range $index, $container := .Containers }}
        {{ if eq $container.Labels "com.docker.compose.service=word-searcher-api" }}
        server {{ $container.IPAddress }}:61370 max_fails=3 fail_timeout=30s;
        {{ end }}
        {{ end }}
    }
    server {
        listen 80;
        server_name 0.0.0.0;
        location / {
            proxy_pass http://wordSearcherApi;
        }
    }
}

当你执行docker-compose up --scale word-searcher-api=5时,docker-gen会立刻检测到新增的容器,自动更新nginx.conf并发送信号让Nginx重载配置,完全不用手动修改upstream。

方案2:用Traefik替代Nginx(更省心)

Traefik是专为微服务打造的反向代理,原生支持Docker服务发现——只要你的应用容器和Traefik在同一个Docker网络里,它就能自动识别容器的启停、扩容,实时更新路由和负载均衡规则,连配置模板都不用写。

示例docker-compose配置:

version: '3'
services:
  word-searcher-api:
    image: your-api-image:latest
    labels:
      # 告诉Traefik这个服务的路由规则
      - "traefik.http.routers.word-searcher.rule=Path(`/`)"
      # 指定服务端口
      - "traefik.http.services.word-searcher.loadbalancer.server.port=61370"
      # 用least_conn负载均衡策略,和你原来的Nginx配置一致
      - "traefik.http.services.word-searcher.loadbalancer.strategy=leastconn"
    networks:
      - traefik-network

  traefik:
    image: traefik:v2.10
    command:
      - "--api.insecure=true" # 开放dashboard方便调试,生产环境建议关闭
      - "--providers.docker=true" # 开启Docker服务发现
      - "--providers.docker.exposedbydefault=false" # 只处理带Traefik标签的容器
      - "--entrypoints.web.address=:80" # 监听80端口
    ports:
      - "80:80"
      - "8080:8080" # Traefik dashboard端口,访问http://localhost:8080查看状态
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro # 挂载Docker sock获取容器信息
    networks:
      - traefik-network

networks:
  traefik-network:
    driver: bridge

扩容时执行docker-compose up --scale word-searcher-api=5,Traefik会自动把流量分配到所有新增的实例,全程无需手动干预。

方案3:Nginx Plus的DNS服务发现(付费方案)

如果你的团队正在使用付费版的Nginx Plus,它支持通过DNS实现服务发现——你可以把Docker服务名称当作DNS域名,Nginx Plus会自动解析这个域名对应的所有容器IP,动态更新upstream节点。不过这个方案需要购买商业授权,适合已经在使用Nginx Plus的场景。

总结

  • 不想换反向代理?用docker-gen是最常用的免费方案,能完美适配现有Nginx配置
  • 想简化运维?直接上Traefik,原生支持Docker服务发现,省去配置模板和额外工具的维护成本

内容的提问来源于stack exchange,提问作者Victor Soares

火山引擎 最新活动