云原生 · AI基础设施 · 运维工程师

企业级 RAG 智能知识库
私有化部署项目规划

基于 K8s + vLLM + Dify + Milvus 的完整私有化大模型知识库系统,涵盖项目规划、架构设计、资源配置、面试问答全套指南。

项目周期 2025.08 – 2026.05
目标企业规模 500 – 1000 人
部署方式 本地私有化内网
核心GPU NVIDIA A10
📋
项目概述
背景、目标与核心价值
项目背景

某企业(500–1000人规模)业务知识分散于多部门文档、历史案例、操作手册中,员工获取信息依赖人工经验传递, 新员工上手周期长、同类问题重复沟通,内部支持响应效率低。

本项目由团队协作完成,我作为运维工程师主导底层 K8s 集群与基础设施建设,支撑大模型与 RAG 平台的整体私有化部署, 构建企业级智能知识库,实现业务知识统一沉淀与智能问答,全程数据不出内网,无需依赖外部 API。

核心目标
  • 员工可通过自然语言检索内部文档
  • 重复问题自动回答,减少人工答疑
  • 知识沉淀不随人员流动而流失
  • 数据完全私有化,满足合规要求
  • 系统高可用,支撑全员并发访问
技术栈全览
Kubernetes Docker GPU Operator vLLM DeepSeek Dify Milvus BGE-M3 Nginx Harbor PostgreSQL Redis MinIO NVIDIA A10
🏗️
系统架构
完整的私有化部署架构与数据流向
🌐 接入层
员工浏览器 / APP
VPN(外网员工)
🔀 入口层
Nginx(统一入口 + 负载均衡)
📦 K8s 编排层(3Master + 4Worker)
Dify(RAG平台+前端)
vLLM(推理服务)
Milvus(向量库)
PostgreSQL
Redis
MinIO
Harbor(镜像仓库)
🖥️ 硬件层
Master × 3
推理节点 × 1(A10 × 2张)
向量化节点 × 1(A10 × 1张)
存储节点 × 2(2TB SSD)
RAG 问答数据流
员工提问 Nginx转发 Dify接收请求 BGE-M3向量化Query Milvus召回Top-K文档片段 Reranker重排序 vLLM(DeepSeek)生成回答 返回员工
⚙️
资源配置
硬件、软件、网络完整清单
服务器节点规划
节点角色 数量 CPU 内存 存储 GPU
Master节点 3台 8核 16GB 100GB SSD
推理节点 1台 32核 64GB 500GB SSD A10 × 2张
向量化节点 1台 16核 32GB 200GB SSD A10 × 1张
存储节点 2台 16核 32GB 2TB SSD
GPU 显存分配规划
节点 GPU型号 显存 运行服务 显存占用
推理节点 A10 × 2 48GB DeepSeek 14B(双卡张量并行) ~40GB(含KV Cache)
向量化节点 A10 × 1 24GB BGE-M3 + Reranker-Large ~5GB
AI 模型选型
用途 模型 显存需求 选型理由
推理问答 DeepSeek-R1-Distill-Qwen-14B 双卡约40GB
(权重28+缓存)
中文效果强、开源免费、支持多卡并行;复杂业务逻辑可用其推理能力(备选 Qwen2.5-14B-Instruct,纯指令、延迟更低)
文本向量化 BGE-M3 ~3GB 中文检索最强Embedding模型
重排序 BGE-Reranker-Large ~2GB 与BGE-M3配套,提升召回精度
服务器硬件(7台)
18–26万
A10 显卡(3张)
6–9万
网络设备
1–2万
软件(全开源)
0元
合计预估
25–37万
📅
项目规划
分阶段实施路径(2025.08 – 2026.05)
第一阶段 · 2025.08 – 09
基础环境搭建
采购服务器与A10显卡,完成机房上架与网络规划。使用 kubeadm 搭建 3Master+4Worker K8s 集群, 配置节点标签与污点,安装 NVIDIA GPU Operator 纳管所有 GPU 资源, 验证 CUDA 环境与 Device Plugin 正常工作。部署 Harbor 私有镜像仓库。
kubeadm GPU Operator Harbor CUDA验证
第二阶段 · 2025.10 – 11
大模型推理服务部署
基于 vLLM 容器化部署 DeepSeek-R1-Distill-Qwen-14B,配置多卡张量并行(tensor-parallel-size=2)切分模型权重, 启用 PagedAttention 与连续批处理提升吞吐。通过 K8s Service 暴露 OpenAI 兼容接口, 完成压测验证并发能力与响应延迟。配置节点亲和性确保推理任务调度至 GPU 节点。
vLLM DeepSeek 14B 张量并行 PagedAttention 压测
第三阶段 · 2025.12 – 2026.01
RAG 平台与向量库部署
K8s 上部署 Milvus 向量数据库(集群模式),配置持久化存储与备份策略。 部署 BGE-M3 Embedding 服务与 Reranker 服务。私有化部署 Dify 平台, 对接 vLLM 模型服务与 Milvus 向量库,搭建知识库问答与多轮检索工作流, 全链路联调验证。
Milvus BGE-M3 Dify 工作流编排
第四阶段 · 2026.02 – 03
文档入库与参数调优
完成 Word/PDF/Markdown 等多源文档批量入库与语义切片,调优分段长度策略、 Top-K 召回数量与 Rerank 重排序阈值参数,持续评测检索准确率。 配置 Nginx 统一入口与负载均衡,完成内网域名解析与访问控制配置。
文档入库 语义切片 Top-K调优 Nginx配置
第五阶段 · 2026.04 – 05
上线运营与持续沉淀
系统正式上线,全员开放访问。配置监控告警(Prometheus + Grafana)监控 GPU 利用率、 推理延迟、向量库查询耗时等核心指标。持续沉淀业务案例,建立知识库更新机制, 定期评估问答质量并迭代优化。
Prometheus Grafana 监控告警 知识运营
⚠️
风险评估
主要技术风险与应对策略
显存不足导致推理服务OOM崩溃
应对:配置 K8s Resource Limit 限制显存申请;启用 vLLM 的 gpu-memory-utilization 参数控制显存占用比;设置 Pod 自动重启策略。
Master节点单点故障导致集群不可用
应对:采用3个Master节点保障etcd高可用;配置 VIP + keepalived 实现 APIServer 高可用;定期备份etcd数据。
检索准确率低,问答质量差
应对:调优分段策略(chunk_size/overlap);增加 Rerank 重排序层;针对专业术语补充同义词词典;定期人工评测并迭代。
Milvus 向量库数据丢失
应对:配置持久化存储(PVC + StorageClass);定期全量备份向量索引;重要文档保留原始文件备份。
GPU驱动版本与CUDA不兼容
应对:使用 GPU Operator 统一管理驱动版本,避免手动安装;测试环境先验证版本组合后再上生产。
🎤
面试项目介绍话术
面试时介绍这个项目的完整口述脚本(约90秒)
💬 推荐话术脚本 · 90秒版本

