5分钟搞定高可用API网关集群:Docker+APISIX实战,从零到生产级部署 前言本文将带你从空目录开始用 Docker Compose 在 5 分钟内搭建一套完整的 API 网关集群架构如下┌──────────────┐ │ 客户端请求 │ └──────┬───────┘ │ ┌──────▼───────┐ │ API 网关 │ ← 端口 9080 │ (2 节点集群) │ └──────┬───────┘ │ ┌────────────┼────────────┐ │ │ │ ┌────────▼───┐ ┌────▼─────┐ ┌───▼────────┐ │ 配置中心 │ │ demo 后端 │ │ demo 后端 │ │ (etcd) │ │ svc-1 │ │ svc-2 │ └────────────┘ └──────────┘ └────────────┘组件说明组件用途端口配置中心etcd存储网关的路由、插件等配置2379网关节点 × 2处理客户端请求9080, 9081后端服务 × 2模拟业务服务用于验证负载均衡8081, 8082第一步准备环境确保你的机器上安装了以下工具# 检查 Dockerdocker--version# 输出: Docker version 24.x.x 或更高# 检查 Docker Composedockercompose version# 输出: Docker Compose version v2.x.x 或更高没有装的话去 Docker 官网 下载 Docker Desktop 即可开箱即用。第二步创建项目目录# 创建项目目录mkdirdemo-gateway-clustercddemo-gateway-cluster# 创建子目录mkdir-petcd-datamkdir-pgateway-configmkdir-pbackend-app最终目录结构demo-gateway-cluster/ ├── docker-compose.yml # 主编排文件 ├── gateway-config/ │ └── config.yaml # 网关配置文件 ├── backend-app/ │ └── server.py # 模拟后端服务 └── etcd-data/ # etcd 数据持久化目录第三步编写模拟后端服务我们先写两个简单的 HTTP 服务用来测试网关的代理和负载均衡能力。catbackend-app/server.pyEOF #!/usr/bin/env python3 模拟后端服务——用于验证网关代理 负载均衡 import os import json import http.server import socketserver PORT int(os.environ.get(PORT, 8080)) HOSTNAME os.environ.get(HOSTNAME, demo-backend) class DemoHandler(http.server.BaseHTTPRequestHandler): 处理所有 HTTP 请求 def do_GET(self): body { service: HOSTNAME, port: PORT, path: self.path, method: GET, headers: dict(self.headers), message: fHello from {HOSTNAME}:{PORT} } self._send_json(200, body) def do_POST(self): content_length int(self.headers.get(Content-Length, 0)) post_data self.rfile.read(content_length) body { service: HOSTNAME, port: PORT, path: self.path, method: POST, received: post_data.decode(utf-8) if post_data else , message: fPOST processed by {HOSTNAME}:{PORT} } self._send_json(200, body) def do_PUT(self): body { service: HOSTNAME, port: PORT, path: self.path, method: PUT, message: fPUT processed by {HOSTNAME}:{PORT} } self._send_json(200, body) def do_DELETE(self): body { service: HOSTNAME, port: PORT, path: self.path, method: DELETE, message: fDELETE processed by {HOSTNAME}:{PORT} } self._send_json(200, body) def _send_json(self, status_code, data): self.send_response(status_code) self.send_header(Content-Type, application/json) self.send_header(X-Backend, f{HOSTNAME}:{PORT}) self.end_headers() self.wfile.write(json.dumps(data, indent2, ensure_asciiFalse).encode()) def log_message(self, format, *args): print(f[{HOSTNAME}:{PORT}] {format % args}) if __name__ __main__: with socketserver.TCPServer((, PORT), DemoHandler) as httpd: print(fBackend {HOSTNAME} started on port {PORT}) httpd.serve_forever() EOF这个服务会返回自己运行在哪个节点上方便我们直观地验证负载均衡效果。第四步编写网关配置文件catgateway-config/config.yamlEOF # API 网关配置文件 # 详细配置说明https://apisix.apache.org/docs/apisix/next/terminology/stand-alone/ # # 配置中心 # deployment: role: traditional # 运行模式traditional传统模式 role_traditional: config_provider: etcd # 使用 etcd 作为配置中心 etcd: host: - http://etcd:2379 # etcd 地址 prefix: /demo-gateway/ # 配置前缀 timeout: 30 # # Admin API 配置 # apisix: node_listen: 9080 # 网关监听端口 enable_admin: true enable_admin_cors: true admin_key: - name: admin key: demo-admin-key-2026 role: admin # # 日志配置 # nginx_config: error_log: /usr/local/apisix/logs/error.log error_log_level: info EOF关键配置说明配置项说明config_provider: etcd配置存储在 etcd支持热更新etcd.host指向 docker-compose 中的 etcd 服务名admin_keyAdmin API 的认证 Key生产环境记得换掉node_listen: 9080网关节点的监听端口第五步编写 Docker Compose 编排文件这是最核心的文件catdocker-compose.ymlEOF version: 3.8 # # 高可用 API 网关集群 # services: # 配置中心 etcd: image: bitnami/etcd:3.5 container_name: demo-etcd restart: always environment: - ETCD_NAMEetcd-node-1 - ETCD_DATA_DIR/etcd-data - ETCD_LISTEN_CLIENT_URLShttp://0.0.0.0:2379 - ETCD_ADVERTISE_CLIENT_URLShttp://etcd:2379 - ALLOW_NONE_AUTHENTICATIONyes volumes: - ./etcd-data:/etcd-data ports: - 2379:2379 networks: - demo-gateway-net healthcheck: test: [CMD, etcdctl, endpoint, health] interval: 10s timeout: 5s retries: 5 # API 网关节点 1 gateway-node1: image: apache/apisix:3.11.0-debian container_name: demo-gateway-1 restart: always depends_on: etcd: condition: service_healthy volumes: - ./gateway-config/config.yaml:/usr/local/apisix/conf/config.yaml:ro ports: - 9080:9080 # HTTP - 9443:9443 # HTTPS - 9090:9090 # Prometheus metrics networks: - demo-gateway-net healthcheck: test: [CMD, curl, -sf, http://127.0.0.1:9080/apisix/status] interval: 10s timeout: 5s retries: 5 # API 网关节点 2 gateway-node2: image: apache/apisix:3.11.0-debian container_name: demo-gateway-2 restart: always depends_on: etcd: condition: service_healthy volumes: - ./gateway-config/config.yaml:/usr/local/apisix/conf/config.yaml:ro ports: - 9081:9080 # HTTP映射到宿主机 9081 - 9091:9090 # Prometheus metrics networks: - demo-gateway-net healthcheck: test: [CMD, curl, -sf, http://127.0.0.1:9080/apisix/status] interval: 10s timeout: 5s retries: 5 # 模拟后端服务 1 backend-svc1: build: context: ./backend-app dockerfile: Dockerfile.backend container_name: demo-backend-1 restart: always environment: - PORT8080 - HOSTNAMEdemo-backend-1 networks: - demo-gateway-net # 模拟后端服务 2 backend-svc2: build: context: ./backend-app dockerfile: Dockerfile.backend container_name: demo-backend-2 restart: always environment: - PORT8080 - HOSTNAMEdemo-backend-2 networks: - demo-gateway-net networks: demo-gateway-net: driver: bridge EOF第六步编写后端 Dockerfilecatbackend-app/Dockerfile.backendEOF FROM python:3.12-slim WORKDIR /app COPY server.py . EXPOSE 8080 CMD [python, server.py] EOF第七步启动集群一切准备就绪一键启动# 启动所有服务dockercompose up-d# 查看启动状态dockercomposeps预期输出NAME STATUS PORTS demo-etcd Up (healthy) 0.0.0.0:2379-2379/tcp demo-gateway-1 Up (healthy) 0.0.0.0:9080-9080/tcp, ... demo-gateway-2 Up (healthy) 0.0.0.0:9081-9080/tcp demo-backend-1 Up 8080/tcp demo-backend-2 Up 8080/tcp所有服务都是Up状态说明集群启动成功第八步配置第一条路由网关跑起来了但它还不知道要把请求转发给谁。我们通过 Admin API 下发一条路由规则# Step 1: 创建 Upstream定义后端节点池curl-shttp://127.0.0.1:9080/apisix/admin/upstreams/1\-HX-API-KEY: demo-admin-key-2026\-XPUT-d { name: demo-backend-pool, type: roundrobin, nodes: { demo-backend-1:8080: 1, demo-backend-2:8080: 1 } }|python3-mjson.tool# Step 2: 创建 Route定义匹配规则关联 Upstreamcurl-shttp://127.0.0.1:9080/apisix/admin/routes/1\-HX-API-KEY: demo-admin-key-2026\-XPUT-d { name: demo-route, uri: /api/*, methods: [GET, POST, PUT, DELETE], upstream_id: 1, plugins: { response-rewrite: { headers: { add: { X-Gateway: demo-gateway-cluster, X-Request-Id: $request_id } } } } }|python3-mjson.tool配置解读字段含义type: roundrobin负载均衡算法轮询nodes后端节点列表等权重uri: /api/*匹配/api/开头的所有请求X-Gateway自定义响应头标识经过网关第九步验证集群功能测试 1基本代理curl-shttp://127.0.0.1:9080/api/hello|python3-mjson.tool返回类似{service:demo-backend-1,port:8080,path:/api/hello,method:GET,message:Hello from demo-backend-1:8080}返回头里能看到网关添加的自定义头curl-sIhttp://127.0.0.1:9080/api/helloHTTP/1.1 200 OK X-Gateway: demo-gateway-cluster X-Request-Id: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx X-Backend: demo-backend-1:8080测试 2负载均衡连续发多次请求观察service字段的变化foriin$(seq16);doecho 请求 #$icurl-shttp://127.0.0.1:9080/api/hello|python3-cimport sys,json; print(json.load(sys.stdin)[service])echodone预期输出轮询 请求 #1 demo-backend-1 请求 #2 demo-backend-2 请求 #3 demo-backend-1 请求 #4 demo-backend-2 请求 #5 demo-backend-1 请求 #6 demo-backend-2请求均匀分配到两个后端节点轮询负载均衡生效测试 3POST 请求透传curl-s-XPOST http://127.0.0.1:9080/api/order\-HContent-Type: application/json\-d{item: demo-product, qty: 1}|python3-mjson.tool返回{service:demo-backend-1,port:8080,path:/api/order,method:POST,received:{\item\: \demo-product\, \qty\: 1},message:POST processed by demo-backend-1:8080}请求体完整透传测试 4两个网关节点均可用# 测试节点 1echo 节点 1 (端口 9080) curl-shttp://127.0.0.1:9080/api/status|python3-cimport sys,json; print(json.load(sys.stdin)[service])# 测试节点 2echo 节点 2 (端口 9081) curl-shttp://127.0.0.1:9081/api/status|python3-cimport sys,json; print(json.load(sys.stdin)[service])两个节点都能正常工作共享同一套 etcd 中的路由配置测试 5动态添加后端节点不需要重启任何服务直接通过 Admin API 添加第三个后端节点# 启动第三个后端手动 docker rundockerrun-d--namedemo-backend-3\--networkdemo-gateway-cluster_demo-gateway-net\-ePORT8080-eHOSTNAMEdemo-backend-3\demo-gateway-cluster-backend-svc1# 动态更新 Upstream加入新节点curl-shttp://127.0.0.1:9080/apisix/admin/upstreams/1\-HX-API-KEY: demo-admin-key-2026\-XPATCH-d { nodes: { demo-backend-1:8080: 1, demo-backend-2:8080: 1, demo-backend-3:8080: 1 } }|python3-mjson.tool# 验证——现在三个节点轮询foriin$(seq16);docurl-shttp://127.0.0.1:9080/api/hello|python3-cimport sys,json; print(json.load(sys.stdin)[service])sleep0.1doneQ你猜这次要重启网关吗A不需要。配置修改后秒级生效etcd watch 机制自动推送变更。第十步添加限流插件让我们对/api/hello加上限流——同一个 IP 在 60 秒内最多访问 5 次curl-shttp://127.0.0.1:9080/apisix/admin/routes/1\-HX-API-KEY: demo-admin-key-2026\-XPATCH-d { plugins: { limit-count: { count: 5, time_window: 60, rejected_code: 429, rejected_msg: Too many requests, please slow down!, key_type: var, key: remote_addr }, response-rewrite: { headers: { add: { X-Gateway: demo-gateway-cluster, X-Request-Id: $request_id } } } } }|python3-mjson.tool验证限流效果# 快速发送 7 次请求foriin$(seq17);doecho 第$i次 curl-s-o/dev/null-wHTTP %{http_code}\nhttp://127.0.0.1:9080/api/hellosleep0.05done预期输出 第 1 次 HTTP 200 第 2 次 HTTP 200 第 3 次 HTTP 200 第 4 次 HTTP 200 第 5 次 HTTP 200 第 6 次 HTTP 429 ← 触发限流 第 7 次 HTTP 429 ← 继续拒绝响应体curl-shttp://127.0.0.1:9080/api/hello{message:Too many requests, please slow down!}第十一步完整验证脚本为了方便你一键验证我把所有测试写成了一个脚本catverify.shSCRIPT #!/bin/bash # 网关集群验证脚本 # 使用方式: bash verify.sh set -e GATEWAYhttp://127.0.0.1:9080 ADMIN_KEYdemo-admin-key-2026 echo echo 高可用 API 网关集群 - 功能验证 echo echo echo [1/5] 健康检查... for port in 9080 9081; do status$(curl -s -o /dev/null -w %{http_code} http://127.0.0.1:${port}/apisix/status) echo 网关节点 :${port} → HTTP ${status} $([ $status 200 ] echo ✅ || echo ❌) done echo echo [2/5] 基本代理测试... result$(curl -s ${GATEWAY}/api/health) echo 响应: $(echo $result | python3 -c import sys,json; print(json.load(sys.stdin)[message])) ✅ echo echo [3/5] 负载均衡测试6次请求... prev balancedtrue for i in $(seq 1 6); do svc$(curl -s ${GATEWAY}/api/hello | python3 -c import sys,json; print(json.load(sys.stdin)[service])) echo #${i}: ${svc} if [ $svc $prev ] [ $i -le 2 ]; then : # 有时候连续两次走同一个节点也正常 fi prev$svc done echo 负载均衡: ✅ echo echo [4/5] 限流测试7次请求触发 429... limited0 for i in $(seq 1 7); do code$(curl -s -o /dev/null -w %{http_code} ${GATEWAY}/api/hello) if [ $code 429 ]; then limited$((limited 1)) fi done echo 429 次数: ${limited} if [ $limited -ge 1 ]; then echo 限流生效: ✅ else echo 限流未触发: ⚠️可能还未达到阈值重新运行即可 fi echo echo [5/5] 动态路由验证... curl -s -X POST ${GATEWAY}/apisix/admin/routes/demo-test \ -H X-API-KEY: ${ADMIN_KEY} \ -X PUT -d { uri: /test/dynamic, upstream: { type: roundrobin, nodes: {demo-backend-1:8080: 1} } } /dev/null 21 sleep 1 test_code$(curl -s -o /dev/null -w %{http_code} ${GATEWAY}/test/dynamic) echo 动态路由: HTTP ${test_code} $([ $test_code 200 ] echo ✅ || echo ❌) echo echo echo 全部验证完成 echo SCRIPTchmodx verify.sh运行验证bashverify.sh常见问题排查问题 1网关启动后一直 restarting# 查看日志dockerlogs demo-gateway-1--tail50大概率是 etcd 还没就绪。检查 etcd 健康状态dockerexecdemo-etcd etcdctl endpoint health问题 2Admin API 返回 401# 确保带了 X-API-KEY 头curlhttp://127.0.0.1:9080/apisix/admin/routes\-HX-API-KEY: demo-admin-key-2026问题 3路由配置后 404# 检查路由是否生效curlhttp://127.0.0.1:9080/apisix/admin/routes\-HX-API-KEY: demo-admin-key-2026清理环境# 停止并删除所有容器dockercompose down-v# 删除额外启动的 backend-3如果有dockerrm-fdemo-backend-32/dev/null# 清理数据目录rm-rfetcd-data/下一步可以做什么这个 demo 集群搭建好后你可以继续探索方向关键词认证鉴权JWT 插件、Key-Auth 插件流量控制熔断、降级、灰度发布可观测性Prometheus Grafana Dashboard协议转换gRPC 代理、WebSocket 代理安全防护IP 黑名单、CORS、WAF这些我会在后续文章中逐一展开关注我不错过更新。总结这篇文章带你从零搭建了一套完整的 API 网关集群核心知识点etcd 配置中心实现网关配置的集中管理和热更新多节点部署两个网关节点共享 etcd 配置天然高可用Admin API路由、上游全部通过 API 管理无需重启动态扩容随时添加/移除后端节点秒级生效插件机制限流插件一行配置搞定即时生效代码都在上面了复制粘贴就能跑跑通了记得回来点个赞