Ops Lua Analysis

Categories:

APISIX CLI ops.lua 源码分析

文件概览

apisix/cli/ops.lua 是 Apache APISIX 的命令行入口操作模块,负责处理所有 CLI 子命令(init、start、stop、restart、reload、test 等)。它将 YAML 配置转换为 nginx.conf,管理 OpenResty 进程生命周期。


1. 命令路由机制(action 表 + _M.execute

-- 第1104-1115行:命令注册表
local action = {
    help = help,
    version = version,
    init = init,
    init_etcd = etcd.init,
    start = start,
    stop = stop,
    quit = quit,
    restart = restart,
    reload = reload,
    test = test,
}

-- 第1118-1130行:命令分发
function _M.execute(env, arg)
    local cmd_action = arg[1]
    if not cmd_action then
        return help()
    end
    if not action[cmd_action] then
        stderr:write("invalid argument: ", cmd_action, "\n")
        return help()
    end
    action[cmd_action](env, arg[2])
end

设计要点:用一个 action 表做命令到函数的映射,简洁且易于扩展。无效命令时打印提示并展示 help。


2. init(env) — 初始化 nginx.conf(第234-890行)

这是最核心的函数,负责从 YAML 配置生成 nginx 配置。流程如下:

2.1 环境预检(第236-248行)

  • 检测是否在 /root 目录运行(仅开发环境允许)
  • 检查 ulimit,低于 1024 发出警告

2.2 YAML 加载与校验(第251-259行)

local yaml_conf, err = file.read_yaml_conf(env.apisix_home)
local ok, err = schema.validate(yaml_conf)

2.3 关键配置校验

校验项 位置 说明
admin_key 第284-331行 检查 Admin API token 是否设置,支持空 token 自动生成
admin_api_mtls 第333-344行 启用 https_admin 时必须配置 SSL 证书
OpenResty 版本 第346-354行 要求 >= 1.21.4
http_stub_status_module 第357-361行 必须编译该模块
proxy-cache 插件 第397-399行 启用时必须配置 apisix.proxy_cache
batch-requests 插件 第401-421行 检查 real_ip_from 是否包含 loopback
standalone 模式 第262-281行 APISIX_STAND_ALONE=true 时 config_provider 必须为 yaml/json

2.4 代理模式处理(第362-380行)

if yaml_conf.apisix.proxy_mode == "http" then
    enable_http, enable_stream = true, false
elseif yaml_conf.apisix.proxy_mode == "stream" then
    enable_http, enable_stream = false, true
elseif yaml_conf.apisix.proxy_mode == "http&stream" then
    enable_http, enable_stream = true, true
end

2.5 端口冲突检测(第423-521行)

validate_and_get_listen_addr()listen_table_insert() 使用 ports_to_check 表确保 admin/status/control/prometheus/HTTP/HTTPS 各端口不冲突。

涉及的端口:

  • Admin:默认 9180
  • Status:默认 7085
  • Control:默认 9090
  • Prometheus:默认 9091

2.6 HTTP/HTTPS 监听标准化(第523-601行)

  • node_listen(可为 number、table、嵌套 table)统一为标准格式 [{ip, port, enable_http3}]
  • ssl.listen 同理标准化
  • 从 3.9 版本起,enable_http2 已从端口级移至 apisix 全局级别,端口级配置会报错

2.7 端口校验(validate_port_or_range,第61-131行)

一个手写的端口号/端口范围校验器,支持:

  • 整数端口号(1-65535)
  • 范围格式(start-end
  • IPv4 带端口(0.0.0.0:8080
  • IPv6 带端口([::1]:8080

2.8 模板渲染(第679-889行)

将处理后的所有配置打包成 sys_conf 表,使用 resty.template 渲染 nginx 模板并写入 conf/nginx.conf

关键 sys_conf 字段:

  • worker_rlimit_nofile:自动设为 worker_connections + 128
  • worker_processes:dev_mode 下强制为 1,否则默认 “auto”
  • dns_resolver:未配置时自动从 /etc/resolv.conf 读取
  • extra_lua_path/cpath:追加自定义 Lua 路径
  • envs:注入环境变量(含 Kubernetes 服务发现所需的变量)

2.9 集群角色处理(第663-671行)

if role == "control_plane" and not admin_server_addr then
    local listen = node_listen[1]
    admin_server_addr = str_format("%s:%s", listen.ip, listen.port)
end

control_plane 角色自动复用第一个 node_listen 地址作为 admin 地址。

2.10 服务发现特殊处理(第811-876行)

  • Kubernetes:注入 shared_dict,解析环境变量占位符(${VAR}
  • Consul:注入 shared_dict

3. start(env, ...) — 启动 APISIX(第923-1019行)

执行流程

  1. cleanup(env) — 删除自定义 yaml 索引文件
  2. 禁止 root 运行 — 生产环境硬性拒绝
  3. 创建 logs 目录
  4. 等待旧进程退出 — 最多 3 秒(30次 × 0.1秒),用 signal.kill(pid, 0) 检测
  5. 解析 -c 参数 — 支持 --config 指定自定义 YAML 路径
  6. init(env) — 生成 nginx.conf
  7. init_etcd(env, args) — 非 data_plane 角色时初始化 etcd
  8. 执行 openresty — 真正的启动

4. test(env) — 配置测试(第1022-1057行)

-- 备份原 nginx.conf → 生成新的 → nginx -t → 恢复原 nginx.conf

这是一个非破坏性操作,测试完后保证恢复原来的 nginx.conf。兼容 macOS 和 Linux 的 os.execute 返回值差异。


5. stop(env) / quit(env) — 停止服务(第1060-1073行)

local cmd = env.openresty_args .. [[ -s quit]]   -- 优雅停止
local cmd = env.openresty_args .. [[ -s stop]]   -- 快速停止

两者都先执行 cleanup(env),然后发送对应的 nginx 信号。

  • quit:优雅停止,等待 worker 处理完当前请求
  • stop:快速停止,立即终止所有 worker

6. restart(env) / reload(env) — 重启与热加载(第1076-1100行)

restarttest → stop → start(先测再停再启)

reloadinit → nginx -t → nginx -s reload(热加载,不中断服务)

reload 失败时只打印消息,不会 die,避免中断已有运行实例。


7. 辅助函数

函数 位置 作用
local_dns_resolver() 第189行 /etc/resolv.conf 解析 DNS 服务器地址
version_greater_equal() 第152行 语义版本比较
get_openresty_version() 第173行 通过 openresty -v 获取版本号
check_running() 第912行 通过 pid 文件判断进程是否存活
get_lua_path() 第215行 规范化 Lua 路径(确保以 ; 结尾)
validate_port_or_range() 第61行 端口/端口范围合法性校验
validate_and_get_listen_addr() 第425行 内嵌函数,校验端口冲突并拼接地址字符串
listen_table_insert() 第480行 内嵌函数,标准化监听表插入(支持 IPv6 双栈)
cleanup() 第898行 删除自定义 yaml 索引文件
sleep() 第907行 通过 os.execute("sleep " .. n) 实现等待

8. 安全与设计亮点

  1. 端口冲突检查 — 多个服务端口(admin/status/control/prometheus/http/https)统一通过 ports_to_check 防止冲突
  2. 配置校验前置 — start/reload/restart/test 都会重新运行 init(),确保配置变更后即时校验
  3. 安全警告 — root 运行、空 admin_key、低 ulimit、admin_key_required=false 都给出明确警告
  4. 进程检测 — 启动前检测旧进程,避免端口冲突;检测 pid 对应的进程是否真实存在(而非仅检查文件)
  5. 向后兼容node_listen 支持 number/table/嵌套 table 三种历史格式
  6. 非破坏性测试test 命令备份并恢复原始 nginx.conf
  7. 优雅降级 — reload 失败不终止运行中的实例

9. 执行流程图

apisix start
  │
  ├── cleanup()
  ├── 检查 /root 禁止运行
  ├── 创建 logs/
  ├── 等待旧进程退出(最多3秒)
  ├── 解析 -c 参数
  ├── init(env)
  │     ├── 读取 & 校验 config.yaml
  │     ├── 校验 admin_key / mtls / plugins
  │     ├── 处理 proxy_mode (http/stream/http&stream)
  │     ├── 端口冲突检测
  │     ├── 标准化 node_listen / ssl.listen
  │     ├── 处理 服务发现 (K8s/Consul)
  │     ├── DNS 解析器配置
  │     └── 模板渲染 → nginx.conf
  ├── init_etcd() [非 data_plane]
  └── 启动 openresty

apisix reload
  ├── init(env)          # 重新生成 nginx.conf
  ├── nginx -t           # 语法测试
  └── nginx -s reload    # 热加载信号

apisix restart
  ├── test(env)          # 备份→生成→测试→恢复
  ├── stop(env)          # nginx -s stop
  └── start(env)         # 完整启动流程
Read More

Apache APISIX 源码阅读指南

【2026-07-26】Apache APISIX 源码阅读指南 - 从启动流程、核心模块、请求处理链路到插件系统的系统化阅读路线