"我来介绍一下我做过的一个 企业级 RAG 智能知识库私有化部署项目(停顿0.5秒)

项目背景是,客户是一家五六百人规模的企业,业务文档分散在各部门,员工找资料要靠问人, 新人上手特别慢,HR 每天回答的都是同样的问题。他们的核心诉求是 数据不能上云,必须私有化部署

我负责整个底层基础设施的搭建和运维。首先我在本地搭了一个 7节点的 K8s 集群,3个Master保证高可用, 4个Worker节点按角色划分,推理节点、向量化节点、存储节点分开。

GPU 这块选了 NVIDIA A10,一共3张, 因为A10是企业级推理卡,功耗低、稳定性好,适合7×24小时运行。 用 GPU Operator 统一纳管, 通过节点亲和性把推理和向量化任务隔离调度,避免显存抢占。

推理服务用 vLLM 部署 DeepSeek 14B, 开启多卡张量并行解决单卡显存不够的问题, PagedAttention 和连续批处理让吞吐提升明显。 知识问答场景对延迟敏感,所以我做了 prompt 控制和参数调整,避免思维链拖慢响应。 上层用 Dify 做 RAG 应用平台, 对接 Milvus 向量库,搭了知识库问答和检索工作流。

整个链路全程内网,Nginx 统一入口,Harbor 管镜像,K8s 保高可用。 员工通过浏览器直接访问,外网员工走 VPN。 上线后重复问题的响应效率得到了显著提升。"

面试常见问题与回答
覆盖技术原理、选型理由、问题排查等高频考点
Q1
为什么选择 vLLM 做推理框架,而不是直接用 Ollama 或者 FastAPI 加载模型?

主要有三个原因:

  • 并发能力:Ollama 是单请求串行处理,并发高了响应慢。vLLM 的连续批处理(Continuous Batching)可以把多个请求动态合并成一个批次推理,吞吐量差距在高并发下能有5-10倍。
  • 显存管理:vLLM 的 PagedAttention 把 KV Cache 做了分页管理,显存利用率更高,能支持更长的上下文而不OOM。
  • 多卡支持:vLLM 原生支持张量并行,一行参数 tensor-parallel-size=2 就能把模型权重切到两张卡上,解决单卡显存不够的问题。Ollama 在多卡并行这块支持没那么完善。
面试加分点:可以补充"我们做过压测,同样的A10双卡环境下,vLLM的QPS是Ollama的约4倍"
Q2
K8s 集群里 GPU 资源是怎么管理和调度的?

分三个层面管理:

  • 资源纳管:用 NVIDIA GPU Operator 自动安装驱动、CUDA、Device Plugin,不需要每个节点手动配置,集群扩容加GPU节点也很方便。
  • 资源隔离:通过节点标签(node label)区分推理节点和向量化节点,再用 nodeAffinity 配置 Pod 的调度偏好,推理任务只调到推理节点,向量化任务只调到向量化节点,避免显存抢占。
  • 资源配额:在 Pod 的 resources 里设置 nvidia.com/gpu: 1 或 2,K8s 会保证这个 Pod 独占对应数量的GPU,不会出现多个Pod争一张卡的情况。
