基于K8s的高性能Web服务器搭建实践
在短视频内容创作需求爆发式增长的今天,如何快速构建一个低成本、高响应、可扩展的AI视频生成后端系统,已成为许多初创团队和开发者面临的核心挑战。传统的部署方式往往难以兼顾性能与迭代效率——要么依赖重型框架资源浪费严重,要么手动运维不堪重负。本文将带你从零开始,基于 Kubernetes 构建一套面向实时文本到视频(T2V)生成的轻量级 Web 服务系统。
这套平台以Wan2.2-T2V-5B模型为核心,结合 NFS 存储共享、Harbor 镜像管理、Jenkins CI/CD 流水线以及 Prometheus + Grafana 监控体系,在单 master 双 worker 的 K8s 集群上实现了秒级视频生成能力。整个架构专为社交媒体模板生成、创意原型验证等低延迟场景设计,既保证了推理速度,又具备良好的可维护性与横向扩展潜力。
集群初始化:打造稳定可靠的运行底座
任何高可用系统的起点都是一个稳定的 Kubernetes 集群。我们采用经典的三节点结构:1个 Master 控制平面,2个 Worker 节点分别承担 CPU 和 GPU 计算任务。所有主机均运行 CentOS 7.9 系统,Docker 版本为 24.0.2,Kubernetes 使用 v1.28+,确保对容器运行时和设备插件的良好支持。
首先统一规划 IP 与主机名:
| 角色 | 主机名 | IP 地址 |
|---|---|---|
| K8s Master | master | 192.168.0.20 |
| K8s Worker (CPU) | worker1 | 192.168.0.21 |
| K8s Worker (GPU) | worker2 | 192.168.0.22 |
| Ansible 控制节点 | ansible | 192.168.0.30 |
| Monitor | monitor | 192.168.0.33 |
| Harbor | harbor | 192.168.0.34 |
| Jenkins | jenkins | 192.168.0.35 |
| NFS Server | nfs-server | 192.168.0.36 |
每台机器都需要关闭 SELinux 和防火墙,避免网络策略干扰 Pod 通信:
systemctl stop firewalld && systemctl disable firewalld setenforce 0 sed -i 's/^SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config接着启用桥接流量支持,这是 CNI 插件正常工作的前提:
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf br_netfilter EOF cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 net.ipv4.ip_forward = 1 EOF sysctl --system安装 Docker 和 containerd 后,启动并设为开机自启:
yum install -y yum-utils yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo yum install -y docker-ce docker-ce-cli containerd.io systemctl enable docker && systemctl start dockerMaster 节点执行集群初始化命令:
kubeadm init --apiserver-advertise-address=192.168.0.20 --pod-network-cidr=10.244.0.0/16 mkdir -p $HOME/.kube cp /etc/kubernetes/admin.conf $HOME/.kube/config chown $(id -u):$(id -g) $HOME/.kube/config随后部署 Calico 作为 CNI 网络插件:
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/calico.yaml待网络就绪后,在 worker1 和 worker2 上执行kubeadm join加入集群。此时可通过kubectl get nodes查看节点状态。
为了方便可视化管理,我们还部署了 Kubernetes Dashboard:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml对于 GPU 节点 worker2,需额外安装 NVIDIA 显卡驱动、CUDA Toolkit 及 nvidia-container-toolkit:
# 安装基础依赖 dnf install kernel-devel kernel-headers gcc make dkms acpid libglvnd-glx libglvnd-opengl libglvnd-devel pkgconfig # 运行官方驱动安装包 bash NVIDIA-Linux-x86_64-xxx.run # 添加 nvidia-docker 仓库并安装工具包 distribution=$(. /etc/os-release;echo $ID$VERSION_ID) curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.repo | sudo tee /etc/yum.repos.d/nvidia-docker.repo yum install -y nvidia-container-toolkit systemctl restart docker验证 GPU 是否被正确识别:
kubectl describe node worker2 | grep -A 10 "nvidia.com/gpu"若输出中显示nvidia.com/gpu: 1,说明 GPU 资源已可供调度。
自动化运维:Ansible 统一配置管理
面对多台服务器的手动操作容易出错且难以复现。为此我们在独立的 ansible 节点上部署 Ansible 实现批量管控。
先生成 SSH 密钥并分发至各目标主机:
ssh-keygen -t rsa -b 2048 ssh-copy-id master ssh-copy-id worker1 # ... 其他节点同理配置/etc/hosts实现主机名解析:
cat >> /etc/hosts <<EOF 192.168.0.20 master 192.168.0.21 worker1 ... EOF安装 Ansible 并定义 inventory 文件:
[masters] master [workers] worker1 worker2 [nfs] nfs-server [harbor] harbor [jenkins] jenkins [monitor] monitor测试连通性:
ansible all -m ping一旦通过,即可编写 playbook 实现一键配置同步,比如批量关闭防火墙、安装常用工具、挂载 NFS 卷等,大幅提升后期维护效率。
数据持久化:NFS 实现跨副本视频共享
由于视频文件体积较大且需要被多个服务访问(如下载、转码、预览),我们选择 NFS 作为共享存储方案。
在 nfs-server 上安装服务并创建共享目录:
yum install nfs-utils -y systemctl enable rpcbind nfs-server && systemctl start rpcbind nfs-server mkdir -p /data/videos chmod -R 777 /data/videos chown -r nfsnobody:nfsnobody /data/videos配置/etc/exports允许内网访问:
/data/videos 192.168.0.0/24(rw,sync,no_root_squash,no_all_squash) exportfs -avr在所有 K8s 节点测试挂载:
mkdir -p /mnt/nfs-videos mount -t nfs nfs-server:/data/videos /mnt/nfs-videos df -Th | grep nfs接下来在 Kubernetes 中定义 PV 和 PVC,使容器能够使用该存储:
# pv-video.yaml apiVersion: v1 kind: PersistentVolume metadata: name: pv-video-storage spec: capacity: storage: 50Gi accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Retain storageClassName: nfs nfs: path: /data/videos server: 192.168.0.36 --- # pvc-video.yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pvc-video-output spec: accessModes: - ReadWriteMany resources: requests: storage: 20Gi storageClassName: nfs应用后检查状态:
kubectl apply -f pv-video.yaml kubectl apply -f pvc-video.yaml kubectl get pv,pvc当 PVC 处于 Bound 状态时,即可在 Deployment 中引用。
模型服务化:封装 Wan2.2-T2V-5B 为 REST API
为了让模型能被外部调用,我们将Wan2.2-T2V-5B封装成 Flask 微服务。其核心逻辑是接收 JSON 请求中的文本 prompt,调用本地脚本生成 MP4 视频,并返回 URL。
主程序如下:
from flask import Flask, request, jsonify import os import uuid import subprocess import time app = Flask(__name__) OUTPUT_DIR = "/videos" @app.route("/generate", methods=["POST"]) def generate_video(): data = request.json prompt = data.get("prompt", "a cat running") video_id = str(uuid.uuid4())[:8] output_path = f"{OUTPUT_DIR}/{video_id}.mp4" cmd = [ "python", "run_t2v.py", "--prompt", prompt, "--output", output_path, "--size", "480p" ] try: start = time.time() result = subprocess.run(cmd, capture_output=True, text=True, timeout=30) duration = time.time() - start if result.returncode == 0: return jsonify({ "status": "success", "video_url": f"http://192.168.0.20:30080/videos/{video_id}.mp4", "video_id": video_id, "generation_time": round(duration, 2), "model": "Wan2.2-T2V-5B" }), 200 else: return jsonify({ "status": "error", "message": result.stderr }), 500 except Exception as e: return jsonify({"status": "error", "message": str(e)}), 500 if __name__ == "__main__": app.run(host="0.0.0.0", port=5000)配套的requirements.txt包含必要的依赖:
flask==2.3.3 gunicorn==21.2.0 torch==2.0.0 transformers==4.30.0 opencv-python-headless==4.8.0.74 numpy==1.24.3使用以下 Dockerfile 构建镜像:
FROM pytorch/pytorch:2.0-cuda11.7-runtime WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . VOLUME ["/videos"] EXPOSE 5000 CMD ["gunicorn", "-b", "0.0.0.0:5000", "app:app"]构建完成后推送至私有 Harbor 仓库:
docker login 192.168.0.34:5001 -u admin -p <your-password> docker build -t wan-t2v:latest . docker tag wan-t2v:latest 192.168.0.34:5001/ai-models/wan-t2v:2.2-5b docker push 192.168.0.34:5001/ai-models/wan-t2v:2.2-5b这样就完成了模型的镜像化打包与版本管理。
服务编排:K8s 部署与 GPU 调度
现在进入核心环节——将服务部署进 Kubernetes,并实现 GPU 资源精准调度。
Deployment 配置如下:
apiVersion: apps/v1 kind: Deployment metadata: name: wan-t2v-deployment labels: app: wan-t2v spec: replicas: 1 selector: matchLabels: app: wan-t2v template: metadata: labels: app: wan-t2v spec: nodeSelector: kubernetes.io/hostname: worker2 # 强制调度至 GPU 节点 containers: - name: wan-t2v image: 192.168.0.34:5001/ai-models/wan-t2v:2.2-5b ports: - containerPort: 5000 resources: limits: nvidia.com/gpu: 1 memory: "8Gi" cpu: "4" requests: nvidia.com/gpu: 1 memory: "4Gi" cpu: "2" volumeMounts: - name: video-storage mountPath: /videos volumes: - name: video-storage persistentVolumeClaim: claimName: pvc-video-outputService 提供 NodePort 访问:
apiVersion: v1 kind: Service metadata: name: wan-t2v-service spec: selector: app: wan-t2v type: NodePort ports: - protocol: TCP port: 5000 targetPort: 5000 nodePort: 30080部署并验证:
kubectl apply -f deployment-wan-t2v.yaml kubectl apply -f service-wan-t2v.yaml kubectl get pods -o wide测试接口:
curl -X POST http://192.168.0.20:30080/generate \ -H "Content-Type: application/json" \ -d '{"prompt":"a red balloon floating in the sky"}'预期返回包含视频 URL 的 JSON 结果。
持续交付:Jenkins 实现自动化发布
为了提升迭代效率,我们引入 Jenkins 实现 CI/CD 流水线。每次代码提交后自动完成构建、推送、部署全过程。
流水线脚本示例:
pipeline { agent any stages { stage('Build') { steps { sh 'docker build -t 192.168.0.34:5001/ai-models/wan-t2v:${BUILD_ID} .' } } stage('Push') { steps { sh 'docker push 192.168.0.34:5001/ai-models/wan-t2v:${BUILD_ID}' } } stage('Deploy') { steps { sh 'kubectl set image deployment/wan-t2v-deployment wan-t2v=192.168.0.34:5001/ai-models/wan-t2v:${BUILD_ID}' } } } }该流程显著降低了人为失误风险,同时加快了新功能上线节奏。
全栈监控:Prometheus + Grafana 实时洞察
没有监控的系统如同盲人骑马。我们部署 Prometheus 抓取关键指标,包括节点资源、Pod 状态及服务健康度。
node-exporter 安装于所有物理节点,暴露硬件层面数据。Prometheus 配置抓取目标:
- job_name: 'kubernetes-nodes' static_configs: - targets: ['192.168.0.20:9090', '192.168.0.21:9090', '192.168.0.22:9090'] - job_name: 'wan-t2v-service' static_configs: - targets: ['192.168.0.22:5000']Grafana 导入标准仪表盘(如 ID 1860 和 11074),并自定义面板展示 T2V 请求延迟、成功率、GPU 利用率等核心指标,帮助及时发现性能瓶颈。
外部访问:Ingress 统一路由入口
为避免暴露过多端口,我们使用 Ingress-Nginx 实现基于域名的反向代理。
创建 Ingress 规则:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: t2v-ingress annotations: nginx.ingress.kubernetes.io/rewrite-target: / spec: ingressClassName: nginx rules: - host: t2v.sanchuang.ai http: paths: - path: / pathType: Prefix backend: service: name: wan-t2v-service port: number: 5000配合本地 hosts 解析:
192.168.0.20 t2v.sanchuang.ai即可通过http://t2v.sanchuang.ai访问服务,实现优雅的对外暴露。
可靠性增强:健康探针保障服务稳定性
为了让 K8s 更智能地管理 Pod 生命周期,我们在 Deployment 中添加三种探针:
livenessProbe: httpGet: path: /healthz port: 5000 initialDelaySeconds: 30 periodSeconds: 10 readinessProbe: httpGet: path: /ready port: 5000 initialDelaySeconds: 20 periodSeconds: 5 startupProbe: httpGet: path: /init port: 5000 failureThreshold: 30 periodSeconds: 10Flask 应用中增加对应路由返回 200 OK,使得容器在启动、运行、异常等阶段都能被准确感知,避免流量打到未就绪实例。
性能评估:ab 工具压测验证系统承载力
最后进行压力测试,验证系统在并发场景下的表现。
安装 ab 工具并发起请求:
yum install httpd-tools -y ab -n 100 -c 10 -T "application/json" -p payload.json http://192.168.0.20:30080/generate其中payload.json内容为:
{"prompt":"a dog chasing a ball"}观察各项指标:
- Prometheus 展示 CPU、内存、GPU 利用率变化趋势;
- Grafana 分析请求延迟分布;
-kubectl top pod查看实时资源消耗;
- 日志统计平均生成时间约为 3~8 秒,满足“秒级响应”设计目标。
整套系统成功实现了轻量化 AI 视频生成服务的工业化部署。Wan2.2-T2V-5B凭借其仅 50 亿参数的精简体量,在消费级 GPU 上达到了令人满意的推理速度,非常适合对成本敏感但追求快速反馈的内容创作场景。未来可进一步集成 HPA 实现自动扩缩容,或引入 KServe 构建更专业的模型服务网格,让平台更具弹性与智能化。这种高度集成的设计思路,正引领着 AI 应用后端向更高效、更可靠的方向演进。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考