当前位置: 首页 > news >正文

【AI图像生成网站Golang】部署图像生成服务(阿里云ACK+GPU实例)

文章目录

    • 一、模型上传
    • 二、容器构建与上传
      • 相关代码
        • 服务端:
        • 后端
        • Dockerfile:
    • 三、集群搭建
      • 1. ACK创建集群
    • 四、运行容器
      • 整体步骤
      • 具体步骤
      • 部署服务pod
    • 五、测试

一、模型上传

        项目使用的模型文件有30多个G,直接创建容器会在创建过程中占用内存过大,以至于磁盘崩溃,实时下载需要额外给集群中的服务配置连接外网的通道,所以选择将容器挂载到集群中,然后映射到容器中调用。

        官方提供的上传方式有四种——ossutil、OSS SDK、OSS API 以及直接拖拽上传。我选择将文件夹直接在网页上上传,然后使用ossutil上传超过5GB的文件。
在这里插入图片描述        上传文件的命令行如下:

ossutil cp D:/localpath/example.iso[本地文件] oss://examplebucket/desfolder/[目标文件夹]

        Bucket里可以不创建文件所在的文件夹目录,上传时平台会自动创建相关目录存放文件。

二、容器构建与上传

        服务使用grpc与后端通信,监听端口为50051。
目录结构如下:
在这里插入图片描述

        由于后端代码是用go写的,所以通过ai.proto文件生成了ai.pb.go 与 ai_grpc.pb.go用来与后端通信。

相关代码