# Pod 资源配置示例 resources: limits: nvidia.com/gpu: 2 # 独占2张GPU nodeAffinity: requiredDuringScheduling: - key: role operator: In values: ["inference"]
Q3
RAG 检索准确率不高怎么排查和优化?

我们遇到过这个问题,排查思路是:

  • 定位问题层:先看是检索层的问题还是生成层的问题。把检索出来的文档片段直接展示出来,如果片段本身就不相关,是检索问题;片段相关但回答不对,是生成问题。
  • 分段策略调优:chunk_size 太大上下文噪音多,太小语义不完整。我们针对不同文档类型(FAQ类、手册类)设置了不同的分段长度,FAQ用短分段,手册用长分段加overlap。
  • 召回参数调整:Top-K 从默认3调到5-8,召回更多候选,再用 Reranker 重排序筛掉不相关的,召回率和精度都有提升。
  • Embedding模型:换成 BGE-M3 替代默认模型,中文场景下检索相关性明显更好。
关键词:分段策略、Top-K、Rerank重排序、Embedding模型选型——这四个是调优的核心抓手
Q4
为什么选 A10 而不是 RTX 4090 或 A100?

这是一个典型的企业生产环境选型问题,我们的考量是:

  • vs RTX 4090:4090是消费级卡,功耗450W,7×24小时满载运行散热压力大,没有ECC内存纠错,长时间推理可能因内存错误崩溃,也没有企业级质保。A10功耗只有150W,企业级稳定性更可靠。
  • vs A100:A100单张8-15万,我们3张A10的成本还不到一张A100,但对于500-1000人企业的并发量完全够用,A100的算力在这个场景下是浪费。
  • A10的优势:24GB显存够跑14B模型双卡并行,功耗低、散热好、有企业质保,性价比在中小企业生产场景下最优。
Q5
K8s Master 节点挂了怎么办?怎么保证高可用?
  • 3个Master节点:etcd 是奇数节点分布式存储,3个节点允许1个挂掉集群仍然正常工作。
  • APIServer 高可用:用 keepalived + VIP 做虚拟IP漂移,任意一个Master挂掉,VIP自动漂移到其他Master,kubectl 和 Worker节点的连接不中断。
  • etcd 备份:定期执行 etcdctl snapshot save 备份etcd数据,出现问题可以快速恢复。
  • Worker节点的应用:K8s 会自动把故障节点上的 Pod 重新调度到其他健康节点,应用层自动恢复。
面试官问这个是考察你对K8s高可用的理解深度,3Master + keepalived VIP + etcd备份是标准答案三件套
Q6
用户数据怎么保证安全?有没有可能泄露?
  • 数据不出内网:整套系统部署在企业内网,vLLM、Milvus、Dify全部私有化,不调用任何外部API,从根本上杜绝数据外传。
  • 访问控制:Nginx 层配置IP白名单,只允许内网IP段访问;外网员工必须先连VPN再访问。
  • 镜像安全:所有镜像走私有 Harbor 仓库,不从公网拉取,避免镜像投毒风险。
  • 存储隔离:Milvus 向量数据和原始文档存储在内网存储节点,配置 PVC 权限隔离,非授权 Pod 无法访问。
Q7
张量并行是什么?你们是怎么配置的?

张量并行(Tensor Parallelism)是一种模型并行方式,把模型的权重矩阵按列或行切分到多张GPU上,每张GPU只保存一部分权重,推理时各卡并行计算再合并结果。

我们的场景:14B 模型 FP16 权重约 28GB(参数量 × 2 字节),单张 A10 只有 24GB 显存装不下,所以用 tensor-parallel-size=2 切到两张 A10 上,每张卡分到约 14GB 权重。

注意区分两个数字:14GB 是切分后的「权重显存」,但实际运行还要叠加 KV Cache 和激活值。我们设 gpu-memory-utilization=0.85,每卡实际占用约 20GB,剩下的显存留给 KV Cache 做并发缓存——这个余量直接决定能扛多少并发,不能拉满。

# vLLM 启动命令示例 python -m vllm.entrypoints.openai.api_server \ --model deepseek-ai/DeepSeek-R1-Distill-Qwen-14B \ --tensor-parallel-size 2 \ --gpu-memory-utilization 0.85 \ --host 0.0.0.0 \ --port 8000
区分概念:张量并行是切权重(同一层分到多卡);流水线并行是切层(不同层分到多卡)。我们用的是张量并行。
显存速算:FP16 权重 ≈ 参数量(B) × 2 GB。14B → 28GB;7B → 14GB;32B → 64GB。再留 20–30% 给 KV Cache。
Q8
项目遇到过什么难点?怎么解决的?

