K8S
基础
示例
推理
运行 stable-diffusion-webui 文生图推理服务

运行 Stable Diffusion webui 文生图推理服务

本示例演示如何在 Kubernetes 上部署 Stable Diffusion webui 提供一个完备推理服务。

前提

存储 PVC

利用持久卷可确保文件持久存在,即使当前运行 Pod 的节点失败。在此示例中,分配了持久卷以保留模型和前端用户数据。

通过 Kubernetes PersistentVolumeClaim 进行持久卷存储的分配,通常称为 PVC,它请求存储大小和要使用的后端存储类型(例如: shared-nvme)。在此示例中,PVC 在 pvc.yaml 文件中定义。

pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: models
spec:
  storageClassName: shared-nvme
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 30Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: extensions
spec:
  storageClassName: shared-nvme
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 30Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: outputs
spec:
  storageClassName: shared-nvme
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 30Gi

部署 Deployment

在这个例子中,使用一个 Kubernetes manifests 来部署一个包含 Stable Diffusion webui 前端和后端推理服务。

  • metadata.labels 用于为 Pod 设置上标签,selector.matchLabels 用于为 Deployment 选中标签为 name: sd 的 Pod 进行控制
  • spec.containers 描述 Container
    • 一个名字为 sdw 的 Container 用于提供推理 API + WebUI 服务
      • 把 models pvc 挂在 Container 内的 /app/stable-diffusion-webui/models 目录下存放模型文件
      • 把 extensions pvc 挂在 Container 内的 /app/stable-diffusion-webui/extensions 目录下存放扩展组件
      • 把 outputs pvc 挂在 Container 内的 /app/stable-diffusion-webui/outputs 目录下存放输出数据
      • 配置 HF_ENDPOINT 代理,用于连接 huggingface 下载模型数据
      • 申请并限制 8 vCPU, 24Gi 内存和 1 个 GPU
  • spec.volumes 描述使用上面创建 pvc 持久卷
  • spec.tolerations 描述容忍 nvidia.com/gpu 污点存在,即可以使用 GPU 节点。通常在 K8S 使用污点以确保 Pod (例如纯 CPU 负载) 不会被调度到不适当节点上。
  • spec.affinity 描述节点亲和性,用于控制偏好或者必须使用那些类型的节点,例如示例必须使用 RTX 4090 节点
deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sd-webui
  namespace: sd
spec:
  selector:
    matchLabels:
      name: sd
  template:
    metadata:
      labels:
        name: sd
    spec:
      containers:
        - name: sd
          image: siutin/stable-diffusion-webui-docker:cuda-v1.9.4-2024-06-12
          command: ["bash", "webui.sh", "--share", "--listen", "--log-startup", "--gradio-debug", "--loglevel=DEBUG"]
          env:
          - name: HF_ENDPOINT
            value: https://hf-mirror.com
          imagePullPolicy: IfNotPresent
          resources:
            limits:
              nvidia.com/gpu: 1
          ports:
            - name: sd-webui
              containerPort: 7860
              protocol: TCP
          volumeMounts:
          - name: models
            subPath: models 
            mountPath: /app/stable-diffusion-webui/models
          - name: extensions
            subPath: extensions
            mountPath: /app/stable-diffusion-webui/extensions
          - name: outputs
            subPath: outputs
            mountPath: /app/stable-diffusion-webui/outputs
      volumes:
        - name: models
          persistentVolumeClaim:
            claimName: models            
        - name: extensions
          persistentVolumeClaim:
            claimName: extensions            
        - name: outputs
          persistentVolumeClaim:
            claimName: outputs    
      securityContext:
        fsGroup: 10000
      tolerations:
        - key: nvidia.com/gpu
          operator: Exists        

服务 Service

提供一个集群内的负载均衡器到 Stable Diffusion webui 容器实例。

下面示例是:

  1. 使用 selector 选中标签为 name: sd 的 Pod
  2. Pod 端口名字为 targetPort: sd-webui (对应 Deployment 中的定义)
  3. 并以 port: 7860 及名字 name: http 提供集群内 type: ClusterIP 的负载均衡服务
service.yaml
apiVersion: v1
kind: Service
metadata:
  name: sd-webui
spec:
  type: ClusterIP
  selector:
    name: sd
  ports:
    - port: 7860
      name: http
      targetPort: sd-webui
      protocol: TCP

入口 Ingress

Ingress 用于暴露应用程序到互联网,从而通过 https 协议访问应用程序。

下面示例是:

  1. rules.host: sd.wh-389a8e0c7dfc.ing.zw1.paratera.com
  2. 路由 path: /
  3. 到 Service name: sd-webuiport: 7860
  4. 同时开启 spec.tls 并设置自动申请 cert-manager.io/cluster-issuer: zerossl-prod 证书
ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: sd-ingress
  annotations:
    cert-manager.io/cluster-issuer: zerossl-prod  
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - sd.wh-389a8e0c7dfc.ing.zw1.paratera.com
    secretName: sd-tls
  rules:
  - host: sd.wh-389a8e0c7dfc.ing.zw1.paratera.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: sd-webui
            port:
              number: 7860

运行示例

  1. 部署

    kubectl apply -f pvc.yaml 
    kubectl apply -f deployment.yaml
    kubectl apply -f service.yaml
    kubectl apply -f ingress.yaml
  2. 查看已创建 Pod

    kubectl get pods

    等待 Pod 进入 Running 状态.

    如果 Pod 一直不能进入 Running,可以通过下面的命令查看 Pod 的详细信息

    kubectl describe pod [pod_id]
  3. 查看 Ingress

    kubectl get ing

    如果 Ingress 准备好,一般在输出 ADDRESS 字段会分配一个 IP 地址

  4. 访问服务

    使用从 Ingress 获取 Hosts 地址,然后在浏览器中访问。

    🎉 恭喜!您已在 Kubernetes 上部署一个带 UI 的 Stable Diffusion 推理服务了!