服务端:
# server.py
import grpc
from concurrent import futures
import ai_pb2, ai_pb2_grpcimport requests, base64, torch, asyncio
from diffusers import StableDiffusionInstructPix2PixPipeline, EulerAncestralDiscreteScheduler
from PIL import Image, ImageOps
from io import BytesIOimport os
os.environ["HF_HUB_OFFLINE"] = "1"
os.environ["TRANSFORMERS_OFFLINE"] = "1"# --- model init (same as before) ---
model_id = "./instruct-pix2pix"
# model_id = "timbrooks/instruct-pix2pix"
pipe = StableDiffusionInstructPix2PixPipeline.from_pretrained(model_id, torch_dtype=torch.float16, safety_checker=None,local_files_only=True,      # ← 强制本地加载
)
pipe.to("cuda")
pipe.scheduler = EulerAncestralDiscreteScheduler.from_config(pipe.scheduler.config)
num_inference_steps = 5
def download_and_prep(url: str) -> Image.Image:resp = requests.get(url, timeout=10)resp.raise_for_status()img = Image.open(BytesIO(resp.content))img = ImageOps.exif_transpose(img).convert("RGB")return img.resize((512,512), Image.Resampling.LANCZOS)def progress_callback(step: int, timestep: int, latents):# step 是当前步数(0 ~ num_inference_steps-1)print(f"[Inference] Step {step+1}/{num_inference_steps} (timestep={timestep})")
class AiService(ai_pb2_grpc.AiServiceServicer):def Generate(self, request, context):print(f"[Generate] 收到请求 prompt={request.prompt!r}, url={request.url}")try:# synchronous single-image inferenceimg = download_and_prep(request.url)print("[Generate] 下载并预处理完毕,开始推理")out = pipe(prompt=request.prompt,image=[img],num_inference_steps=num_inference_steps,image_guidance_scale=1,callback=progress_callback,callback_steps=1,)print("[Generate] 推理完成,准备返回")buf = BytesIO()out.images[0].save(buf, format="PNG")return ai_pb2.GenerateReply(processed_image=buf.getvalue(),error="")except Exception as e:print(f"[Generate] 捕获到异常: {e}")return ai_pb2.GenerateReply(processed_image=b"",error=str(e))def serve():server = grpc.server(futures.ThreadPoolExecutor(max_workers=4))ai_pb2_grpc.add_AiServiceServicer_to_server(AiService(), server)server.add_insecure_port('[::]:50051')print("Starting gRPC AI server on port 50051 …")server.start()server.wait_for_termination()if __name__ == "__main__":serve()
后端
package apiimport ("backend/ai_service""context""encoding/base64""fmt""google.golang.org/grpc""google.golang.org/grpc/credentials/insecure""time"
)// InstructPix2PixGRPC 通过 gRPC 调用后端生成图像
func InstructPix2PixGRPC(ctx context.Context, prompt, url string) (string, error) {// 1. 建立 gRPC 连接conn, err := grpc.DialContext(ctx, "localhost:50051",grpc.WithTransportCredentials(insecure.NewCredentials()), // 不用 TLSgrpc.WithBlock(), // 等待连接成功)if err != nil {return "", fmt.Errorf("连接 gRPC 服务失败: %w", err)} else {fmt.Println("连接 gRPC 服务成功")}defer conn.Close()// 2. 创建客户端client := ai_service.NewAiServiceClient(conn)// 3. 设置超时时间ctx, cancel := context.WithTimeout(ctx, 1000*time.Second)defer cancel()// 4. 发起请求req := &ai_service.GenerateRequest{Url:    url,Prompt: prompt,}resp, err := client.Generate(ctx, req)if err != nil {return "", fmt.Errorf("gRPC 调用失败: %w", err)}if resp.Error != "" {return "", fmt.Errorf("服务端返回错误: %s", resp.Error)}fmt.Printf("服务端返回: %s", resp)// 5. 将二进制图像数据 base64 编码encoded := base64.StdEncoding.EncodeToString(resp.ProcessedImage)fmt.Printf("编码: %s", encoded)return encoded, nil
}
Dockerfile:
# syntax=docker/dockerfile:1FROM docker.io/python:3.9-slim# 1. 系统依赖(如果需要编译 Pillow 等)
RUN apt-get update && apt-get install -y --no-install-recommends build-essential libjpeg-dev && rm -rf /var/lib/apt/lists/*# 2. 创建工作目录
WORKDIR /app# 3. 复制 Python 依赖列表并安装
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt# 4. 安装 GPU 版 PyTorch (cu121)
RUN pip install --no-cache-dir torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121# 5. 复制服务代码
COPY api_offline.py ai_pb2.py ai_pb2_grpc.py ./# 6. 环境变量:关闭联网拉取
ENV HF_HUB_OFFLINE=1 TRANSFORMERS_OFFLINE=1 HF_HUB_DISABLE_TELEMETRY=1
# 如果你指定过 revision,还可以把它写到环境里# 7. 暴露 gRPC 端口
EXPOSE 50051# 8. 默认启动命令
CMD ["python", "api_offline.py"]

使用命令docker build -t my-instruct-pix2pix-offline .在本地创建镜像后,用以下命令在本地测试运行容器:

docker run --gpus all -it -d --name ai-offline -v F:/ai_service/instruct-pix2pix:/app/instruct-pix2pix:ro -p 50051:50051 docker-name

参数说明:

  • --gpus all:模将宿主机所有 GPU 分配给容器,用于加速深度学习推理。
  • -it:连接标准输入和伪终端,支持交互式操作
  • -d:以后台模式(守护进程)运行容器
  • -v F:/ai_service/instruct-pix2pix:/app/instruct-pix2pix:ro
    • 将本地目录 F:\ai_service\instruct-pix2pix 挂载到容器 /app/instruct-pix2pix
    • :ro 表示只读,防止容器修改宿主机文件
  • -p 50051:50051:映射容器的 50051 端口到宿主机同端口,外部可通过 localhost:50051 访问

本地部署运行测试后,推送到云端

# 先打tag
docker tag docker-name:latest crpi-xxxxxxx.cn-xxxxx.personal.cr.aliyuncs.com/ai-web-rpc/docker-name:latest
# 推送
docker push crpi-xxxxxxx.cn-xxxxx.personal.cr.aliyuncs.com/ai-web-rpc/docker-name:latest

三、集群搭建

接下来使用ACK服务搭建k8s集群。

1. ACK创建集群

在这里插入图片描述

在这里插入图片描述

网络插件选Terway,Flannel容易有版本不适配的问题。

在这里插入图片描述

点下一步,开始创建节点池。
在这里插入图片描述

GPU实例选择: i型适用于模型推理,v型适用于模型训练,ENI 数量与可创建 pod 数挂钩,这里ENI数量为4时,可创建pod数为33

在这里插入图片描述

其他选项默认,推理模型节点设置为1即可

在这里插入图片描述

剩下的默认就行,自己测试的话这里可以选基础版

在这里插入图片描述

检测全部通过就可以创建集群了,注意余额要大于100,不然会报错,学生每年会有300块的优惠券,记得领

在这里插入图片描述

创建成功
在这里插入图片描述
等待节点池和节点就绪之后检查节点中pod运行情况会发现

在这里插入图片描述

解决方法在【k8s】阿里云ACK服务中GPU实例部署问题,暂时没发现别的解决方法,有小伙伴有更好的办法的话可以在评论区分享。

四、运行容器

参考了阿里云的文档:使用阿里云容器ACK通过云存储网关(CSG)挂载OSS

整体步骤

$env:KUBECONFIG = "ack-kubeconfig.yaml"
kubectl apply -f namespace.yaml
kubectl apply -f secrets.yaml
kubectl create -f oss-pv.yaml
kubectl get pv
kubectl create -f oss-pvc.yaml
kubectl get pvc -n ai-service

具体步骤

  1. 若要使用本地命令行控制云端,需要配置KUBECONFIG环境变量
$env:KUBECONFIG = "ack-kubeconfig.yaml"

在这里插入图片描述

在这里插入图片描述
创建命名空间

kubectl apply -f namespace.yaml
# namespace.yaml
apiVersion: v1
kind: Namespace
metadata:name: ai-service

创建并部署ACR镜像拉取密码

创建密码

kubectl -n ai-service create secret docker-registry regcred --<你的网址> --docker-username=<你的账号> --docker-password=<你的密码> --dry-run=client -o yaml > secrets.yaml

可在以下页面设置密码
在这里插入图片描述

# secrets.yaml
apiVersion: v1
data:.dockerconfigjson: *******
kind: Secret
metadata:creationTimestamp: nullname: regcrednamespace: ai-service
type: kubernetes.io/dockerconfigjson

部署密码

kubectl apply -f secrets.yaml

创建oss-pv

# oss-pv.yaml
apiVersion: v1
kind: Secret
metadata:name: oss-secretnamespace: ai-service
stringData:akId: "Id"akSecret: "Secret"
---
apiVersion: v1
kind: PersistentVolume
metadata:name: oss-pvlabels:alicloud-pvname: oss-pv
spec:storageClassName: oss-scncapacity:storage: 40GiaccessModes:- ReadWriteManypersistentVolumeReclaimPolicy: Retaincsi:driver: ossplugin.csi.alibabacloud.comvolumeHandle: oss-pvnodePublishSecretRef:name: oss-secretnamespace: ai-servicevolumeAttributes:bucket: "Bucket name"url: "OSS endpoint"path: "子目录"otherOpts: "-o max_stat_cache_size=0 -o allow_other"
kubectl create -f oss-pv.yaml
kubectl get pv

查看状态

NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE        
oss-pv   40Gi       RWX            Retain           Bound    ai-service/oss-pvc   oss-scn        <unset>                          2m49s 

在这里插入图片描述

在这里插入图片描述
部署oss-pvc

apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: oss-pvcnamespace: ai-service
spec:storageClassName: oss-scnaccessModes:- ReadWriteManyresources:requests:storage: 40Giselector:matchLabels:alicloud-pvname: oss-pv
kubectl create -f oss-pvc.yaml
kubectl get pvc -n ai-service

查看状态

NAME      STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
oss-pvc   Bound    oss-pv   40Gi       RWX            oss-scn        <unset>                 1s 

部署服务pod

在这里插入图片描述

将pod对应的yaml文件复制到模板,可以选择保存模板,这样再次创建的时候可以直接使用。
在这里插入图片描述

点击下方的链接,会自动跳转到容器组子页面。

在这里插入图片描述
在这里插入图片描述

成功运行
在这里插入图片描述
成功运行后,在本地运行下面命令行可以将容器地址映射到本地调用。

kubectl port-forward -n ai-service pod/ai-service 50051:50051

五、测试

成功调用。
在这里插入图片描述

相关文章:

  • python打卡day53
  • ​​信息系统项目管理师-信息系统工程 知识点总结与例题分析​​
  • MultiTalk 是一种音频驱动的多人对话视频生成模型
  • 设计模式(二)
  • 上传IPA到App Store的步骤
  • Java线程异常处理与多线程编程实践
  • 当Python遇上多线程:ThreadPoolExecutor的实用指南
  • stl学习
  • 迁移学习基础
  • unity学习摘要
  • 利用pycharm搭建模型步骤
  • DIPLOMAT开源程序是基于深度学习的身份保留标记对象多动物跟踪(测试版)
  • 机器学习 vs 深度学习:区别与应用场景全解析
  • python有一个列表如何颠倒里面的顺序
  • 基于Python的二手房源信息爬取与分析的设计和实现,7000字论文编写
  • Java 锁升级机制详解
  • Linux操作系统——批量装机
  • 好用的批量处理软件,免费使用!
  • electron在单例中实现双击打开文件,并重复打开其他文件
  • windows录频软件
  • 家政保洁服务网站模板/广州网站营销seo
  • 工信部网站信息查询/市场营销方案范文5篇
  • 乌鲁木齐新市区建设局网站/视频号直播推广二维码
  • 网站推广国外/百度关键词模拟点击软件
  • 南京做网站的公司/北京seo包年
  • 可以做兼职翻译的网站/网站排名优化培训电话