遇到过三个比较典型的难点:

  • 难点1 – 显存OOM:初期推理和向量化服务部署在同一节点,高并发时显存被抢占导致推理服务OOM崩溃。解决方案是通过节点亲和性把两类任务调度到不同节点,彻底隔离显存资源。
  • 难点2 – 检索准确率低:初期用默认分段策略,长文档切出来的片段语义不完整,召回质量差。通过调研不同文档类型,针对性调整chunk_size和overlap,加上Reranker重排序,准确率得到明显提升。
  • 难点3 – Milvus集群模式部署复杂:Milvus依赖etcd和MinIO,初期配置不当导致集群启动失败。通过仔细研读官方文档、拆解各组件依赖关系,重新规划存储配置后解决。
面试技巧:难点回答要有"问题 → 排查 → 解决"的完整闭环,展示你的问题解决能力而不只是踩坑经历
Q9
PagedAttention 是什么原理?为什么能提升推理效率?

PagedAttention 借鉴了操作系统的虚拟内存分页机制。

传统推理框架会为每个请求预分配一块连续的 KV Cache 显存,但请求的实际长度不固定,导致大量显存碎片浪费,真实利用率只有20-40%。

PagedAttention 把 KV Cache 切成固定大小的"页",按需动态分配,不同请求的页可以不连续存放,显存利用率提升到接近100%。

结果是:同样的显存能并发处理更多请求,推理吞吐量大幅提升,高并发场景下效果特别明显。

类比记忆:PagedAttention = 操作系统的虚拟内存分页,解决的是KV Cache的显存碎片问题
Q10
Milvus 和普通数据库有什么区别?为什么用向量数据库?

核心区别在于检索方式不同:

  • 普通数据库(MySQL等):做精确匹配,用SQL查"标题='xxx'"或关键词like查询,找不到语义相近的内容。
  • 向量数据库(Milvus):把文本转成高维向量(embedding),存储向量。查询时把问题也转成向量,计算向量间的余弦相似度,返回语义最相近的文档片段,哪怕用词不同也能找到。

比如员工问"怎么请假",文档里写的是"休假申请流程",关键词搜不到,向量检索因为语义相似可以召回。这就是RAG必须用向量数据库的原因。

选Milvus而不是Faiss:Milvus支持持久化、动态增删、水平扩展,适合生产;Faiss是内存索引库,适合研究。
规模判断:500–1000人、文档百万级向量内,Milvus Standalone(单机版)就够,运维简单;只有到千万级向量、高并发写入才上 Cluster 模式(依赖 etcd+MinIO+Pulsar,运维成本高)。面试被问"为什么上集群"答不上来反而扣分,按真实数据量说。
🛠️ 运维核心考点专区 · Q11–Q28(监控 / 日志 / 网络 / 存储 / CI-CD / 排障 / Linux)
Q11
这套系统你是怎么做监控的?GPU 和推理服务的核心指标怎么采集?

监控是这个项目我作为运维最核心的工作,分四层:

  • 主机层:每个节点装 node-exporter,采集 CPU、内存、磁盘、网络。Prometheus 抓取,Grafana 出大盘。
  • GPU 层:用 NVIDIA 的 dcgm-exporter(以 DaemonSet 跑在 GPU 节点上),采集显存占用、GPU 利用率、温度、功耗、ECC 错误。这是 nvidia-smi 拿不到的细粒度指标。
  • K8s 层:kube-state-metrics + cAdvisor,监控 Pod 重启次数、容器资源用量、节点状态。
  • 应用层:vLLM 本身暴露 /metrics 接口(Prometheus 格式),能拿到推理延迟、吞吐 token/s、KV Cache 利用率、排队请求数。Milvus 也有自己的 metrics 端点。
# dcgm-exporter 关键指标 DCGM_FI_DEV_GPU_UTIL # GPU利用率% DCGM_FI_DEV_FB_USED # 已用显存MB DCGM_FI_DEV_GPU_TEMP # GPU温度 DCGM_FI_DEV_POWER_USAGE # 功耗W # vLLM 暴露的推理指标 vllm:num_requests_running # 正在推理的请求数 vllm:num_requests_waiting # 排队等待数(这个涨说明要扩容) vllm:gpu_cache_usage_perc # KV Cache占用率
运维岗加分:别只说"用Prometheus+Grafana监控",要说出具体exporter和指标名。GPU监控的核心是 dcgm-exporter,推理服务监控的核心是 vllm 的 /metrics——这两个能说出来,面试官就知道你真做过。
Q12
告警是怎么配的?举几个你设置的告警规则。

用 Prometheus 的 Alertmanager,告警分级推送(企业微信/钉钉机器人 + 邮件,紧急的电话)。几条核心规则:

  • 显存告警:GPU 显存使用率 > 90% 持续 2 分钟,告警——可能要 OOM。
  • 推理排队:vllm:num_requests_waiting > 20 持续 1 分钟,说明并发顶不住,提示扩容。
  • Pod 重启:kube_pod_container_status_restarts_total 在 5 分钟内增长,说明服务在崩溃重启。
  • 节点失联:up == 0 或 node NotReady,立即电话告警。
  • 磁盘水位:存储节点磁盘 > 85%,提前清理(向量库和日志最容易撑爆)。
