Stable Yogi Leather-Dress-Collection持续集成/部署:使用Docker与K8s管理模型服务
你是不是也遇到过这样的烦恼?好不容易在本地把那个能生成各种皮革连衣裙设计图的AI模型——Stable Yogi Leather-Dress-Collection——给调通了,效果也挺满意。但一到要把它放到服务器上,给团队或者用户用的时候,问题就来了:环境依赖怎么装?版本冲突怎么解决?服务挂了怎么自动重启?流量大了怎么扩容?
这些问题,单靠手动操作,不仅效率低,还容易出错。今天,我就来跟你聊聊,怎么用Docker和Kubernetes(简称K8s)这套组合拳,把我们的AI模型服务管得服服帖帖,实现从代码提交到服务上线的自动化流水线。这就像给你的模型服务请了个“全能管家”,部署、更新、扩容、监控,它全包了。
1. 为什么需要CI/CD和容器化?
在聊具体怎么做之前,咱们先得搞清楚,为啥要折腾这些。你想想看,传统的部署方式是不是这样:找台服务器,照着文档一步步装Python、装CUDA、装各种奇奇怪怪的库,版本还得对上。好不容易装好了,换台机器又得重来一遍。更头疼的是,如果模型更新了,你得手动去每台服务器上操作,万一漏了哪台,服务就可能不一致。
Docker的出现,就是为了解决“在我机器上能跑,到你那就跑不起来”这个经典难题。它把应用和它需要的所有环境,打包成一个叫“镜像”的盒子。这个盒子在任何支持Docker的机器上打开,里面的应用都能以一模一样的方式运行。对于我们的Stable Yoji模型来说,这意味着再也不用担心服务器环境差异了。
而Kubernetes,则是管理这些Docker盒子的“超级调度员”。当你有成百上千个服务盒子在运行时,K8s能帮你自动安排它们在哪台机器上运行(调度),某个盒子挂了能自动重启(自愈),流量大了能自动复制更多盒子出来(伸缩),还能在不中断服务的情况下更新盒子里的内容(滚动更新)。
把这两者结合起来,再配上持续集成/持续部署(CI/CD)的流程,就构成了一套完整的DevOps实践。简单说,就是开发者提交代码后,自动打包成Docker镜像,然后自动部署到K8s集群里。整个过程无需人工干预,又快又稳。
2. 第一步:将Stable Yogi服务Docker化
万事开头难,咱们先从把模型服务装进“盒子”开始。这里假设你已经有一个能本地运行的Stable Yogi模型Web服务,比如用FastAPI写的一个接口。
2.1 编写Dockerfile
Dockerfile就像是制作“盒子”的说明书。我们在项目根目录创建一个名为Dockerfile的文件(没有后缀名)。
# 使用一个包含CUDA和Python的官方基础镜像,确保能跑深度学习模型 FROM nvidia/cuda:12.1.1-runtime-ubuntu22.04 # 设置工作目录 WORKDIR /app # 安装系统依赖和Python RUN apt-get update && apt-get install -y \ python3-pip \ python3-dev \ && rm -rf /var/lib/apt/lists/* # 将本地的依赖文件复制到容器内 COPY requirements.txt . # 安装Python依赖,使用清华镜像加速 RUN pip3 install --no-cache-dir -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt # 将整个项目代码复制到容器内 COPY . . # 暴露服务运行的端口,假设你的FastAPI服务跑在7860端口 EXPOSE 7860 # 设置容器启动时执行的命令 CMD ["python3", "app/main.py"]这个Dockerfile做了几件事:
- 选了一个带CUDA的Ubuntu系统作为底板。
- 在“盒子”里安装了Python和pip。
- 根据
requirements.txt安装了所有Python库。 - 把我们的代码全部放进“盒子”。
- 告诉外界,服务在7860端口。
- 设定好“盒子”一启动,就运行我们的主程序。
注意:你的requirements.txt需要包含fastapi,uvicorn,torch以及Stable Yogi模型所需的所有库。
2.2 构建与测试Docker镜像
说明书写好了,现在来制作“盒子”,也就是镜像。
打开终端,进入项目目录,执行构建命令:
# -t 给镜像打个标签,名字叫stable-yogi,版本是v1.0 # . 表示Dockerfile在当前目录 docker build -t stable-yogi:v1.0 .这个过程可能会花点时间,因为它要下载基础镜像和安装所有依赖。构建成功后,你可以用下面的命令看看镜像是否在本地:
docker images | grep stable-yogi接下来,我们运行这个“盒子”,测试一下:
# -p 将容器的7860端口映射到主机的9000端口 # --gpus all 让容器能使用主机的GPU(确保主机有NVIDIA驱动和Docker GPU支持) docker run --gpus all -p 9000:7860 --name yogi-test stable-yogi:v1.0如果一切正常,你应该能在终端看到服务启动的日志。打开浏览器,访问http://你的服务器IP:9000/docs,就能看到FastAPI自动生成的API文档界面了。试着调用一下生成皮革连衣裙的接口,看看功能是否正常。
测试完毕后,可以停止并删除这个测试容器:
docker stop yogi-test docker rm yogi-test3. 第二步:使用Kubernetes编排与管理服务
现在我们的模型服务已经完美地打包进了Docker镜像。接下来,就要请出“超级调度员”K8s,来管理这个服务的生老病死了。你需要一个K8s集群,可以是云服务商提供的(如阿里云ACK、腾讯云TKE),也可以是自己用kubeadm搭建的。
3.1 创建核心配置文件:Deployment
在K8s里,Deployment是用来定义和管理一组完全相同Pod(可以理解为一个或多个容器)的主要对象。它保证了指定数量的Pod副本始终运行。
创建一个文件叫deployment.yaml:
apiVersion: apps/v1 kind: Deployment metadata: name: stable-yogi-deployment labels: app: stable-yogi spec: replicas: 2 # 我们希望始终有2个副本在运行 selector: matchLabels: app: stable-yogi template: # 这是Pod的模板 metadata: labels: app: stable-yogi spec: containers: - name: stable-yogi-container image: stable-yogi:v1.0 # 使用我们刚才构建的镜像 imagePullPolicy: IfNotPresent # 如果本地有镜像就不去远程拉取 ports: - containerPort: 7860 # 容器内部端口 resources: limits: nvidia.com/gpu: 1 # 申请1块GPU,需要集群有GPU设备插件 memory: "8Gi" cpu: "2" requests: memory: "4Gi" cpu: "1" livenessProbe: # 存活探针,检查容器是否活着 httpGet: path: /health # 假设你的服务有健康检查接口 port: 7860 initialDelaySeconds: 30 # 容器启动30秒后开始检查 periodSeconds: 10 # 每10秒检查一次 readinessProbe: # 就绪探针,检查容器是否准备好接收流量 httpGet: path: /ready port: 7860 initialDelaySeconds: 5 periodSeconds: 5这个配置文件定义了一个部署:
- 名字叫
stable-yogi-deployment。 - 始终维持2个副本(Pod)。
- 每个Pod里运行一个容器,使用我们本地的
stable-yogi:v1.0镜像。 - 为每个容器申请了1块GPU、2核CPU和8Gi内存的限制。
- 配置了健康检查,K8s会根据这个探针自动重启不健康的容器。
3.2 创建服务访问配置:Service
Pod的IP地址是不固定的,而且外部无法直接访问。我们需要一个Service来为这组Pod提供一个稳定的访问入口。
创建一个文件叫service.yaml:
apiVersion: v1 kind: Service metadata: name: stable-yogi-service spec: selector: app: stable-yogi # 选择所有标签为app: stable-yogi的Pod ports: - port: 80 # Service对外的端口 targetPort: 7860 # 转发到Pod的哪个端口 protocol: TCP type: LoadBalancer # 类型可以是ClusterIP(集群内访问)、NodePort(节点端口)、LoadBalancer(云负载均衡器)LoadBalancer类型通常用于云服务商,它会自动创建一个外部负载均衡器,并分配一个公网IP,这样你就能从互联网访问你的模型服务了。
3.3 部署到Kubernetes集群
假设你已经配置好kubectl命令行工具并连接到了你的K8s集群,现在可以部署了:
# 应用Deployment配置 kubectl apply -f deployment.yaml # 应用Service配置 kubectl apply -f service.yaml部署后,可以检查一下状态:
# 查看Deployment状态 kubectl get deployments # 查看Pod状态,应该能看到2个Running的Pod kubectl get pods # 查看Service状态,如果是LoadBalancer,EXTERNAL-IP列会显示公网IP(可能需要等待一会儿) kubectl get svc当Service获得外部IP后,你就可以通过http://<EXTERNAL-IP>/docs来访问你的模型服务了。
4. 第三步:实现自动化CI/CD流水线
手动构建镜像、更新配置还是太麻烦。我们的目标是:当我向代码仓库(比如GitLab或GitHub)提交新代码时,自动完成所有部署步骤。这里以GitHub Actions为例。
4.1 推送镜像到镜像仓库
首先,需要把Docker镜像推送到一个公共或私有的镜像仓库(如Docker Hub、阿里云容器镜像服务ACR)。我们修改一下构建和推送的步骤。
假设你使用Docker Hub,先登录:
docker login然后重新构建并打上带仓库地址的标签:
docker build -t yourdockerhub/stable-yogi:v1.0 . docker push yourdockerhub/stable-yogi:v1.0同时,需要修改deployment.yaml中的镜像地址:
image: yourdockerhub/stable-yogi:v1.04.2 配置GitHub Actions自动化流程
在项目根目录创建.github/workflows/cicd-pipeline.yaml文件:
name: CI/CD Pipeline for Stable Yogi on: push: branches: [ main ] # 当代码推送到main分支时触发 jobs: build-and-push: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 - name: Log in to Docker Hub uses: docker/login-action@v2 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Build and push Docker image uses: docker/build-push-action@v4 with: context: . push: true tags: | yourdockerhub/stable-yogi:latest yourdockerhub/stable-yogi:${{ github.sha }} deploy-to-k8s: needs: build-and-push # 等待构建任务完成 runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Set up Kubeconfig run: | echo "${{ secrets.KUBE_CONFIG }}" | base64 -d > kubeconfig.yaml export KUBECONFIG=kubeconfig.yaml - name: Deploy to Kubernetes run: | # 更新deployment.yaml中的镜像标签为本次提交的SHA sed -i 's|yourdockerhub/stable-yogi:.*|yourdockerhub/stable-yogi:${{ github.sha }}|' deployment.yaml kubectl apply -f deployment.yaml kubectl apply -f service.yaml # 执行滚动更新,K8s会逐步用新Pod替换旧Pod kubectl rollout status deployment/stable-yogi-deployment这个流水线做了两件事:
- 构建与推送:在代码推送后,自动构建Docker镜像,并推送到Docker Hub,同时打上
latest和本次提交ID两个标签。 - 部署到K8s:使用存储在GitHub Secrets中的K8s集群凭证(
KUBE_CONFIG),更新Deployment中的镜像版本,并触发K8s的滚动更新。
你需要在GitHub仓库的Settings -> Secrets中配置DOCKER_USERNAME,DOCKER_PASSWORD和KUBE_CONFIG(后者是你的kubeconfig文件内容经过base64编码后的字符串)。
从此以后,你只需要专注写代码,提交到main分支,剩下的构建、测试、部署全由这条流水线自动完成。
5. 进阶:弹性伸缩与监控
基础管线搭好了,我们再来看看如何让它更智能、更可靠。
5.1 配置HPA实现弹性伸缩
如果突然有很多用户来生成皮革连衣裙,2个Pod可能扛不住。我们可以配置Horizontal Pod Autoscaler(HPA),让K8s根据CPU或内存使用率自动增减Pod数量。
# 创建一个HPA,目标Deployment是stable-yogi-deployment,CPU利用率目标为50%,Pod数量在1到5之间自动调整 kubectl autoscale deployment stable-yogi-deployment --cpu-percent=50 --min=1 --max=5或者,使用YAML文件定义更复杂的规则(hpa.yaml):
apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: stable-yogi-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: stable-yogi-deployment minReplicas: 1 maxReplicas: 5 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 505.2 添加基础监控与日志
服务跑起来,我们还得知道它跑得怎么样。
查看日志:
# 查看某个Pod的日志 kubectl logs <pod-name> # 持续查看日志(类似tail -f) kubectl logs -f <pod-name> # 查看指定Deployment所有Pod的日志 kubectl logs -l app=stable-yogi --tail=50监控资源使用: K8s自带基础监控。你可以使用kubectl top命令查看资源使用情况:
kubectl top pods kubectl top nodes对于生产环境,建议集成更强大的监控系统,如Prometheus(收集指标) + Grafana(展示仪表盘),以及EFK/ELK栈(收集和分析日志)。这些工具的部署稍微复杂一些,但能让你对服务的健康状况了如指掌。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。