为什么我会把 AI-Infra-Guard 部署在 Docker 里
先说结论:AI-Infra-Guard 这套东西,如果你还在手动装依赖、配环境、逐个模块起服务,那真的是在浪费生命。这个项目本质上是一个面向 AI 基础设施的“体检 + 技能摸底”工具,它要扫描的不只是机器资源,还有你整个 AI 底座上跑着的模型服务、推理框架、向量库、调度器这些组件到底健不健康、支不支持你接下来要做的事。Docker 一键起,不是为了炫技,是为了让你把精力花在扫描结果上,而不是花在“为什么我本地能跑、服务器上跑不起来”这种破事上。
我接触这个项目是因为团队最近在梳理内部 AI 平台的组件清单,需要快速评估各节点的能力水位——比如有没有装 CUDA、推理框架版本够不够新、有没有暴露不必要的调试端口。手工去逐台机器敲命令,能敲到怀疑人生。AI-Infra-Guard 的价值就在于把“技能扫描”这件事自动化,而且它的扫描项设计是冲着 AI 基础设施的真实痛点去的,不是那种 ping 一下 IP 就算完事的玩具。
这篇文章我会从部署方案选型讲起,然后完整拆解一次实战扫描过程,最后单独用一节复盘我踩过的一次“漏报”事故——准确说是误判,差点让团队把一个健康的节点当成僵尸节点处理掉。整个过程我都会给出具体的命令、参数和排查思路,方便你直接照着复现。
适合谁来参考这篇文章?如果你正在做 AI 平台运维、模型服务部署前的环境预检、或者想给团队搞一套基础设施健康度巡检体系,那 AI-Infra-Guard 的这套玩法非常值得借鉴。如果你只是对 Docker 部署感兴趣,也能从里面看到一套完整的多服务编排实践。
1. 部署方案选型:为什么必须用 Docker 一键起
1.1 手动部署的痛点,我替你踩过了
在我决定用 Docker 之前,先在一台干净的 Ubuntu 22.04 上试过手动部署 AI-Infra-Guard。过程怎么说呢,就是典型的“你以为你在装软件,其实你在给环境排雷”。
首先 Python 版本就有讲究,项目要求 3.10 以上,但系统自带的可能是 3.8 或者 3.9。用 pyenv 装 Python 不是不行,但 pyenv 本身又依赖一堆编译工具链,什么 build-essential、libssl-dev、zlib1g-dev,缺一个编译就报错。装完 Python 还得处理 pip 源的网络问题,然后项目管理工具 poetry 或 pdm 又得单独装。这些还只是前置准备。
真正的痛点在于 AI-Infra-Guard 依赖的底层扫描库。比如要用到 psutil 来采集系统指标,需要编译部分 C 扩展;要用到某些 GPU 检测模块,就得保证本机有完整的 NVIDIA 驱动开发头文件,否则编译直接失败。这些库装完之后还得面对版本冲突——项目要求的某个依赖版本和系统已有的包冲突,一 upgrade 又把别的服务搞挂了。我当时在一台还跑着其他业务的机器上操作,战战兢兢。
这些时间成本其实完全可以避免。容器化的核心价值就是“环境隔离 + 依赖打包”,AI-Infra-Guard 的 Docker 镜像把 Python 版本、依赖库、系统级工具全部固化在一个镜像里,宿主机只需要有 Docker Engine,其他的乱七八糟全靠镜像内部自包含。
1.2 Docker Compose 编排带来的额外收益
AI-Infra-Guard 不只是一个单体服务,它分成了扫描器(Scanner)、服务端(Server)、前端控制台(Web UI)这几个核心组件。这种架构天然适合用 Docker Compose 来编排。
手动部署的时候,你得分别启动这三个进程,还要手工处理它们之间的网络通信、配置文件同步、日志收集。一旦机器重启,这三个进程不会自动恢复,你还得写 systemd service 或者 supervisor 配置来守护。说实话,为了跑一个扫描工具去写 systemd 配置,性价比太低了。
用 Docker Compose 的话,整个应用被定义在一个docker-compose.yml文件里,设置好依赖关系后,一条docker compose up -d就能把服务端、扫描器、控制台全部按顺序拉起。而且 Compose 会创建自定义网络,容器之间通过服务名互相访问,解决了手动部署时最容易出错的“地址配置错”问题。
注意:宿主机网络和 Compose 网络是隔离的。如果你想在浏览器里打开控制台,记得把 Web UI 服务的端口映射到宿主机,这也是我在下面的部署步骤里重点强调的。
1.3 Docker Desktop 和 Linux 环境的选择
这里要单独提一下 Docker Desktop。如果你用的是 Windows 或者 macOS 开发机,Docker Desktop 是最省事的方案,但有两个坑要先排掉。
第一个坑是 “Virtualization support not detected” 这类报错。这不是 Docker 的问题,而是 Windows 的 WSL2 或 Hyper-V 虚拟化没有被正确启用。处理方法很固定:控制面板 -> 程序 -> 启用或关闭 Windows 功能 -> 勾选“适用于 Linux 的 Windows 子系统”和“虚拟机平台”,然后重启,再打开 Docker Desktop 一般就能起来。
第二个坑是 Docker Desktop 的资源限制。默认配置下,它只会给虚拟机分配 2 个 CPU 和 2GB 内存。如果你要扫描的 AI 基础设施规模比较大,或者扫描任务本身要并行跑很多探针,这个资源配额很可能导致扫描超时。我建议在 Docker Desktop 的 Settings -> Resources 里把 CPU 调到 4 核以上,内存至少 4GB。实测下来,这个配置对 AI-Infra-Guard 的日常扫描已经足够。
如果你用的是 Linux 服务器,那就没有 Docker Desktop 这层虚拟化开销了,直接装 Docker Engine 就行。Ubuntu 上装 Docker 的标准姿势是把官方源配好,然后apt install docker-ce docker-ce-cli containerd.io。装完记得把当前用户加入 docker 组,否则每条命令都要加 sudo。
提示:不建议在 Windows 上手动部署 AI-Infra-Guard。它的扫描探针涉及很多系统级调用,Windows 下的兼容性测试做得并不充分,你大概率会撞上一堆莫名其妙的坑。直接用 Docker Desktop 跑容器,省心得多。
2. 部署实操:从头到尾带你跑通
2.1 获取项目与镜像准备
部署前先确认宿主机满足两个基本条件:Docker Engine 版本在 20.10 以上,Compose 插件已安装。查询方法很简单:
docker version --format '{{.Server.Version}}' docker compose version如果 compose 提示没有这个命令,Ubuntu 上用apt install docker-compose-plugin补上。
然后克隆项目代码:
git clone https://github.com/your-repo/AI-Infra-Guard.git cd AI-Infra-Guard/deploy项目提供了三种镜像获取方式:本地构建、拉取官方镜像、离线导入。我这边因为内网环境访问 Docker Hub 不方便,直接用了本地构建。如果你能访问外网,推荐直接用官方编排脚本里定义的镜像名,省去构建时间。
本地构建也很简单,项目根目录下有写好的 Dockerfile,在deploy目录里执行:
docker compose build如果你网络好,也可以直接用现成镜像,把docker-compose.yml里的build字段注释掉,换成image: your-registry/ai-infra-guard:latest。两种方式殊途同归。构建过程中如果因为网络问题拉取基础镜像失败,建议配置 Docker daemon 的镜像加速器,这个下文避坑部分会展开。
2.2 修改核心配置
代码拿到手别急着起服务,先把配置改对。AI-Infra-Guard 的配置文件主要是config/guard.yaml,里面定义了扫描目标范围、技能检查项、告警阈值三个核心部分。
扫描目标范围这部分,需要你把要扫描的 AI 基础设施节点 IP 或网段填进去,例如:
scan: targets: - "192.168.1.10" - "192.168.1.0/24" exclude: - "192.168.1.200"注意exclude是用来排除某些运维保留地址的,用网段扫描的时候特别有用。技能检查项这部分默认配置已经覆盖了 CPU、内存、磁盘、GPU、容器运行时、Python 环境、常见 AI 框架等,按需增删。告警阈值我建议先用默认值,跑两轮真实数据后再根据实际情况调整。
另外docker-compose.yml里需要关注几个端口映射。默认情况下 Web UI 映射到宿主机的 8080,服务端 API 是 9090。如果你的宿主机端口被占用,直接改ports字段左侧的宿主机端口。实际部署时我还发现,项目默认把扫描器部署为单实例,扫描大批量节点时耗时较长。如果后续需要横向扩容,可以通过docker compose up --scale scanner=3来扩展扫描器数量,但注意这会触发并发扫描,目标节点上有防火墙的话容易误判为攻击行为,需要谨慎操作。
2.3 一键启动与验证
配置完成后,执行:
docker compose up -d第一次启动会自动构建镜像并创建容器,耐心等一下。启动完成后用docker compose ps查看状态,三个服务的状态都应该是 Up。接着验证服务端接口是否响应:
curl -s http://localhost:9090/api/v1/health正常情况下会返回{"status":"ok"}之类的 JSON。Web UI 直接浏览器打开http://localhost:8080,能看到登录页说明整套系统已经跑通了。默认账号密码在项目的.env文件里,首次登录后强制修改。
这里我要强调一个细节:扫描器容器的网络模式。默认配置下扫描器和宿主机共享网络模式,这样扫描器能拿到宿主机完整的网络权限,不至于扫描本机服务时被容器网络挡在门外。但如果你用的是 Docker Desktop for Windows,共享宿主机网络这个配置可能是失效的,因为容器实际上跑在虚拟机里。这种情况建议加一条 Docker Desktop 的路由规则,或者把宿主机 IP 通过环境变量传给扫描器。
登录前端控制台后,第一步就是把扫描目标加进去。这里的目标可以是 IP、网段,也可以是一个域名。加完之后点击“立即扫描”,就能看到任务进入队列。
3. 技能扫描实战:我拿真实 AI 节点做了次体检
3.1 准备一个标准的 AI 推理节点
这次扫描的目标是一台承载着模型推理服务的 GPU 节点,配置大概是这样:双路 Intel Xeon、256GB 内存、一张 NVIDIA A100 80GB、系统是 Ubuntu 20.04、装的是 CUDA 11.8、推理框架是 Triton Inference Server。为什么会选这个节点?因为它承载了团队里一个比较重要的在线推理服务,最近频繁被算法团队反馈“响应变慢”,我正好借这次扫描看看是不是基础设施层面出了问题。
扫描之前,我先在节点上手工确认了几个关键信息:NVIDIA 驱动版本、Triton Inference Server 的进程状态、GPU 利用率。这些信息是用来和 AI-Infra-Guard 的扫描结果做交叉验证的。
确认完毕后,我在 AI-Infra-Guard 控制台新建扫描任务,扫描目标填这台节点的 IP,扫描模板选择 “AI Inference Node Full Check”。这个模板是项目自带的,包含的技能检查项非常全:基础资源、GPU 栈、推理框架、网络模块、系统安全配置都有覆盖。
3.2 扫描任务发起与实时观察
点击开始扫描后,任务状态从 Pending 变成 Running。整个扫描过程大概持续了几分钟,具体耗时取决于目标节点开了多少探针。我在另一个终端窗口里用docker logs -f ai-infra-guard-scanner实时盯着日志,可以看到扫描器正在逐项检查目标的各个技能点。
这里科普一下 AI-Infra-Guard 的扫描逻辑,它的探针是分层的。第一层是基础探测,先确认目标节点的网络连通性和 SSH 可达性;第二层是系统级扫描,通过 SSH 执行一组预定义命令来采集 CPU 核数、内存大小、磁盘分区、内核版本等;第三层是技能专检,尝试探测目标节点上是否运行了特定的 AI 服务,比如检查 GPU 驱动是否加载、是否有推理框架的默认端口在监听、是否有模型仓库目录存在。
这种分层设计的好处是效率高,如果第一层都过不去就不会浪费时间往下扫。坏处是如果目标节点开了严格的 SSH 白名单,除特定用户外其他用户无法登录,那扫描器可能连门都进不去,直接返回不可达,看起来像是节点挂了。这个坑后面复盘部分我会详说。
扫描结束后,控制台的报告页展示了一份结构化的扫描结果。
3.3 扫描结果解读:哪些是绿灯,哪些是红灯
这份报告按检查项分类,每项都有状态(通过/未通过/告警)、实测值、参考建议三项信息。我捡几个关键的说:
GPU 栈检查这一项是绿灯,驱动版本 525.105.17,CUDA 版本 11.8,和预期一致。推理框架检测同样是绿灯,Triton 的 8000 端口在监听,进程状态正常。但 CPU 负载检查这一项红色告警,显示过去 15 分钟平均负载是 12.7,而这款 CPU 的逻辑核是 32 核,按常规经验负载不应该这么高。
我根据报告里的建议字段,先去目标节点上用了top和iotop排查。一通操作下来,发现是某个数据预处理任务在疯狂读磁盘,占了大量 IO 带宽,服务端响应慢的根源基本锁定在这个 IO 争抢上。AI-Infra-Guard 虽然没有直接告诉我瓶颈是 IO,但它提示了 CPU 负载异常这个线索,让我少走了不少弯路。
另一个有意思的发现是,扫描报告提示目标节点开放了一个管理端口 8088,但团队内部并没有登记这个端口。顺着线索查下去,发现是某位同事为了调试便利临时起的一个 Web 服务,没设认证就暴露在内网。这个发现让安全团队多了一个排查任务。这个案例也说明,AI-Infra-Guard 虽然不是专职安全工具,但它的端口探测能力在资产管理层面确实能帮上忙。
3.4 扫描报告的自动化落库与通知
AI-Infra-Guard 的扫描结果是可落库的。它内置的存储层会按时间戳保存每次扫描的原始数据,方便后续做趋势分析和对比。我个人比较推荐把报告导出成 JSON 格式,然后通过项目自带的 webhook 模块把结果同步到内部工单系统。
这里给一个小建议:扫描任务一定要配置调度周期。AI-Infra-Guard 支持 cron 表达式,我设置为每天凌晨 2 点跑一轮全量扫描,覆盖所有生产 AI 节点。这样每天早上到工位打开控制台,就能看到一份昨夜的基础设施健康速报。遇到状态变化能第一时间发现,比出事之后再去翻日志强太多。
4. 一次“漏报”事故的完整复盘:健康节点差点被误判成僵尸
4.1 事故现场:明明活着,扫描器却说挂了
使用 AI-Infra-Guard 的第二周,我安排了一次针对所有 GPU 节点的例行扫描。扫描完成后,报告里有一个节点被标记为“不可达”,状态是红色,探针显示“SSH 认证失败”加“网络超时”。
这个节点是我们团队压箱底的另一个推理节点,上周还在正常跑着定时任务,完全没有要宕机的预兆。按照报告的状态,下一步常规处理就是拉起告警、让值班同事去机房做硬件排查,或者直接考虑重建节点。但我心里犯嘀咕,因为这个节点上周我还在上面跑过脚本,不可能说挂就挂。
我决定先不按“节点宕机”预案走,而是亲自连上去看看。结果非常打脸——我用同一个 SSH 密钥手动连接,秒连,而且uptime显示这台机器已经稳定运行了 87 天。CPU、内存、磁盘都没有异常,监听端口全部正常,Triton 推理服务还在对外响应请求。健康得不能再健康了。
这个结果让人有点懵:如果节点是健康的,那 AI-Infra-Guard 为什么会报“不可达”?如果扫描器报告错了,那以后还怎么信任它的结论?带着这个疑问,我开始了这次事故的完整排查。
4.2 排查过程:日志逐字段比对
第一步是看扫描器日志,目标节点在扫描任务里确实被标记为失败,错误信息是 “Failed to establish SSH connection: handshake timeout”。
第二步,我在扫描器容器里手动执行了一次 SSH 连接测试,用的命令和配置与扫描脚本完全一致,结果依然提示超时。这说明问题不是偶然的网络抖动,而是扫描器在特定网络环境下持久存在的问题。
第三步是关键——我尝试在宿主机(非容器)里执行同样的 SSH 命令,结果竟然通了。至此,问题从“节点挂了”变成“容器内网络到节点不通”。继续查容器网络配置,发现扫描器容器被分配了一个 IP 段,而这个 IP 段和目标节点处于不同的 VLAN。宿主机到目标节点能通,是因为宿主机有往那个 VLAN 的正确路由;而容器跑在 Docker 的默认 bridge 网络上,根本不知道那条路由该走哪里。
这就是经典的容器网络路由缺失问题。容器内ip route里没有去往目标 VLAN 的静态路由,默认网关指向 Docker 的 bridge 网关,而这个网关不会把包转发到目标 VLAN,于是连接请求在超时之后被判定为不可达。
4.3 根因确认:网络路由表的宿主机与容器差异
为了证实这个判断,我在容器里和目标节点上分别抓包,对比 TCP SYN 包的走向。抓包结果显示,扫描器容器发出的 SYN 包到了宿主机之后,并没有被转发到目标节点所在 VLAN 的网关,而是直接丢掉了。而宿主机自己发出的 SYN 包能看到正确的路由路径,网关成功转发。
这个现象的根本原因在于 Docker 默认 bridge 网络的隔离性。容器内的网络栈和宿主机是隔离的,它只知道自己的网段和 docker0 的网关地址。如果你要扫描的目标和宿主机不在同一个广播域或路由域内,就得显式告诉容器网络如何到达那个目标,否则所有数据包都会掉进黑洞。
确认根因后,修复方案很明确:在 Compose 文件中把扫描器指向宿主机网络模式,或者给容器自定义网络添加一条静态路由。考虑到这台机器上还有其他容器服务,直接用 host 网络模式会带来端口冲突风险,所以我选择了自定义网络加静态路由的方案,针对性解决扫描器到目标 VLAN 的通讯问题。
在docker-compose.yml里,我给扫描器服务新增了自定义网络配置,并往该网络里注入了一条路由规则。改完后重启扫描器容器,再次发起扫描,目标节点的状态从红色变成绿色。
4.4 复盘总结:为什么这不算工具“漏报”
排查结束之后,团队里有人开玩笑说“AI-Infra-Guard 有漏报问题,应该反馈给开发者修 bug”。但我不这么看。准确地说,这次事件是部署拓扑缺陷导致的误报,不是扫描器本身的漏报。
所谓“漏报”,通常指目标确实有问题但工具没有发现。而这次是工具把健康节点误判为不可达,属于配置层面的误报。AI-Infra-Guard 的扫描探针本身没有问题,它只是忠实地记录了“从这个容器视角看,目标节点不可达”这一事实。扫描器没有魔法戒指去感知全局网络,它只能反映自己所在网络环境能感知到的东西。
这次事故真正的教训是:部署扫描器之前,必须先把目标网络的拓扑摸清楚。如果你要扫描的节点分散在多个 VLAN 里,那务必确保扫描器所在容器的网络能和所有目标 VLAN 路由打通,否则“漏报”的根本不在扫描器身上,而在网络规划的人身上。
提示:正式部署前,建议先用
docker exec -it <scanner-container> bash进入容器,手动 ping 或 nc 测一下目标节点的端口连通性。这一步能提前挡掉 90% 的网络误配问题。
5. 实战中的避坑清单与进阶玩法
5.1 高频问题速查表
| 现象 | 可能原因 | 解决办法 |
|---|---|---|
docker compose up提示镜像拉取超时 | 网络问题或镜像源被墙 | 配置 Docker 镜像加速器,或改为本地构建 |
| Web UI 打不开 | 宿主机端口被占用或映射错误 | 修改 compose 文件中的端口映射,检查端口占用 |
| 扫描任务一直 Pending | 服务端队列未消费或扫描器未注册 | 查看服务端日志,确认 scanner 是否正常启动并注册到服务端 |
| 扫描结果全是 Unreachable | 容器网络与目标节点不通 | 检查路由、防火墙、VLAN 隔离 |
| SSH 认证失败 | 密钥未挂载到扫描器容器 | 在 compose 文件中正确挂载宿主机 SSH 密钥,并设置好权限 |
| GPU 技能检测失败 | 目标节点近期更新过驱动,扫描器内置驱动指纹表过旧 | 更新扫描器镜像或手动添加新的驱动指纹规则 |
| 磁盘检查提示空间不足但实际还有空间 | 扫描器默认阈值配置过严 | 在配置文件中调整磁盘剩余空间告警阈值 |
这几个是实战里最容易碰到的高频项。尤其是 SSH 密钥挂载这一项,很多第一次部署的人会忽略,导致扫描器无法以预期的用户权限去对目标执行命令。权限不够的话很多检测项都会失败或降级,但日志里看起来又像“正常超时”,非常迷惑。
5.2 我踩过的其他坑
- 镜像构建失败:项目里某些底层依赖包体积很大,构建时经常超时。解决方案是给 Docker daemon 配置国内可用的镜像加速器,同时把构建过程中的基础镜像改为私有 registry 里的缓存版本,构建速度快了不止一倍。
- 端口冲突:默认的控制台端口 8080 比较抢手,很多机器上已经跑了别的 Web 服务。建议使用 18080、28080 这类高位端口来做宿主机映射,降低冲突概率。
- 扫描深度不够:如果目标节点有启动 agent 权限,可以部署 AI-Infra-Guard 的 Agent 模式。Agent 模式能采集到更多系统层面的信息,比如 Docker 容器列表、进程级 GPU 使用率,这是纯 SSH 探针模式看不到的。
- 数据库存储膨胀:扫描结果长期积累之后,PostgreSQL 或 SQLite 的数据量会变得有点大。建议配置定时任务定期清理三个月前的历史扫描数据,只保留统计摘要,以控制存储成本。
- 误报处理机制:建议在收到告警时,先通过工单系统发起确认流程,由人工快速验证再决定是否触发后续响应。纯粹依赖告警自动化处理网络类问题,会有一大批因为安全策略或路由策略导致的麻烦事。
5.3 进阶玩法:AI-Infra-Guard 还能这样用
跑通基础的技能扫描之后,我慢慢把它往更多场景延伸了。
第一个进阶用法是“变更前基线扫描”。每次升级推理框架、调整 GPU 驱动之前,先让 AI-Infra-Guard 跑一次全量扫描,把当前环境的技能基线存下来;变更完成后再跑一次,对比两份报告,能一眼看出哪些能力变了、哪些依赖出现了回归。有几次就是靠这份对比报告,在模型版本升级后立刻发现了框架版本不兼容的问题,避免带病上线。
第二个进阶用法是“资产台账自动更新”。AI-Infra-Guard 的扫描结果里有很多元数据,比如主机名、操作系统版本、CPU 核数、内存容量等。把这些数据同步到 CMDB 系统之后,资产台账的准确性提升了不少。内网的资产管理审计需求也能顺带覆盖掉,一举两得。
第三个进阶用法是“多环境对比”。把测试环境、预发环境、生产环境的扫描结果放在一张表里粘贴对比,环境一致性一目了然。某次大版本升级的时候,就是靠这个对比发现测试环境 GPU 驱动比生产环境新了两个版本,立刻拉平了版本号再放流量,规避了一次潜在的推理结果不一致问题。
第四个进阶用法是“AI 就绪度评估”。如果团队在评估是否要上一个新的 AI 工作负载,我会先在目标节点上跑一轮 AI-Infra-Guard 的专项扫描,根据报告里的能力矩阵去判断“这个节点适合不适合跑这一类的负载”。项目内置的 AI 技能矩阵输出,实际评估效率比手动逐项验证高出几个数量级。
6. 写在最后的个人体会
AI-Infra-Guard 本身不是那种复杂得离谱的项目,但它非常精准地解决了一个实际痛点:AI 基础设施不像普通 Web 服务,它的组件太杂、版本太乱、依赖太深,靠人工巡检基本不可能做到全面覆盖。而 Docker 部署又把使用门槛压低了一大截。真正的好工具就是这样,不是功能越多越牛,而是能让人一扫就知道“我现在这套东西到底行不行、哪里不行”。
我个人在实际操作中体会最深的一点是:不要把扫描报告当成“圣旨”,要把它当成“线索”。任何自动化扫描工具都可能因为网络环境、配置差异、安全策略产生误判,但 AI-Infra-Guard 已经把大量重复性的检测工作做掉了,我们就该把精力集中在它标出来的那些异常项上,逐个人工确认、定位根因、形成闭环。这次复盘的那次“漏报”,说到底不是工具骗了我,而是我当初部署的时候少看了一眼路由表,多花了半小时排查而已。
最后再分享一个小技巧:AI-Infra-Guard 的扫描报告默认是存在容器里的,如果容器重建,历史数据可能就没了。我在 compose 文件里给数据目录加了一个宿主机卷挂载,确保扫描历史不会因为容器生命周期而丢失。这个细节看起来不起眼,真遇到需要回溯“三个月前这个节点的 GPU 驱动版本是多少”这种问题时,你就会明白它有多值钱。