# Prometheus 告警规则示例 - alert: GPUMemoryHigh expr: DCGM_FI_DEV_FB_USED / DCGM_FI_DEV_FB_TOTAL > 0.9 for: 2m # 持续2分钟才告警,避免抖动误报 labels: { severity: critical } annotations: summary: "GPU {{$labels.gpu}} 显存超90%"
关键细节:告警一定要带 for(持续时间)避免瞬时抖动误报,要分 severity 级别。面试官问告警就是想确认你懂"告警降噪",不是把阈值一设就完事。
Q13
集群里这么多服务,日志怎么收集和排查?ELK 怎么落地的?

用 EFK 方案(K8s 里更常用 Fluent Bit 替代 Logstash,更轻量):

  • 采集:Fluent Bit 以 DaemonSet 部署在每个节点,挂载 /var/log/containers,自动收集所有 Pod 的 stdout/stderr 日志。
  • 处理:Fluent Bit 解析日志、打上 K8s 元数据标签(namespace、pod、container),过滤掉无用的 health check 噪音。
  • 存储检索:送进 Elasticsearch,按天建索引(方便定期清理冷数据),Kibana 做查询和可视化。
  • 排查实战:推理服务报错时,直接在 Kibana 按 pod 名 + 时间范围过滤,比 kubectl logs 翻历史方便得多,尤其 Pod 重启后旧日志已经没了,集中收集就能回溯。
为什么 Fluent Bit 不用 Logstash:Logstash 吃内存(JVM,动辄1GB+),Fluent Bit 是 C 写的,内存几十MB,DaemonSet 跑每个节点上更合适。这个对比能体现你做过资源权衡。
Q14
一个 Pod 起不来,状态一直 CrashLoopBackOff / Pending,你怎么排查?

这是运维日常,我的标准排查流程:

# 1. 先看事件,80%的问题这一步就定位了 kubectl describe pod <pod> -n <ns> # 看 Events 段 # 2. 看容器日志(崩溃看上一次的日志用 -p) kubectl logs <pod> -n <ns> --previous # 3. 看 Pod 详细状态和退出码 kubectl get pod <pod> -o yaml | grep -A5 state

按状态对症:

  • Pending:调度不上去。常见原因——资源不够(GPU 被占满)、节点亲和性/污点不匹配、PVC 没绑定。describe 的 Events 会直接说。
  • CrashLoopBackOff:容器启动后崩溃在重启。看 logs --previous,常见是配置错误、依赖服务连不上、OOMKilled(describe 看 Last State)。
  • ImagePullBackOff:拉镜像失败。检查 Harbor 地址、imagePullSecret、镜像 tag 是否存在。
  • OOMKilled:内存超 limit 被杀。调大 limit 或查内存泄漏。
回答这种题的精髓是体现"流程化排查":describe 看事件 → logs 看日志 → 按状态分类对症。别一上来就猜原因,要展示方法论。
Q15
Dify 调不通 vLLM 的服务,K8s 里服务之间网络不通怎么排查?

K8s 网络排查从下往上分层定位:

  • ① Pod 自己活着吗:kubectl get pod 看 vLLM Pod 是不是 Running、Ready 1/1。没 Ready 说明探针没过,服务没真正起来。
  • ② Service 选对 Pod 了吗:kubectl get endpoints <svc> 看有没有后端 IP。空的说明 Service 的 selector 标签和 Pod 标签对不上——这是最高频的坑。
  • ③ DNS 解析通吗:进一个 Pod 里 nslookup <service>.<namespace>,解析不了是 CoreDNS 问题。
  • ④ 端口对吗:Service 的 targetPort 要和容器实际监听端口一致(vLLM 是 8000)。
  • ⑤ 网络策略拦了吗:有没有 NetworkPolicy 把流量挡了。
# 临时起个调试 Pod 测连通性 kubectl run debug --rm -it --image=nicolaka/netshoot -- bash # 在里面测: curl http://vllm-svc.default:8000/v1/models # 测服务 nslookup vllm-svc.default # 测DNS
最常见根因:Service selector 和 Pod label 不匹配 → endpoints 为空。记住"先看 endpoints 有没有后端"这一招,能秒杀一半网络问题。
Q16
Milvus、PostgreSQL 这些有状态服务的存储怎么做的?PV/PVC/StorageClass 讲一下。

有状态服务的数据必须持久化,不能存容器里(Pod 一重建就没了)。三个概念的关系:

  • PV(PersistentVolume):实际的存储资源,对应后端的一块磁盘/NFS/Ceph。
  • PVC(PersistentVolumeClaim):Pod 对存储的"申请单",声明要多大、什么读写模式。
  • StorageClass:动态供给的模板。配了 SC 后,创建 PVC 会自动生成对应 PV,不用手动建。

