APISIX 3.12网关部署实战:动态路由、插件配置与Nginx迁移避坑
很多人第一次接触 APISIX基本都是在被 Nginx 的配置文件反复折磨之后。业务一多location 块拆了又拆reload 动作一天要做七八次每次点回车都提心吊胆怕把线上连接打断了。我也是这么过来的后来把服务网关整体切到 APISIX 3.12路由、上游、插件全部通过 API 动态修改发布新服务再也不用碰配置文件这才真正体会到什么叫“网关本该如此”。这篇文章不聊虚的就从零开始把 APISIX 3.12 的安装、依赖准备、核心配置、常用插件以及我实际部署中踩过的坑全部按照操作顺序写出来。全程保姆级适合刚接触 API 网关的开发和运维同学也适合那些正在 Nginx 和 APISIX 之间犹豫的人参考。文章里所有命令我都按 3.12 版本实测过照着敲就行。1. API网关为什么值得换APISIX的架构与选型思路1.1 网关要解决的问题从一次发布事故说起我印象很深的一次事故发生在某次凌晨上线。当时后端新增了一个服务需要在前置 Nginx 里加一条 location 转发规则。配置写好之后执行nginx -t语法没问题于是 reload。结果流量一刷新线上出现大量 502。排查了半天才发现新加的 location 和一个老的泛匹配规则冲突reload 之后老的规则被覆盖了请求全都打到不存在的 upstream 上。这不是 Nginx 本身不好而是它作为静态配置型网关在面对频繁变更时天然处于劣势。路由规则一旦多了人工维护 location 的优先级和顺序就是一场噩梦。而 API 网关要解决的核心问题恰恰就是“让路由和策略可以像数据库一样被动态查询和更新”同时把鉴权、限流、灰度、日志这些横切能力统一收口到入口层不让每个业务服务自己重复实现。APISIX 在这一点上做得非常彻底。它把控制面和数据面拆开控制面是 Admin API任何路由变更都通过 HTTP 接口提交写入 etcd数据面是 OpenResty 集群实时监听 etcd 的变化然后更新各自内存中的路由表。整个过程不需要 reload也没有连接中断。1.2 Nginx配置方式 vs APISIX动态配置把两者放在一起对比思路差异就很明显了。Nginx 的核心单位是 server 和 location所有规则写死在.conf 文件里改完必须 reload而且 reload 不是绝对无损的APISIX 的核心单位是 Route、Upstream、Service 和 Plugin全部以 JSON 结构存在 etcd 里通过 REST API 增删改查改完毫秒级生效。举一个最直观的例子。Nginx 里给某个接口加限流要写 limit_req_zone 和 limit_req 指令还要确认作用域。APISIX 只需要给对应 Route 绑一个 limit-req 插件{ plugins: { limit-req: { rate: 1, burst: 2, rejected_code: 429, key_type: var, key: remote_addr } } }这个 JSON 直接通过 PUT 请求丢给 Admin API 就生效了。想要临时放开再 PUT 一次把插件删掉就行。而且所有历史配置都存在 etcd可以随时回滚这在 Nginx 时代是很难做到的。1.3 APISIX 3.12版本选型要点选 3.12 而不是更早版本主要是两个原因。第一3.x 系列从 3.0 开始重构了配置结构etcd配置挪到了deployment.etcd下面很多老教程里的写法已经不适用了。网上大量文章讲 2.x 版本的配置直接抄到 3.12 上大概率启动报错。第二3.12 经过多个小版本迭代稳定性比 3.0、3.5 这些早期版本好很多插件生态也齐全key-auth、limit-req、cors、jwt-auth 这些常用插件都是默认内置的不需要额外安装。如果你需要 gRPC 代理、自定义负载均衡、多语言插件Java、Go 写的外部插件3.12 也都支持。对于大多数中小团队这个版本作为统一流量入口完全够用。提示不是所有标着“APISIX 教程”的文章都能直接照搬尤其要注意里面配置文件里有没有etcd:这种顶层字段。3.x 版本必须写成deployment.etcd。这个细节我后文还会再强调。2. 装之前先盘清楚环境依赖、etcd与端口规划2.1 系统与硬件要求APISIX 本身是基于 OpenResty 的对 Linux 系统很友好。我这边测试环境和生产环境分别用到了 CentOS 7.9 和 Ubuntu 22.04都没问题。硬件上最低 1 核 2G但这只够本地学习如果承载真实流量建议 2 核 4G 起步磁盘 20G 以上。毕竟 APISIX 要用到 OpenResty 的共享内存做缓存内存太紧张会影响路由匹配性能。系统层面注意两点。第一需要开放必要的端口后面我会讲具体是哪些。第二如果你用的是 CentOS 7内核版本低没关系但一定要确保iptables或者firewalld不会拦截内部端口很多部署失败其实是防火墙把 etcd 或 Admin API 的端口挡了。2.2 etcdAPISIX的配置核心etcd 在 APISIX 里的角色简单说就是“配置总仓”。所有路由、上游、插件、消费者配置都写在 etcd 里APISIX 数据面节点通过长连接监听 etcd 的变更推送。所以 etcd 不装好APISIX 根本起不来这不是依赖问题是架构问题。单机学习环境装一个 etcd 节点就够了生产环境强烈建议 3 节点起步做高可用。APISIX 的deployment.etcd.host配置支持多个地址它会自动 failoverdeployment: etcd: host: - http://10.0.0.11:2379 - http://10.0.0.12:2379 - http://10.0.0.13:2379etcd 的安装方式很多CentOS 上如果 yum 源里有 etcd 可以直接装没有的话用二进制包最省事。我习惯的做法是下载官方 release 包解压后用 systemd 托管ETCD_VERv3.5.15 wget https://github.com/etcd-io/etcd/releases/download/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz tar -xzf etcd-${ETCD_VER}-linux-amd64.tar.gz sudo mv etcd-${ETCD_VER}-linux-amd64/etcd /usr/local/bin/ sudo mv etcd-${ETCD_VER}-linux-amd64/etcdctl /usr/local/bin/然后写一个 systemd unit 文件放在/etc/systemd/system/etcd.service[Unit] Descriptionetcd Afternetwork.target [Service] Typesimple ExecStart/usr/local/bin/etcd \ --name etcd0 \ --data-dir /var/lib/etcd \ --listen-client-urls http://0.0.0.0:2379 \ --advertise-client-urls http://127.0.0.1:2379 \ --listen-peer-urls http://0.0.0.0:2380 \ --initial-advertise-peer-urls http://127.0.0.1:2380 \ --initial-cluster etcd0http://127.0.0.1:2380 Restartalways RestartSec5 [Install] WantedBymulti-user.target启动验证sudo systemctl daemon-reload sudo systemctl enable etcd sudo systemctl start etcd etcdctl --endpointshttp://127.0.0.1:2379 endpoint health看到healthy输出说明 etcd 就绪了。如果这一步没做好后面 APISIX 启动一定会报failed to fetch data from etcd。2.3 端口规划与访问控制APISIX 3.12 涉及四个核心端口我列一个表建议你截图存下来端口用途暴露范围建议9080网关数据面 HTTP 入口对外网开放9443网关数据面 HTTPS 入口对外网开放9180Admin API 控制面仅内网/本机2379etcd 客户端端口仅内网很多人在这一步犯的错误是把 9180 和 2379 直接暴露到公网。Admin API 如果暴露出去等于把网关的“遥控器”送给了别人任何人都能创建路由、删配置etcd 暴露出去则更危险所有路由明文配置直接裸奔。所以我无论在 Docker 还是 RPM 部署里都会严格要求这两个端口只绑内网 IP或者用防火墙做来源 IP 白名单。3. 三种安装路线实测Docker、RPM与源码编译3.1 方式一Docker Compose一键拉起推荐测试如果只是想快速体验 APISIX或者本地开发要搭一套环境Docker Compose 是最省事的方案。新建一个apisix-docker目录里面放两个文件。首先是config.yaml这是 APISIX 的核心配置我只保留最关键的部分apisix: node_listen: 9080 admin_api: listen: - ip: 0.0.0.0 port: 9180 admin_key: - name: admin key: change-me-to-random-secret role: admin deployment: role: traditional role_traditional: config_provider: etcd etcd: host: - http://etcd:2379然后是docker-compose.ymlversion: 3.8 services: etcd: image: bitnami/etcd:3.5 container_name: etcd environment: - ALLOW_NONE_AUTHENTICATIONyes - ETCD_ADVERTISE_CLIENT_URLShttp://etcd:2379 - ETCD_LISTEN_CLIENT_URLShttp://0.0.0.0:2379 ports: - 2379:2379 apisix: image: apache/apisix:3.12 container_name: apisix restart: always ports: - 9080:9080 - 9180:9180 volumes: - ./config.yaml:/usr/local/apisix/conf/config.yaml:ro depends_on: - etcd启动命令docker compose up -d这里有个细节depends_on只能保证容器启动顺序不能保证 etcd 已经可服务。如果 APISIX 容器起来时 etcd 还在初始化可能出现启动失败。遇到这种情况不要慌docker restart apisix一下就好。等一会儿再看容器状态docker ps | grep apisix看到Up且不是不断重启的状态基本就成功了。3.2 方式二RPM包安装生产环境首选生产环境我推荐 RPM 包方式因为 APISIX 官方仓库提供的 RPM 包自带 systemd 管理脚本开机自启、日志查看都方便和系统集成得最紧密。先添加 APISIX 官方 yum 源。如果你的系统没有yum-config-manager先装个yum-utilssudo yum install -y yum-utils sudo yum-config-manager --add-repo https://repos.apiseven.com/apache-apisix.repo sudo yum -y install apisix安装完成后验证版本apisix version正常会输出类似3.12.0的版本号。接下来修改配置文件/usr/local/apisix/conf/config.yaml。先把 admin_key 从默认值换成你自己的随机密钥再把deployment.etcd.host指向本机 etcddeployment: role: traditional role_traditional: config_provider: etcd etcd: host: - http://127.0.0.1:2379启动 APISIX 直接使用 systemdsudo systemctl enable apisix sudo systemctl start apisix如果启动过程中报错查看日志journalctl -u apisix -n 50这里我特别提醒一句RPM 方式安装的 APISIX 已经内置了配套的 OpenResty不需要你事先自己装一个 OpenResty否则版本或路径可能冲突。我第一次装的时候不放心非要自己先编译了个 OpenResty结果 APISIX 启动时加载动态库路径错乱白白折腾了两个小时后来把自定义 OpenResty 卸掉才恢复“出厂状态”。3.3 方式三源码编译安装进阶了解源码编译适合两类人一类是想二次开发 APISIX 的人另一类是所处的平台没有现成 RPM 包的人。整体流程是git clone -b 3.12 https://github.com/apache/apisix.git cd apisix make deps make install源码方式本质上是对 OpenResty 的定制构建依赖较复杂编译时间长而且部署后和系统服务的整合需要自己处理。除非你有明确需求否则我不建议仅仅为了尝鲜就去源码编译。后面两种方式能覆盖 99% 的场景。3.4 安装后的统一验证清单不管用哪种方式装好我都建议按下面这套清单做一遍验证确认网关核心链路是通的数据面端口可访问curl -i http://127.0.0.1:9080正常会返回 APISIX 的默认错误提示因为没有配置任何路由。Admin API 可访问curl -i http://127.0.0.1:9180/apisix/admin/routes不带 key 会返回 401带 key 返回空列表。etcd 中存在 APISIX 的配置前缀进入 etcd 容器或本机执行etcdctl get / --prefix能看到/apisix开头的 key。检查 APISIX 错误日志无 etd 连接告警Docker 方式用docker logs apisixRPM 方式用journalctl -u apisix。管理员密钥可以通过如下命令测试curl -i http://127.0.0.1:9180/apisix/admin/routes \ -H X-API-KEY: change-me-to-random-secret返回{list:[],total:0}就说明 Admin API 正常。如果返回 401请检查 key 名称和配置里的name是否匹配。4. 核心概念一次讲透Route、Upstream与Service的关系4.1 三个核心对象的关系在开始创建路由之前必须把 APISIX 里三个最基础的概念搞清楚因为所有操作都是围绕它们展开的。Route 是“外部请求怎么走”的规则它描述 URI、Host、Method 这些匹配条件以及匹配到之后要执行哪些插件。Upstream 是“后端去哪找”的地址信息它定义一组真实业务节点的 IP、端口、权重和负载均衡算法。Service 则是“多个路由共用一套配置”的抽象层。举个例子购物车服务和订单服务可能都挂同一套限流策略和鉴权策略那这套公共策略就放到 Service 里两个 Route 都引用同一个 Service。三者的关系可以类比为Route 是路口指示牌告诉流量走哪条路Upstream 是这条路尽头的仓库地址Service 是整片路网统一的限高、限速标准。4.2 通过Admin API创建第一个路由与上游现在开始第一次真正使用 APISIX。我先创建一个 Upstream把流量指向一个测试用的后端服务 httpbin.orgcurl http://127.0.0.1:9180/apisix/admin/upstreams/1 \ -H X-API-KEY: change-me-to-random-secret -X PUT -d { type: roundrobin, nodes: { httpbin.org:80: 1 } }注意这里的nodes格式必须是域名:端口: 权重端口不能省略否则会报 invalid node。权重是可选的默认为 1多个节点可以配置成不同权重实现简单的流量分发比如新版本服务给小流量{ type: roundrobin, nodes: { 10.0.0.21:8080: 1, 10.0.0.22:8080: 2 } }然后创建 Route绑定刚建好的 Upstreamcurl http://127.0.0.1:9180/apisix/admin/routes/1 \ -H X-API-KEY: change-me-to-random-secret -X PUT -d { uri: /get, upstream_id: 1 }现在测试完整链路curl http://127.0.0.1:9080/get如果你看到 httpbin 返回的 JSON 数据说明网关已经成功把/get这个路径的请求转发到了后端。APISIX 从创建路由到生效基本是毫秒级的不需要重启也不需要 reload。4.3 路由匹配规则默认前缀匹配带来的坑这里有个非常容易踩的坑。APISIX 的uri默认是前缀匹配也就是说我前面创建的路由/get会同时匹配/get、/get/foo、/getanything。这跟 Nginx 的 location 精确匹配不同很多从 Nginx 迁移过来的人都在这上面栽过跟头。如果你需要精确匹配有几种做法。一种是在vars里限定curl http://127.0.0.1:9180/apisix/admin/routes/1 \ -H X-API-KEY: change-me-to-random-secret -X PATCH -d { vars: [[uri, , /get]] }另一种是给路由增加优先级并配合更具体的规则。实际项目中我建议一开始就明确设计 URI 规范能精确匹配的就精确匹配必须用前缀模糊的场景要单独评估是否会被其他路由覆盖。毕竟路由表一旦复杂前缀重叠很容易造成请求“流窜”到错误的上游。5. 真实业务配置鉴权、限流、CORS与可视化面板5.1 key-auth给接口加一把钥匙网关上线后的第一件事通常是把业务接口保护起来不能让人随便访问。APISIX 的 key-auth 插件是最简单直接的鉴权方式。先创建一个 Consumer代表调用方curl http://127.0.0.1:9180/apisix/admin/consumers \ -H X-API-KEY: change-me-to-random-secret -X PUT -d { username: app_user, plugins: { key-auth: { key: secret-key-123456 } } }然后给之前的路由挂上 key-auth 插件curl http://127.0.0.1:9180/apisix/admin/routes/1 \ -H X-API-KEY: change-me-to-random-secret -X PATCH -d { plugins: { key-auth: {} } }验证一下效果。不带 key 请求curl http://127.0.0.1:9080/get会返回 401。带上 key 请求curl http://127.0.0.1:9080/get -H apikey: secret-key-123456就能正常拿到后端数据。key-auth 的使用场景很明确内部服务之间调用、B 端开放平台接口签名、前后端分离但不想引入复杂 OAuth 的场景都用得上。一个 Consumer 对应一个调用方便于后续单独对它做限流和审计。5.2 limit-req保护后端不被打挂接口一旦上线就会面临“恶意刷接口”和“瞬时高并发”的问题。限流插件是网关的标配APISIX 里最常用的是 limit-req它实现的是固定窗口加桶形的限流逻辑。参数解释一下rate每秒允许的平均请求数。burst峰值桶容量通俗讲就是允许瞬时多打几个请求进来消耗积压。rejected_code被拒绝时返回的状态码一般用 429。key_type和key限流维度varremote_addr是按客户端 IP 限。给已有路由加限流curl http://127.0.0.1:9180/apisix/admin/routes/1 \ -H X-API-KEY: change-me-to-random-secret -X PATCH -d { plugins: { limit-req: { rate: 1, burst: 2, rejected_code: 429, key_type: var, key: remote_addr } } }配置好之后用ab或wrk压一下就能看到连续请求很快返回 429。生产环境的经验值是rate不要拍脑袋填要结合后端接口的真实 RT 和压测结果来定。比如后端单机 QPS 是 200同一接口挂了两台机器网关层的 rate 就可以压到 300 到 350 左右留点裕量不要贴着实际能力硬设。5.3 CORS插件前后端分离的刚需现在前后端分离几乎是标配前端域名和 API 域名不同跨域问题躲不掉。如果不想在每个业务服务里各自处理 CORS直接在网关层统一配置是最省事的。APISIX 的 cors 插件可以做到curl http://127.0.0.1:9180/apisix/admin/routes/1 \ -H X-API-KEY: change-me-to-random-secret -X PATCH -d { plugins: { cors: { allow_origins: https://myweb.example.com, allow_methods: GET,POST,PUT,DELETE,OPTIONS, allow_headers: Content-Type,Authorization, expose_headers: *, max_age: 3600 } } }这里要提醒一点网上很多配置会直接写allow_origins: *。如果接口要携带 Cookie 或走 Authorization 头*会导致浏览器拦截必须写上具体域名。CORS 插件解决了跨域但没有解决所有问题比如 Preflight 请求OPTIONS在网关层直接处理不给后端增加无谓的并发压力。5.4 部署APISIX Dashboard可视化运维命令行的 Admin API 用久了你会发现还是想有个界面看路由配置。APISIX 官方有 Dashboard 项目虽然是独立组件但和 APISIX 的集成做得很好。Docker 方式启动docker run -d --name apisix-dashboard \ -p 9000:9000 \ -e APISIX_API_URLhttp://172.17.0.1:9180 \ -e APISIX_API_KEYchange-me-to-random-secret \ apache/apisix-dashboard:3.0.2注意这里的172.17.0.1是 Docker 默认网桥的宿主机地址这样 Dashboard 容器能找到宿主机的 APISIX Admin API。如果 APISIX 本身也在容器里要看具体的网络配置。默认账号密码通常是 admin/admin首次登录后务必立刻修改。Dashboard 里可以直观地看到所有 Route、Upstream、Consumer 的列表也能在线创建配置。它的定位是“可视化运维工具”而不是“唯一管理入口”。我的习惯是正式变更走脚本调 Admin API保障可重复执行性查询和排障打开 Dashboard 看效率更高。6. 部署后的排错清单与性能调优6.1 启动失败与etcd连接问题安装过程中最常见的错误就是 APISIX 启动时连不上 etcd报错信息里会出现类似failed to fetch data from etcd或etcd cluster is unavailable的字样。遇到这个按顺序排查etcd 进程是否正常etcdctl --endpointshttp://127.0.0.1:2379 endpoint health。APISIX 配置里的deployment.etcd.host是否指向了 etcd 实际监听的地址。Docker 方式下APISIX 容器内访问 etcd 要用容器网络内的服务名http://etcd:2379而不是http://127.0.0.1:2379。防火墙和 SELinux 是否放行了 2379 端口访问。还有一类隐蔽问题是你改了 config.yaml 但没改对缩进。YAML 对缩进极其敏感一个 tab 或者一个空格错误APISIX 启动时会直接抛invalid configuration。我的建议是改完配置执行apisix testRPM 方式或者apisix config validate先确认语法没问题再启动。提示如果开启了 SELinux建议先临时setenforce 0验证是不是它拦截了网络访问。确认是 SELinux 之后再决定是调策略还是干脆关闭。生产环境尽量不直接关闭但确实很多团队为了省事会关掉这个取舍要看你们的运维基线。6.2 路由404与插件不生效路由创建成功但访问 404这种情况也经常出现。我总结下来原因无非三种。第一种是 URI 匹配不上。默认前缀匹配可能会被更精确的路由“抢”走或者你的请求路径和路由里的uri并不一致。这时候可以先看请求到底被哪条路由匹配了APISIX 在错误日志里会打印匹配到的路由 id。第二种是 Upstream 不存在或配置错误。很多人在 Route 里填了upstream_id但这个 ID 对应的 Upstream 要么没创建要么节点 IP 不通。调试方法很简单直接请求网关端口观察返回是 502 还是 404502 说明路由匹配到了但上游不通404 说明没匹配到路由。第三种是插件没生效。要注意不是所有插件都能用 PATCH 直接叠加。部分插件需要在routes/1的plugins下完整替换或者你 PATCH 的 JSON 里少了关键的plugins层级。我建议每次改完插件后立刻执行 GET 看下最终配置curl http://127.0.0.1:9180/apisix/admin/routes/1 \ -H X-API-KEY: change-me-to-random-secret查看返回 JSON 里plugins字段是否完整、参数是否在预期位置。这样排查速度比瞎猜快得多。6.3 安全加固与性能调优一个 APISIX 网关上线后安全隐患往往来自配置。我列几个必做的加固动作修改默认 admin_key并且使用至少 32 位的随机字符串。Admin API 端口 9180 不要绑定 0.0.0.0绑定内网 IP。etcd 不要暴露公网并且尽量启用 TLS 或账号认证。生产环境把 Dashboard 放在内网不要通过公网直接访问。性能调优方面有几个性价比很高的参数。APISIX 的 Worker 进程数默认跟随 CPU 核心可以在 config.yaml 里显式设置nginx_config: worker_processes: auto worker_cpu_affinity: auto event: worker_connections: 10240如果业务是短连接为主worker_connections要调到 10240 以上否则高并发下很容易出现too many open files。还需要注意系统层面的ulimit -n建议至少 65535。另一个容易被忽略的点是局域网内大量后端节点场景下etcd 会成为瓶颈。生产环境把 etcd 从 APISIX 所在机器上独立拆出去单独机器部署并且给 etcd 数据目录用 SSD能明显减少配置变更时的延迟。最后提一个调优思路如果你的路由表非常大上万条建议把默认的radixtree_uri路由模式改为radixtree_host_uri虽然匹配时会多判断一层 Host但在多域名场景下能减少 URI 冲突也让路由表更清晰。这个改动需要重启 APISIX并且要在测试环境先验证。我在实际部署 APISIX 3.12 的过程中最大的体会是它解决问题的思路和 Nginx 完全不是一个时代。只要前期把 etcd 部署好、端口隔离做好、核心概念搞明白后面的日常运维会轻松非常多。尤其是当你只需要通过一条 PUT 请求就能完成一次接口发布的时候你就不太想回到那个改配置文件后紧张地 reload 的日子了。如果你正在从 Nginx 迁移建议先在测试环境把现有的 location 规则逐一翻译成 APISIX 的 Route同时把 key-auth 和 limit-req 插件加上用压测工具跑一遍对比性能和延迟。数据面本身性能损耗很小通常可以放心切换。第一次上线时可以保留 Nginx 作为前置双跑几天观察日志对比确认无误后再切流量。这样做虽然多一步但心里踏实。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →