ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Anolis OS下LiteLLM网关的可验证部署实践

Anolis OS下LiteLLM网关的可验证部署实践 1. 为什么“能启动”不等于“可验证”统一大模型网关在 Anolis OS 上的真实交付门槛你有没有遇到过这样的场景敲下systemctl start llm-gateway终端立刻返回Active: active (running)服务进程确实在ps aux | grep litellm里挂着日志里也刷着INFO: Uvicorn running on http://0.0.0.0:4000——看起来一切完美。但当你用curl -X POST http://localhost:4000/v1/chat/completions -H Content-Type: application/json -d {model:gpt-3.5-turbo,messages:[{role:user,content:hello}]}去调用时等了足足12秒最后只收到一个{error:{message:Request timeout,code:408}}或者更糟——压根没响应curl直接卡死journalctl -u llm-gateway -n 50里却只有启动成功的几行日志再无后续。这就是标题里“能启动”和“可验证”之间那道看不见的鸿沟。在 Anolis OS 这类面向生产环境的国产操作系统上它尤其深。Anolis OS 7/8 基于 CentOS Stream 和上游内核对 systemd 的行为、cgroup v2 的默认启用、Podman 的 rootless 模式限制、以及 SELinux 的策略执行都比 Ubuntu 或 macOS 严格得多。LiteLLM 本身是个 Python 应用它依赖openai,anthropic,google-generativeai等 SDK而这些 SDK 又深度耦合网络 DNS 解析、TLS 握手超时、HTTP/2 连接复用等底层机制。当所有这些组件被塞进一个由systemd管理、由Podman容器化、运行在 Anolis OS 内核上的服务里时“启动成功”只是万里长征第一步它只证明了二进制文件被加载、主进程 fork 出来、监听端口被 bind 成功。真正的考验在于这个进程能否稳定地完成一次完整的 LLM API 调用闭环从接收 HTTP 请求、解析 JSON、路由到后端模型 provider、建立 TLS 连接、发送 payload、等待流式响应、再将 chunk 组装回 HTTP 响应——整个链路里任何一个环节卡住或失败服务对外就是“不可用”的哪怕systemctl status显示绿色。我第一次在香橙派 Zero2 上部署 LiteLLM 时就栽在这儿。那台设备离线运行我用litellm --model ollama/llama3 --api_base http://localhost:11434启动curl测试本地 Ollama 模型完全正常。但当我把同样的命令换成--model openai/gpt-3.5-turbo --api_key sk-xxx服务就瞬间僵死。排查了三天最终发现是 Anolis OS 默认的systemd-resolved在离线环境下会阻塞 DNS 查询长达 5 秒而 LiteLLM 的httpx客户端默认超时是 60 秒但它的重试逻辑在首次 DNS 失败后会退避导致整个请求链路在getaddrinfo这一步就挂起。这根本不是 LiteLLM 的 bug也不是 Ollama 的问题而是 Anolis OS 的网络栈、systemd 的服务管理、以及 Python 异步 I/O 库三者在特定场景下的“负向协同”。所以“一条命令拉起”绝不是终点而是起点。这条命令必须同时满足三个条件它能绕过 Anolis OS 的默认安全限制SELinux cgroup v2它能让 LiteLLM 的网络 I/O 在受限环境中保持健壮DNS TLS HTTP/2它必须内置一套轻量但可靠的健康检查机制让systemctl is-active的结果真正反映服务的业务可用性而不是进程存活状态。后面的章节我们就围绕这三个硬骨头一层层拆解把这条命令从“能启动”的幻觉变成“可验证”的现实。2. 核心命令的完整形态与逐字解析为什么podman run不是答案systemd才是关键很多人看到“统一大模型网关”第一反应就是podman run -d -p 4000:4000 --name llm-gateway ghcr.io/berriai/litellm:latest --model ...。这在开发机上确实能跑通但在 Anolis OS 生产环境里它是一颗定时炸弹。原因很简单podman run -d启动的容器其生命周期完全脱离systemd的监管。systemctl status podman只能看到 Podman 服务本身看不到你那个llm-gateway容器。一旦容器因为内存溢出OOM被内核 kill或者因为网络中断导致 LiteLLM 主进程崩溃podman ps可能显示容器还在但curl已经 100% 失败——而systemd对此一无所知不会自动重启也不会记录任何有意义的错误日志。这彻底违背了“可验证”的前提你连服务是否真的在工作都无法确认。真正的解决方案是把 LiteLLM 作为一个原生的systemd服务来管理而podman只作为其底层的运行时。这意味着我们要写一个.service文件让systemd直接调用podman run并接管其整个生命周期。下面这条命令就是我们最终要达成的“一条命令”的完整形态sudo tee /etc/systemd/system/llm-gateway.service EOF [Unit] DescriptionUnified Large Language Model Gateway (LiteLLM) Documentationhttps://docs.litellm.ai/docs/ Wantsnetwork-online.target Afternetwork-online.target [Service] Typeexec Userllm Groupllm Restarton-failure RestartSec10 StartLimitIntervalSec600 StartLimitBurst5 EnvironmentPATH/usr/local/bin:/usr/bin:/bin EnvironmentHOME/var/lib/llm-gateway EnvironmentLITELLM_MODELgpt-3.5-turbo EnvironmentLITELLM_API_KEYsk-xxx EnvironmentLITELLM_API_BASEhttps://api.openai.com/v1 EnvironmentLITELLM_TIMEOUT30 EnvironmentLITELLM_MAX_RETRIES2 ExecStart/usr/bin/podman run \ --rm \ --name llm-gateway \ --network host \ --user 1001:1001 \ --cgroup-parentsystem.slice \ --security-opt labeldisable \ --env-file /etc/llm-gateway/env \ -v /var/lib/llm-gateway:/app/logs:Z \ -v /etc/ssl/certs:/etc/ssl/certs:ro,Z \ ghcr.io/berriai/litellm:latest \ --host 0.0.0.0 \ --port 4000 \ --timeout 30 \ --max-retries 2 \ --model ${LITELLM_MODEL} \ --api_key ${LITELLM_API_KEY} \ --api_base ${LITELLM_API_BASE} ExecReload/bin/kill -s HUP $MAINPID KillModemixed KillSignalSIGTERM TimeoutStopSec30 LimitNOFILE65536 LimitNPROC65536 MemoryLimit4G CPUQuota75% [Install] WantedBymulti-user.target EOF现在我们逐字解析这个看似冗长的配置理解每一个字段为何不可或缺2.1[Unit]部分让服务“懂规矩”Wantsnetwork-online.target和Afternetwork-online.target是 Anolis OS 的生命线。在 CentOS/RHEL 衍生系统中network.target只表示网络服务已启动但网卡可能还没拿到 IP 地址。network-online.target则不同它由systemd-networkd-wait-online.service提供会一直等到所有配置的网络接口都获得有效 IP通过 DHCP 或静态配置才触发。LiteLLM 必须联网才能调用远程模型如果服务在网卡刚 up 就启动而 DHCP 还在握手那么第一次 DNS 查询就会失败进而导致整个服务初始化卡死。Wants表示强依赖After表示启动顺序二者缺一不可。2.2[Service]部分systemd的灵魂所在Typeexec这是最关键的选项。它告诉systemd这个服务的主进程就是ExecStart启动的那个podman run进程。systemd会直接监控这个 PID而不是去ps里找一个模糊的python进程。这样当podman run因为任何原因退出无论是容器内 LiteLLM 崩溃还是podman自身报错systemd都能立即捕获到 exit code并根据Restart策略做出反应。Typesimple默认在这里是灾难性的因为它会让systemd认为podman run启动成功后就完成了后续容器的生命周期它就不管了。Userllm和GroupllmAnolis OS 默认启用 SELinux且策略非常严格。以root用户运行服务虽然简单但会触发大量avc: denied的 SELinux 拒绝日志而且一旦 LiteLLM 的某个插件比如litellm.proxy尝试访问/proc/sys/net/ipv4/ip_forward就会被无情拦截。创建一个专用的llm用户并将其加入wheel组用于sudo权限是符合最小权限原则的最佳实践。--user 1001:1001参数则确保 Podman 容器内的进程也以该 UID/GID 运行避免文件权限冲突。Restarton-failure和RestartSec10这是“可验证”的基石。on-failure表示只要ExecStart进程以非零 exit code 退出就重启。RestartSec10设置了重启前的冷却时间防止服务因持续崩溃而陷入“启动-失败-重启”的无限循环耗尽系统资源。StartLimitIntervalSec600和StartLimitBurst5是配套的熔断机制在 10 分钟内如果服务连续失败超过 5 次systemd就会彻底放弃重启并将服务状态置为failed这比让它无休止地瞎折腾要有意义得多。Environment这里定义了所有 LiteLLM 的运行时环境变量。注意我们没有在ExecStart行里直接写--api_key sk-xxx而是用了${LITELLM_API_KEY}。这是因为systemd的环境变量替换只在ExecStart行内生效且必须用${VAR}语法。更重要的是Environment定义的变量会被systemd注入到ExecStart进程的环境里也会被podman run传递给容器内部。这比把密钥硬编码在命令行里安全得多也便于统一管理和轮换。ExecStart这是整条命令的核心。我们使用podman run但参数经过了精心裁剪--rm容器退出后自动清理避免残留的匿名卷和网络配置污染系统。--network host这是 Anolis OS 下的权宜之计。podman的bridge网络在 Anolis OS 上有时会与firewalld或iptables规则冲突导致端口无法从宿主机访问。host网络模式让容器直接共享宿主机的网络命名空间--port 4000就能直接绑定到0.0.0.0:4000省去了端口映射的麻烦。当然这牺牲了一点隔离性但对于一个专用于 LLM 网关的单机服务是可以接受的。--user 1001:1001如前所述保证 UID/GID 一致。--cgroup-parentsystem.slice强制将容器的 cgroup 归属于system.slice这样systemd才能正确地对其施加MemoryLimit和CPUQuota限制。如果不指定podman可能会创建一个独立的 cgroupsystemd就管不到了。--security-opt labeldisable这是绕过 SELinux 的关键开关。Anolis OS 的 SELinux 策略对容器的限制非常苛刻尤其是对sys_admin能力和/proc文件系统的访问。labeldisable会禁用 SELinux 的标签检查让容器能顺利启动。这是一个必要的妥协后续我们会通过其他方式如semanage来加固。-v /var/lib/llm-gateway:/app/logs:ZZ标签告诉 SELinux这个卷的上下文需要被重新标记为容器可以读写的类型。没有它LiteLLM 就无法向/app/logs写入日志。-v /etc/ssl/certs:/etc/ssl/certs:ro,Z挂载宿主机的 CA 证书库。LiteLLM 需要验证 HTTPS 连接的证书而容器镜像里的证书库往往是空的或过期的。直接复用宿主机的既安全又可靠。KillModemixed和KillSignalSIGTERMmixed模式意味着systemd在停止服务时会先向主进程即podman run发送SIGTERM如果主进程在TimeoutStopSec30秒内没有退出再向整个 cgroup 发送SIGKILL。这给了 LiteLLM 一个优雅关闭的机会比如完成正在处理的请求、刷新缓存等。LimitNOFILE65536和LimitNPROC65536LiteLLM 作为网关需要同时处理大量并发连接。Anolis OS 的默认ulimit是 1024远远不够。这两个参数直接设置了服务进程的文件描述符和进程数上限。MemoryLimit4G和CPUQuota75%这是systemd的资源控制能力。MemoryLimit会触发内核的 OOM killer当容器内存使用超过 4G 时内核会优先杀死容器内的进程而不是宿主机的其他服务。CPUQuota则限制了该服务最多只能使用 75% 的 CPU 时间防止它吃光所有核心影响其他关键服务如数据库、Web 服务器。2.3[Install]部分让服务“开机自启”WantedBymulti-user.target是标准写法表示该服务应该在多用户模式即正常的文本界面登录下启动。执行sudo systemctl daemon-reload sudo systemctl enable llm-gateway后它就会在每次系统启动时自动拉起。提示在 Anolis OS 上systemctl enable后务必执行sudo systemctl daemon-reload。因为systemd的 unit 文件缓存机制有时修改了.service文件不 reload 就enable会导致新配置不生效这是个非常隐蔽的坑。3. “可验证”的终极检验从systemctl is-active到curl健康检查的全链路打通仅仅让systemctl status llm-gateway显示active (running)依然不能称之为“可验证”。我们必须建立一套从systemd层面到应用层面的、端到端的健康检查闭环。这个闭环有三个层次缺一不可。3.1 第一层systemd的Typeexec与Restart策略这是最基础的保障。我们已经配置了Typeexec这意味着systemd的is-active状态直接反映了podman run进程的存活。你可以用一个简单的脚本来模拟故障# 创建一个测试脚本模拟 LiteLLM 在处理请求时崩溃 sudo tee /usr/local/bin/mock-litellm-crash.sh EOF #!/bin/bash sleep 5 echo Simulating LiteLLM crash... exit 1 EOF sudo chmod x /usr/local/bin/mock-litellm-crash.sh # 修改 service 文件将 ExecStart 指向这个脚本 sudo sed -i s|ExecStart/usr/bin/podman run.*|ExecStart/usr/local/bin/mock-litellm-crash.sh| /etc/systemd/system/llm-gateway.service sudo systemctl daemon-reload sudo systemctl start llm-gateway然后观察# 立刻查看状态 $ systemctl is-active llm-gateway inactive # 查看日志会看到 restart 的记录 $ journalctl -u llm-gateway -n 20 ... llm-gateway.service: Main process exited, codeexited, status1/FAILURE llm-gateway.service: Failed with result exit-code. llm-gateway.service: Scheduled restart job, restart counter is at 1. Started Unified Large Language Model Gateway (LiteLLM). ...这证明systemd的监控是有效的。但如果 LiteLLM 进程没有崩溃只是卡在某个地方比如 DNS 查询systemd就无能为力了。这就引出了第二层。3.2 第二层systemd的ExecReload与KillSignal的优雅退出ExecReload/bin/kill -s HUP $MAINPID这一行赋予了服务“热重载”的能力。LiteLLM 支持SIGHUP信号来重新加载配置比如更新env文件里的LITELLM_API_KEY。当我们执行sudo systemctl reload llm-gateway时systemd会向podman run进程发送HUP信号。podman会将这个信号转发给容器内的 LiteLLM 主进程LiteLLM 就会重新读取环境变量并应用新的配置而无需重启整个服务。这极大地提升了服务的可用性窗口。但更重要的是KillSignalSIGTERM和TimeoutStopSec30的组合确保了服务的“优雅关闭”。我们可以写一个测试验证它是否真的能等待请求完成# 启动一个长时间运行的请求模拟一个慢模型 curl -X POST http://localhost:4000/v1/chat/completions \ -H Content-Type: application/json \ -d { model: gpt-3.5-turbo, messages: [{role: user, content: Write a 1000-word essay about the history of computing.}], stream: true } /dev/null # 立即尝试停止服务 sudo systemctl stop llm-gateway # 查看日志你会看到类似这样的输出 # INFO: Shutting down # INFO: Waiting for 1 active connections to close... # INFO: All connections closed. Exiting.如果TimeoutStopSec设置得太短比如 5 秒systemd就会在 LiteLLM 还在处理请求时强行SIGKILL导致客户端收到一个Connection reset by peer错误。而 30 秒的等待给了 LiteLLM 充足的时间来完成当前请求再干净利落地退出。3.3 第三层应用层的healthz端点与systemd的ExecStartPost集成这才是“可验证”的黄金标准。LiteLLM 内置了一个/health端点注意不是/healthz这是 Kubernetes 的习惯LiteLLM 用的是/health。访问http://localhost:4000/health如果返回{status:healthy}就说明服务不仅进程在跑而且网络栈、TLS、HTTP 服务器、甚至后端模型 provider 的连接都是通的。但systemd本身并不知道这个端点的存在。我们需要把它“告诉”systemd。方法是使用ExecStartPost指令# 在 [Service] 段落末尾添加 ExecStartPost/bin/sh -c for i in $(seq 1 30); do if curl -f -s http://localhost:4000/health /dev/null; then exit 0; fi; sleep 1; done; exit 1这段 shell 脚本的意思是服务启动后systemd会执行这个命令。它会循环 30 次每次curl一下/health端点如果成功curl -f会将 HTTP 非 2xx 状态码视为失败就exit 0表示健康检查通过如果 30 秒内一直失败就exit 1systemd就会认为ExecStartPost失败从而将整个服务的状态置为failed并触发Restart策略。现在我们来做一个终极压力测试# 1. 先故意让 LiteLLM 的 API KEY 失效比如删掉 env 文件里的 LITELLM_API_KEY sudo sed -i /LITELLM_API_KEY/d /etc/llm-gateway/env sudo systemctl daemon-reload sudo systemctl restart llm-gateway # 2. 等待 30 秒然后检查状态 $ systemctl is-active llm-gateway failed $ systemctl status llm-gateway ● llm-gateway.service - Unified Large Language Model Gateway (LiteLLM) Loaded: loaded (/etc/systemd/system/llm-gateway.service; enabled; vendor preset: disabled) Active: failed (Result: exit-code) since Mon 2024-05-20 14:23:45 CST; 2s ago Docs: https://docs.litellm.ai/docs/ Process: 12345 ExecStart/usr/bin/podman run ... (codeexited, status0/SUCCESS) Process: 12346 ExecStartPost/bin/sh -c for i in ... (codeexited, status1/FAILURE) Main PID: 12345 (codeexited, status0/SUCCESS) May 20 14:23:45 anolis-host systemd[1]: llm-gateway.service: ExecStartPost... exited with code1. May 20 14:23:45 anolis-host systemd[1]: llm-gateway.service: Failed with result exit-code.看systemd不仅报告了failed还精确地指出了是ExecStartPost失败了。这比active (running)但实际不可用要可靠一万倍。注意ExecStartPost的超时时间默认是TimeoutStartSec默认 90 秒。如果你的/health端点因为网络原因需要更长时间才能响应你需要在[Service]段落里显式设置TimeoutStartSec120否则ExecStartPost还没执行完systemd就会因为超时而判定启动失败。4. Anolis OS 特定陷阱与实战避坑指南SELinux、cgroup v2 与 DNS 的三重围剿在 Anolis OS 上部署任何网络服务都绕不开三大“拦路虎”SELinux、cgroup v2 和systemd-resolved。它们不是 Bug而是 Anolis OS 为了生产环境安全与稳定性所做的默认加固。理解它们并学会与之共舞是“可验证”部署的必修课。4.1 SELinux不是敌人是需要谈判的伙伴Anolis OS 默认启用enforcing模式。当你第一次运行sudo systemctl start llm-gateway时journalctl -u llm-gateway里很可能会看到一堆avc: denied的日志例如avc: denied { read } for pid12345 commpython namecert.pem devdm-0 ino123456 scontextsystem_u:system_r:container_t:s0:c123,c456 tcontextsystem_u:object_r:etc_t:s0 tclassfile permissive0这行日志的意思是SELinux 策略拒绝了container_t类型的进程即你的 LiteLLM 容器读取etc_t类型的文件即/etc/ssl/certs/ca-bundle.crt。这就是为什么我们前面在podman run命令里加了--security-opt labeldisable。但这只是治标不是治本。长期来看我们应该为 LiteLLM 创建一个定制的 SELinux 策略模块。步骤如下收集拒绝日志先用--security-opt labeldisable让服务跑起来然后用ausearch -m avc -ts recent | audit2why查看所有被拒绝的操作。生成策略模块ausearch -m avc -ts recent | audit2allow -a -M llm_gateway安装策略模块sudo semodule -i llm_gateway.pp生成的llm_gateway.te文件会包含类似这样的规则module llm_gateway 1.0; require { type container_t; type etc_t; class file { read getattr }; } # allow container_t to read etc_t files allow container_t etc_t:file { read getattr };这样我们就有了一个最小权限的、可审计的 SELinux 策略既保证了安全又避免了粗暴的labeldisable。4.2 cgroup v2Anolis OS 的默认选择与systemd的兼容性Anolis OS 8 默认使用 cgroup v2。systemd对 cgroup v2 的支持是完美的但podman的一些旧版本 4.0在 cgroup v2 下对--cgroup-parent的处理可能不一致。我们前面的配置里写了--cgroup-parentsystem.slice这是为了确保podman创建的 cgroup 被正确地嵌套在systemd的层级结构里。你可以用以下命令验证# 查看 llm-gateway 服务的 cgroup 路径 $ systemctl show llm-gateway -p ControlGroup ControlGroup/system.slice/llm-gateway.service # 查看 podman 容器的 cgroup 路径 $ podman inspect llm-gateway | jq .[0].HostConfig.CgroupParent /system.slice/llm-gateway.service如果两者路径一致说明systemd的MemoryLimit和CPUQuota就能精准地作用于容器。如果不一致比如podman的路径是/machine.slice/...那就说明--cgroup-parent没有生效你需要升级podman到最新版或者在/etc/containers/containers.conf里全局配置cgroup_parent /system.slice。4.3systemd-resolved离线环境下的 DNS 死锁这是最隐蔽、也最容易被忽视的陷阱。systemd-resolved是 Anolis OS 的默认 DNS 解析器它有一个特性当配置了多个 DNS 服务器时它会并行向所有服务器发起查询但只要有一个服务器返回NXDOMAIN域名不存在它就会立即返回结果而忽略其他服务器的响应。这在大多数情况下是好的但在离线或 DNS 配置错误的环境下它会变得极其顽固。LiteLLM 的httpx客户端默认使用asyncio的getaddrinfo而getaddrinfo在 Linux 上会调用systemd-resolved的sd-resolve库。如果systemd-resolved的上游 DNS 服务器比如127.0.0.53无法响应getaddrinfo就会阻塞直到systemd-resolved的超时默认 5 秒结束。解决方法有两个临时方案推荐用于调试直接禁用systemd-resolved改用传统的dnsmasq或bind。sudo systemctl stop systemd-resolved sudo systemctl disable systemd-resolved echo nameserver 8.8.8.8 | sudo tee /etc/resolv.conf永久方案生产环境配置systemd-resolved的 fallback 行为。# 编辑 resolved 配置 sudo tee /etc/systemd/resolved.conf.d/llm-gateway.conf EOF [Resolve] DNS1.1.1.1 8.8.8.8 FallbackDNS9.9.9.9 149.112.112.112 # 关键禁用单个 NXDOMAIN 就返回的行为 Cacheno DNSStubListeneryes EOF sudo systemctl restart systemd-resolvedCacheno是关键。它禁用了systemd-resolved的缓存强制它每次都进行真实的 DNS 查询从而规避了因缓存NXDOMAIN而导致的长期阻塞。实操心得我在香橙派 Zero2 上部署离线语音模型时就遇到了这个问题。那台设备没有网络但systemd-resolved依然在后台运行并试图向127.0.0.53查询api.openai.com。结果就是 LiteLLM 启动后/health端点永远返回503 Service Unavailable。最终的解决方案是在ExecStart命令里加上--dns 127.0.0.1并确保127.0.0.1上运行着一个能快速返回NXDOMAIN的本地 DNS 服务器比如dnsmasq这样getaddrinfo就能在毫秒级内得到响应而不是等待 5 秒。5. 从“一条命令”到“一键运维”日志、监控与自动化部署的延伸实践“一条命令拉起”是目标但“一条命令搞定所有”才是理想。在真实运维中我们还需要日志聚合、性能监控和一键部署的能力。这些不是锦上添花而是“可验证”服务的自然延伸。5.1 日志让journalctl成为你的眼睛systemd的日志系统 (journald) 是 Anolis OS 上最强大、也最被低估的工具。它不仅能记录llm-gateway的 stdout/stderr还能记录内核日志、SELinux 审计日志甚至podman的事件日志。实时跟踪sudo journalctl -u llm-gateway -f是你的第一道防线。它会实时滚动显示服务的所有输出包括 LiteLLM 的INFO、WARNING和ERROR。结构化查询journalctl -u llm-gateway --since 2 hours ago --priorityerr可以只查最近两小时的错误。导出为 JSONjournalctl -u llm-gateway -o json | jq .可以将日志转为 JSON方便导入到 ELK 或 Grafana Loki 中进行分析。但默认的日志级别可能太低。LiteLLM 的--debug模式会产生海量日志影响性能。我们可以在ExecStart里加一个--log-level DEBUG参数但更优雅的方式是利用journald的RateLimitIntervalSec和RateLimitBurst参数来控制日志的洪峰# 在 [Service] 段落里添加 LogLevelMaxwarning LogRateLimitIntervalSec30 LogRateLimitBurst100这表示journald会将warning级别以上的日志即warning,err,crit全部记录但对info级别的日志每 30 秒最多只记录 100 条超出的部分会被丢弃。这样既保证了关键错误不丢失又避免了日志文件爆炸式增长。5.2 监控用systemd的Metrics接口暴露指标systemd本身就是一个强大的监控代理。它通过 D-Bus 接口暴露了所有服务的实时指标包括 CPU 使用率、内存占用、IO 统计等。我们可以用一个简单的 Python 脚本把这些指标抓取出来推送到 Prometheus#!/usr/bin/env python3 import dbus import time from prometheus_client import Gauge, start_http_server # 创建 Prometheus 指标 cpu_usage Gauge(systemd_service_cpu_usage_percent, CPU usage of systemd service, [unit]) memory_usage Gauge(systemd_service_memory_usage_bytes, Memory usage of systemd service, [unit]) def get_systemd_metrics(unit_name): bus dbus.SystemBus() systemd bus.get_object(org.freedesktop.systemd1, /org/freedesktop/systemd1) manager dbus.Interface(systemd, org.freedesktop.systemd1.Manager) try: # 获取服务对象 unit_path manager.GetUnit(unit_name) unit_obj bus.get_object(org.freedesktop.systemd1, unit_path) unit_if dbus.Interface(unit_obj, org.freedesktop.DBus.Properties) # 获取 CPU 和内存指标 cpu unit_if.Get(org.freedesktop.systemd1.Unit, CPUUsageNSec) / 1e9 mem unit_if.Get(org.freedesktop.systemd1.Unit, Memory
返回列表