我们的方案:存储节点用 SSD,通过 StorageClass 做动态供给。Milvus、PostgreSQL 用 StatefulSet 部署(保证 Pod 名字稳定、PVC 一一对应),配 volumeClaimTemplates 自动给每个副本分配独立存储。

为什么有状态服务用 StatefulSet 不用 Deployment:StatefulSet 保证 Pod 有稳定的网络标识(pod-0、pod-1)和绑定的持久存储,重建后还挂回原来的盘。Deployment 的 Pod 是无差别的,不适合数据库。
Q17
Nginx 作为统一入口,你具体配了什么?负载均衡策略怎么选的?

Nginx 在这套系统里干三件事:反向代理、负载均衡、访问控制。

# 推理服务负载均衡(多个vLLM副本) upstream vllm_backend { # least_conn:把请求给当前连接数最少的后端 # 推理请求耗时长短不一,比轮询更均衡 least_conn; server 10.0.1.11:8000; server 10.0.1.12:8000; } server { listen 80; location / { # IP白名单,只放内网网段 allow 10.0.0.0/8; deny all; proxy_pass http://vllm_backend; # 大模型流式输出,关闭缓冲让token实时返回 proxy_buffering off; # 推理慢,超时调大,否则长回答会被掐断 proxy_read_timeout 300s; } }
针对大模型场景的两个关键配置:① proxy_buffering off(流式输出实时返回)② proxy_read_timeout 调大(长文本生成耗时久)。能说出这两个,说明你真在 LLM 场景下配过 Nginx,不是套模板。负载均衡选 least_conn 而非默认轮询,因为推理请求耗时差异大。
Q18
这个项目有没有做 CI/CD?Jenkins + Harbor 的流程讲一下。

RAG 应用层(Dify 自定义组件、配置)和一些工具镜像走 CI/CD,模型镜像因为大不频繁动。流程:

  • ① 代码提交:开发推代码到 GitLab,触发 Jenkins Webhook。
  • ② 构建:Jenkins Pipeline 拉代码 → docker build 打镜像 → 打 tag(用 git commit id 或时间戳,不用 latest,方便回滚)。
  • ③ 推送:推到私有 Harbor 仓库。
  • ④ 部署:kubectl set image 更新 Deployment 镜像,或改 manifest 后 apply,K8s 滚动更新。
  • ⑤ 回滚:出问题 kubectl rollout undo 一键回退上个版本。
# Jenkinsfile 核心阶段 stage('Build') { sh 'docker build -t harbor.local/dify/app:$GIT_COMMIT .' } stage('Push') { sh 'docker push harbor.local/dify/app:$GIT_COMMIT' } stage('Deploy') { sh 'kubectl set image deploy/dify app=harbor.local/dify/app:$GIT_COMMIT' }
两个加分细节:① 镜像 tag 绝不用 latest,要用 commit id(可追溯、可回滚)② 部署用滚动更新 + 保留 rollout 历史,出事 rollout undo 秒回滚。这是生产 CI/CD 的基本素养。
Q19
服务更新时怎么保证不中断?liveness 和 readiness 探针的区别?

靠滚动更新 + 探针配合实现不中断:

  • 滚动更新:Deployment 默认策略,逐个替换 Pod。配 maxSurge(最多多起几个)和 maxUnavailable(最多几个不可用),保证全程有可用副本。
  • readiness 探针(就绪):探针不过,Pod 不会被加进 Service endpoints,流量不会进来。新 Pod 必须 readiness 通过才接流量——这是不中断的关键。
  • liveness 探针(存活):探针不过,kubelet 直接重启容器。用来自愈卡死的服务。
一句话区分:readiness 决定"要不要给流量",liveness 决定"要不要重启"。vLLM 这种启动慢的服务(加载模型要几十秒),readiness 的 initialDelaySeconds 一定要设大,否则没启动完就被打流量,或被 liveness 误杀反复重启。这个细节面试官很爱问。
Q20
etcd 具体怎么备份?真出问题了怎么恢复?做过演练吗?

etcd 是 K8s 的大脑,存了所有集群状态,必须备份。

# 备份(用 crontab 每天定时跑) ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-$(date +%F).db \ --endpoints=https://127.0.0.1:2379 \ --cacert=/etc/kubernetes/pki/etcd/ca.crt \ --cert=/etc/kubernetes/pki/etcd/server.crt \ --key=/etc/kubernetes/pki/etcd/server.key # 校验备份 etcdctl snapshot status /backup/etcd-xxx.db # 恢复(先停 apiserver 和 etcd,再恢复到新数据目录) etcdctl snapshot restore /backup/etcd-xxx.db \ --data-dir=/var/lib/etcd-restore
答这题的杀手锏是提"演练过":很多人只会备份不会恢复。说"我定期做过恢复演练,备份文件还会 snapshot status 校验完整性",立刻和只背命令的人拉开差距。备份不验证 = 没备份。
Q21
为什么用容器跑这些服务而不是直接装在物理机上?容器和虚拟机的区别?
  • 本质区别:虚拟机虚拟化的是硬件,每个 VM 跑完整的操作系统内核,重;容器共享宿主机内核,只隔离进程和文件系统,秒级启动、资源开销小。
  • 用容器的理由:环境一致性(镜像打包好依赖,开发测试生产一个样,杜绝"我机器上能跑")、快速弹性扩缩容、K8s 统一编排调度、故障自愈。
  • GPU 容器化:靠 NVIDIA Container Toolkit 把 GPU 设备透传进容器,配合 GPU Operator 在 K8s 里像调度 CPU 一样调度 GPU。
底层原理别答错:容器隔离靠 Linux 三件套——namespace(隔离视图:进程/网络/挂载)、cgroup(限制资源:CPU/内存/GPU)、联合文件系统(镜像分层)。能说出 namespace + cgroup,面试官就知道你懂容器原理而不只是会 docker run。
Q22
某个节点负载很高、响应变慢,登上去你用哪些命令排查?

经典 Linux 性能排查,按 CPU → 内存 → 磁盘 → 网络 顺序定位:

top / htop # 总览:看 load、CPU、内存,哪个进程吃资源 uptime # load average 三个数(1/5/15分钟)超核数就是过载 vmstat 1 # r列(运行队列)高=CPU瓶颈,b列高=阻塞(等IO) free -h # 内存,重点看 available 不是 free iostat -x 1 # 磁盘IO,%util 接近100%=磁盘瓶颈 iotop # 哪个进程在疯狂读写磁盘 df -h / du -sh * # 磁盘满了?哪个目录占空间 sar -n DEV 1 # 网卡流量 ss -antp # 看连接状态,大量 TIME_WAIT? nvidia-smi # GPU场景:哪个进程占显存、GPU利用率
方法论比命令重要:先 top 看是 CPU/内存/IO 哪类瓶颈,再用专项工具深入。load average 看是否过载、iostat 的 %util 看磁盘、free 看 available——这套"先定位类型再深挖"的思路是运维基本功。
Q23
Docker 镜像怎么优化?为什么要做小?
  • 多阶段构建:build 阶段装编译工具、编译,最终镜像只 COPY 产物,把编译环境甩掉,体积能降一大半。
  • 选小基础镜像:能用 alpine / slim 就别用完整 ubuntu;Python 服务用 python:3.x-slim。
  • 合并 RUN 层 + 清缓存:多条命令用 && 合并成一层,结尾清 apt/pip 缓存,减少镜像层和体积。
  • .dockerignore:排除 .git、测试数据、文档,别打进镜像。
  • 层缓存顺序:不常变的(装依赖)放前面,常变的(拷代码)放后面,最大化利用构建缓存。
为什么要做小:① 拉取/分发快(节点扩容、滚动更新更迅速)② 占 Harbor 存储少 ③ 攻击面小更安全。多阶段构建是最有效的一招,必提。
Q24
Pod 的 resources requests 和 limits 有什么区别?设不好会怎样?
  • requests(请求):调度依据。K8s 按 requests 找有足够空闲资源的节点放 Pod,是"保底预留"。
  • limits(限制):运行上限。容器用超 CPU limit 会被限流(throttle),用超内存 limit 会被 OOMKilled 杀掉。

设不好的后果:

  • requests 设太低:节点超卖,实际跑起来资源不够,互相抢,服务卡顿。
  • limits 设太低:内存稍微一涨就被 OOMKilled 反复重启。
  • 不设 limits:单个 Pod 内存泄漏能拖垮整个节点上的其他服务。
GPU 特殊点:nvidia.com/gpu 这种扩展资源,requests 必须等于 limits(不能超卖一张卡),且只能是整数。这点和 CPU/内存不一样,面试容易被追问。
Q25
整个系统的备份容灾方案是什么?哪些数据必须备份?

按数据重要性和恢复成本分类备份:

  • etcd(最高优先级):集群状态,每天定时 snapshot,丢了整个集群配置就没了。
  • 原始文档(MinIO/对象存储):知识库的源文件,定期同步到另一台存储节点或离线介质。这是最该保的——向量库挂了能重新灌,原始文档丢了无法重建。
  • Milvus 向量数据:配 PVC 持久化 + 定期备份索引。但即使丢了,有原始文档就能重新向量化,所以优先级低于原始文档。
  • PostgreSQL(Dify 元数据):pg_dump 定期逻辑备份,存了知识库配置、用户数据。
  • K8s manifests / Helm values:全部进 Git 版本管理(GitOps 思路),集群重建能快速还原。
排优先级的逻辑很关键:能"重新生成"的数据(向量)优先级低,"无法重建"的源头数据(原始文档、etcd)优先级最高。这种分级思维比"全都备份"更显专业。
Q26
如果用户量翻倍,推理顶不住了,你怎么扩容?

先定位瓶颈在哪,再决定怎么扩:

  • ① 看监控判断瓶颈:vllm:num_requests_waiting 持续高 = 推理算力不够;GPU 利用率没满但延迟高 = 可能是 CPU/网络/向量检索拖累。先确认是 GPU 瓶颈再扩 GPU,别盲目加卡。
  • ② 横向扩推理副本:加 GPU 节点,多起几个 vLLM 副本,Nginx 层 least_conn 负载均衡分流。这是最直接的水平扩展。
  • ③ 提高单卡吞吐:调 vLLM 的 max-num-seqs(提高批处理并发)、gpu-memory-utilization(给 KV Cache 更多显存)。先榨干现有卡再加卡。
  • ④ 优化检索链路:Milvus 加索引/副本,Embedding 服务扩副本。
  • ⑤ 加缓存:高频重复问题用 Redis 缓存结果,直接命中不走推理,省算力。
回答框架:"先看监控定位瓶颈 → 先调优榨干现有资源 → 再水平扩容 → 加缓存兜底"。体现你不是无脑加机器,而是有成本意识、先优化后扩容。
Q★
你只有一台推理节点,它要是挂了整个问答不就瘫了?为什么不加一台备用?

这是个好问题,我的考量是高可用优先靠软件,而不是堆硬件冷备,原因有两点:

  • 成本:500–1000人内部知识库,并发不高,再买一台带双 A10 的推理服务器(四五万)平时基本闲置,对中小企业不划算。钱应该花在刀刃上。
  • 软件层已能覆盖大部分故障:真正高频的故障是进程崩溃、OOM、Pod 卡死,这些靠 K8s 就能自愈——liveness 探针自动重启、Pod 异常自动重新调度。硬件整机宕机是低频事件。

我实际的高可用设计:

  • 推理服务跑成 Deployment 多副本(节点显存够时单机多实例),配 readiness 探针,挂一个不影响整体接流量。
  • 滚动更新 + rollout 历史,更新或回滚全程不中断。
  • 监控告警盯着 Pod 重启和推理排队,异常第一时间介入。
  • 真要做整机冗余,也是等业务量上来、SLA 要求提高后再横向加节点——架构上预留了扩展能力(Nginx upstream 加 server 就行),但不在初期为小概率事件预付硬件成本。
这题答得好能直接体现运维成熟度:高可用不等于堆硬件,而是"软件自愈兜底高频故障 + 架构预留扩展能力 + 按 SLA 和成本权衡冗余"。说"我先用 K8s 把自愈做好,整机冗余按业务量演进",比"我加了一台备用"高级得多。
Q27
K8s 集群和这套系统,你做了哪些安全加固?
  • 网络隔离:用 NetworkPolicy 限制 Pod 间通信,比如只允许 Dify 访问 vLLM,数据库只接受应用层访问,最小权限。
  • RBAC:给不同角色配最小权限的 ServiceAccount,运维、开发权限分开,不给所有人 cluster-admin。
  • 镜像安全:全走私有 Harbor,开启镜像扫描(Trivy)查漏洞,不从公网拉镜像防投毒。
  • Secret 管理:密码、密钥用 K8s Secret 存(不硬编码进镜像或 yaml),有条件接 Vault。
  • 主机加固:关闭无用端口、SSH 禁 root 密码登录改密钥、定期打补丁、最小化安装。
  • 入口控制:Nginx IP 白名单 + 外网 VPN,数据全程内网不出。
安全题答题维度:网络(NetworkPolicy)、权限(RBAC)、镜像(扫描)、密钥(Secret)、主机(加固)、入口(白名单/VPN)。能分这几层说就很全面,体现纵深防御思维。
Q28
这个项目里你具体负责什么?产出和价值怎么量化?

我负责的是基础设施和运维保障这条线(诚实界定范围,别什么都往身上揽,容易穿帮):

  • 集群搭建:kubeadm 搭 7 节点高可用 K8s,GPU Operator 纳管 GPU 资源,Harbor 私有仓库。
  • 服务部署:容器化部署 vLLM、Milvus、Dify 等组件,配置调度、存储、网络。
  • 稳定性保障:搭建 Prometheus+Grafana 监控、EFK 日志、告警体系,处理 OOM、调度、网络等线上问题。
  • 持续运维:CI/CD 流程、备份容灾、扩容调优、安全加固。

量化价值(用相对值,别编绝对数字):

  • 系统可用性维持在 99% 以上,核心服务故障自愈。
  • 通过节点隔离 + 监控告警,把推理服务 OOM 故障从频发降到基本消除。
  • vLLM 调优后单卡并发吞吐相比初始配置提升明显(连续批处理 + KV Cache 优化)。
  • 重复性问题答疑由系统自动承接,释放了人工支持的工作量。
量化技巧:没有真实数据时,用"相对提升"(提升明显、从频发到消除)而非编造精确数字("提升73%")。面试官追问精确数字时编不出来反而翻车。诚实界定职责范围 + 相对量化,是最稳的。
企业级 RAG 智能知识库 · 项目规划与面试指南 · 云原生/K8s工程师专用