使用微服务和异步消息传递来部署图片处理功能

Last reviewed 2023-07-17 UTC

本文档介绍如何实现将微服务与 Pub/Sub 和 GKE 集成中所述的参考架构。此架构旨在使用容器和异步消息传递功能来处理长时间运行的进程。

本文档使用一个示例照片分享应用来生成照片缩略图。您可以使用 Google Kubernetes Engine (GKE) 来部署应用,并使用 Pub/Sub 来异步调用长时间运行的进程。您还可以使用适用于 Cloud Storage 的 Pub/Sub 通知功能来添加一些辅助作业,而无需修改应用的代码。

应用由 Cloud Build 容器化并存储在 Artifact Registry 中。它使用 Cloud Vision 来检测不当图片。

架构

下图展示了实现参考架构的示例相册应用的设计。

相册应用的架构。

图 1. 基于使用容器和异步消息传递的图片处理架构。

上图展示了如何生成缩略图:

  1. 客户端将图片上传到应用。
  2. 应用将图片存储在 Cloud Storage 中。
  3. 系统为缩略图生成请求。
  4. 缩略图生成器生成缩略图。
  5. 成功响应被发送到相册应用。
  6. 成功的响应被发送给客户端,您可以在 Cloud Storage 中找到该缩略图。

下图展示了应用如何以异步方式将缩略图生成功能作为一项单独的服务来实现。

缩略图提取进程的架构。

图 2. 缩略图提取进程的架构。

您可以使用 Pub/Sub 向缩略图生成服务发送服务请求。这一新架构以异步方式调用服务,使应用将响应发送回客户端后才在后台创建缩略图。该设计还让您可以对缩略图生成服务进行扩缩,以便多个作业能够并行运行。

目标

  • 在 GKE 上部署示例相册应用。
  • 从应用发出异步服务调用。
  • 在将新文件上传到 Cloud Storage 存储桶时,使用 Cloud Storage 的 Pub/Sub 通知触发应用。
  • 使用 Pub/Sub 执行更多任务,而无需修改应用。

费用

在本文档中,您将使用 Google Cloud 的以下收费组件:

您可使用价格计算器根据您的预计使用情况来估算费用。 Google Cloud 新用户可能有资格申请免费试用

完成示例应用的构建后,您可以删除所创建的资源以避免继续计费。如需了解详情,请参阅清理

须知事项

  1. 登录您的 Google Cloud 账号。如果您是 Google Cloud 新手,请创建一个账号来评估我们的产品在实际场景中的表现。新客户还可获享 $300 赠金,用于运行、测试和部署工作负载。
  2. 在 Google Cloud Console 中的项目选择器页面上,选择或创建一个 Google Cloud 项目

    转到“项目选择器”

  3. 确保您的 Google Cloud 项目已启用结算功能

  4. 启用 GKE, Cloud SQL, Cloud Build, Artifact Registry, and Cloud Vision API。

    启用 API

  5. 在 Google Cloud Console 中的项目选择器页面上,选择或创建一个 Google Cloud 项目

    转到“项目选择器”

  6. 确保您的 Google Cloud 项目已启用结算功能

  7. 启用 GKE, Cloud SQL, Cloud Build, Artifact Registry, and Cloud Vision API。

    启用 API

  8. 在 Google Cloud 控制台中,激活 Cloud Shell。

    激活 Cloud Shell

    Cloud Shell 会话随即会在 Google Cloud 控制台的底部启动,并显示命令行提示符。Cloud Shell 是一个已安装 Google Cloud CLI 且已为当前项目设置值的 Shell 环境。该会话可能需要几秒钟时间来完成初始化。

设置环境

在本部分中,您将为整个文档中使用的值分配默认设置。如果您关闭 Cloud Shell 会话,则会丢失这些环境设置。

  1. 在 Cloud Shell 中,设置默认 Google Cloud 项目:

    gcloud config set project PROJECT_ID
    

    PROJECT_ID 替换为您的 Google Cloud 项目 ID。

  2. 设置默认的 Compute Engine 区域:

    gcloud config set compute/region REGION
    export REGION=REGION
    

    REGION 替换为您附近的区域。如需了解详情,请参阅区域和地区

  3. 设置默认的 Compute Engine 可用区:

    gcloud config set compute/zone ZONE
    export ZONE=ZONE
    

    ZONE 替换为您附近的可用区。

  4. 下载示例应用文件并设置当前目录:

    git clone https://github.com/GoogleCloudPlatform/gke-photoalbum-example
    cd gke-photoalbum-example
    

创建 Cloud Storage 存储桶并上传默认缩略图

  1. 在 Cloud Shell 中,创建 Cloud Storage 存储分区以存储原始图片和缩略图:

    export PROJECT_ID=$(gcloud config get-value project)
    gsutil mb -c regional -l ${REGION} gs://${PROJECT_ID}-photostore
    
  2. 上传默认缩略图文件:

    gsutil cp ./application/photoalbum/images/default.png \
        gs://${PROJECT_ID}-photostore/thumbnails/default.png
    
    • 按以下格式存储上传的图片:gs://PROJECT_ID-photostore/FILENAME,其中 FILENAME 表示上传的图片文件的名称。
    • 按以下格式存储生成的缩略图:gs://PROJECT_ID-photostore/thumbnails/FILENAME
    • 原始图片和相应的缩略图具有相同的 FILENAME 值,但缩略图存储在 thumbnails 存储桶中。
    • 创建缩略图时,相册应用中会显示以下 default.png 占位符缩略图。

      默认占位符缩略图。

  3. 将缩略图文件设为公开:

    gsutil acl ch -u AllUsers:R \
        gs://${PROJECT_ID}-photostore/thumbnails/default.png
    

创建 Cloud SQL 实例和 MySQL 数据库

  1. 在 Cloud Shell 中,创建 Cloud SQL 实例:

    gcloud sql instances create photoalbum-db --region=${REGION} \
        --database-version=MYSQL_8_0
    
  2. 检索连接名称:

    gcloud sql instances describe photoalbum-db \
        --format="value(connectionName)"
    

    记下该名称,后面您将用到该名称。

  3. root@% MySQL 用户设置密码:

    gcloud sql users set-password root --host=% --instance=photoalbum-db \
        --password=PASSWORD
    

    PASSWORD 替换为 root@% 用户的安全密码。

  4. 连接到 Cloud SQL 实例:

    gcloud sql connect photoalbum-db --user=root --quiet
    

    出现提示时,输入您在上一步中设置的密码。

  5. 创建一个名为 photo_db 的数据库,其中用户为 appuser,密码为 pas4appuser

    create database photo_db;
    create user 'appuser'@'%' identified by 'pas4appuser';
    grant all on photo_db.* to 'appuser'@'%' with grant option;
    flush privileges;
    
  6. 确认结果并从 MySQL 退出:

    show databases;
    select user from mysql.user;
    exit
    

    在输出中,确认已创建 photo_db 数据库和 appuser 用户:

    mysql> show databases;
    +--------------------+
    | Database           |
    +--------------------+
    | information_schema |
    | mysql              |
    | performance_schema |
    | photo_db           |
    | sys                |
    +--------------------+
    5 rows in set (0.16 sec)
    
    mysql> \t
    Outfile disabled.
    mysql> select user from mysql.user;
    +-------------------+
    | user              |
    +-------------------+
    | appuser           |
    | cloudsqlreplica   |
    | cloudsqlsuperuser |
    | root              |
    | cloudsqlexport    |
    | cloudsqlimport    |
    | cloudsqloneshot   |
    | root              |
    | cloudsqlexport    |
    | cloudsqlimport    |
    | cloudsqloneshot   |
    | root              |
    | cloudsqlapplier   |
    | cloudsqlimport    |
    | mysql.infoschema  |
    | mysql.session     |
    | mysql.sys         |
    | root              |
    +-------------------+
    18 rows in set (0.16 sec)
    
    mysql> exit
    Bye
    

创建 Pub/Sub 主题和订阅

  1. 在 Cloud Shell 中,创建名为 thumbnail-service 的 Pub/Sub 主题:

    gcloud pubsub topics create thumbnail-service
    

    相册应用通过在 thumbnail-service 主题上发布消息,向缩略图生成服务发送请求。

  2. 创建名为 thumbnail-workers 的 Pub/Sub 订阅:

    gcloud pubsub subscriptions create --topic thumbnail-service thumbnail-workers
    

    缩略图生成服务会收到来自 thumbnail-workers 订阅的请求。

创建 GKE 集群

  1. 在 Cloud Shell 中,创建一个有权调用 API 的 GKE 集群:

    gcloud container clusters create "photoalbum-cluster" \
        --scopes "https://www.googleapis.com/auth/cloud-platform" \
        --num-nodes "5"
    
  2. 配置访问凭据,以便在后续步骤中使用 kubectl 命令管理集群:

    gcloud container clusters get-credentials photoalbum-cluster
    
  3. 显示节点列表:

    kubectl get nodes
    

    在输出中,确认有 5 个节点的 STATUS 值为 Ready

    NAME                                                STATUS   ROLES    AGE     VERSION
    gke-photoalbum-cluster-default-pool-d637570a-2pfh   Ready    <none>   2m55s   v1.24.10-gke.2300
    gke-photoalbum-cluster-default-pool-d637570a-3rm4   Ready    <none>   2m55s   v1.24.10-gke.2300
    gke-photoalbum-cluster-default-pool-d637570a-f7l4   Ready    <none>   2m55s   v1.24.10-gke.2300
    gke-photoalbum-cluster-default-pool-d637570a-qb2z   Ready    <none>   2m53s   v1.24.10-gke.2300
    gke-photoalbum-cluster-default-pool-d637570a-rvnp   Ready    <none>   2m54s   v1.24.10-gke.2300
    

创建 Artifact Registry 代码库

  • 在 Cloud Shell 中,创建一个代码库来存储容器映像:

    gcloud artifacts repositories create photoalbum-repo \
        --repository-format=docker \
        --location=us-central1 \
        --description="Docker repository"
    

为应用构建映像

  1. 在文本编辑器中,打开 application/photoalbum/src/auth_decorator.py 文件并更新用户名和密码:

    USERNAME = 'username'
    PASSWORD = 'passw0rd'
    
  2. 在 Cloud Shell 中,使用 Cloud Build 服务为相册应用构建映像:

    gcloud builds submit ./application/photoalbum -t \
        us-central1-docker.pkg.dev/${PROJECT_ID}/photoalbum-repo/photoalbum-app
    
  3. 使用 Cloud Build 服务为 thumbnail-worker 缩略图生成服务构建映像:

    gcloud builds submit ./application/thumbnail -t \
        us-central1-docker.pkg.dev/${PROJECT_ID}/photoalbum-repo/thumbnail-worker
    

部署相册应用

  1. 在 Cloud Shell 中,使用您环境中的值更新相册和缩略图生成器的 Kubernetes Deployment 清单:

    connection_name=$(gcloud sql instances describe photoalbum-db \
        --format "value(connectionName)")
    
    digest_photoalbum=$(gcloud container images describe \
        us-central1-docker.pkg.dev/${PROJECT_ID}/photoalbum-repo/photoalbum-app:latest --format \
        "value(image_summary.digest)")
    
    sed -i.bak -e "s/\[PROJECT_ID\]/${PROJECT_ID}/" \
        -e "s/\[CONNECTION_NAME\]/${connection_name}/" \
        -e "s/\[DIGEST\]/${digest_photoalbum}/" \
        config/photoalbum-deployment.yaml
    
    digest_thumbnail=$(gcloud container images describe \
        us-central1-docker.pkg.dev/${PROJECT_ID}/photoalbum-repo/thumbnail-worker:latest --format \
        "value(image_summary.digest)")
    
    sed -i.bak -e "s/\[PROJECT_ID\]/${PROJECT_ID}/" \
        -e "s/\[CONNECTION_NAME\]/${connection_name}/" \
        -e "s/\[DIGEST\]/${digest_thumbnail}/" \
            config/thumbnail-deployment.yaml
    
  2. 创建部署资源以启动相册应用和缩略图生成服务:

    kubectl create -f config/photoalbum-deployment.yaml
    kubectl create -f config/thumbnail-deployment.yaml
    
  3. 创建服务资源,为应用分配外部 IP 地址:

    kubectl create -f config/photoalbum-service.yaml
    
  4. 查看 Pod 的结果:

    kubectl get pods
    

    在输出中,确认每个 photoalbum-appthumbail-worker Pod 有 3 个 Pod 且其 STATUS 值为 Running

    NAME                                READY     STATUS    RESTARTS   AGE
    photoalbum-app-555f7cbdb7-cp8nw     2/2       Running   0          2m
    photoalbum-app-555f7cbdb7-ftlc6     2/2       Running   0          2m
    photoalbum-app-555f7cbdb7-xsr4b     2/2       Running   0          2m
    thumbnail-worker-86bd95cd68-728k5   2/2       Running   0          2m
    thumbnail-worker-86bd95cd68-hqxqr   2/2       Running   0          2m
    thumbnail-worker-86bd95cd68-xnxhc   2/2       Running   0          2m
    

    thumbnail-worker Pod 会通过 thumbnail-workers 订阅来订阅缩略图生成请求。如需了解详情,请参阅如何在源代码中使用 callback 函数。

  5. 查看服务的结果:

    kubectl get services
    

    在输出中,确认 photoalbum-service 服务的 EXTERNAL-IP 列中有一个外部 IP 地址。服务可能需要几分钟时间才能全部运行。

    NAME                 TYPE           CLUSTER-IP      EXTERNAL-IP       PORT(S)        AGE
    kubernetes           ClusterIP      10.23.240.1     <none>            443/TCP        20m
    photoalbum-service   LoadBalancer   10.23.253.241   146.148.111.115   80:32657/TCP   2m
    

    记下该外部 IP 地址,后面您将用到该 IP 地址。在此示例中,该 IP 地址为 146.148.111.115

测试相册应用

  1. 如需在网络浏览器中访问已部署的应用,请转到以下网址,并输入您之前设置的用户名和密码:

    http://EXTERNAL_IP
    

    EXTERNAL_IP 替换为您在上一步中复制的 IP 地址。

  2. 如需上传图片文件,请点击上传

    在您等待服务生成唯一缩略图时显示的占位符缩略图。

    此时,屏幕上将显示缩略图占位符。

    在后台,缩略图生成服务会创建已上传图片的缩略图。如需查看生成的缩略图,请点击刷新。Cloud Vision API 会添加它检测到的图片标签。

    包含相关图片标签的缩略图。

    要查看原始图片,请点击缩略图。

添加不当图片检测功能

下图演示了如何使用 Cloud Storage 的 Pub/Sub 通知来触发用于检测不当内容的服务。当 Cloud Storage 存储分区中存储了包含不当内容的新文件时,此功能会对图片进行模糊处理。

不当内容功能的架构。

在上图中,该服务使用 Vision API 的安全搜索检测功能检测图片中的不当内容。

由于照片应用会异步触发缩略图生成器和图片检查工具;因此,无法保证它们按特定顺序执行。如果缩略图生成发生在图片模糊处理之前,那么您可能会在短时间内看到不当缩略图。但是,图片检查工具最终会对不当图片和不当缩略图进行模糊处理。

创建 Pub/Sub 主题、订阅和通知

  1. 在 Cloud Shell 中,创建名为 safeimage-service 的 Pub/Sub 主题:

    gcloud pubsub topics create safeimage-service
    
  2. 创建名为 safeimage-workers 的 Pub/Sub 订阅:

    gcloud pubsub subscriptions create --topic safeimage-service \
        safeimage-workers
    
  3. 配置 Pub/Sub 通知,以便在新文件上传到 Cloud Storage 存储分区时向 safeimage-service 主题发送消息:

    gsutil notification create -t safeimage-service -f json \
        gs://${PROJECT_ID}-photostore
    

构建和部署工作器映像

  1. 在 Cloud Shell 中,使用 Cloud Build 为 safeimage-workers 订阅构建容器映像:

    gcloud builds submit ./application/safeimage \
        -t us-central1-docker.pkg.dev/${PROJECT_ID}/photoalbum-repo/safeimage-worker
    
  2. 使用 Google Cloud 项目 ID、Cloud SQL 连接名称和容器映像摘要更新安全映像服务的 Kubernetes Deployment 清单:

    digest_safeimage=$(gcloud container images describe \
        us-central1-docker.pkg.dev/${PROJECT_ID}/photoalbum-repo/safeimage-worker:latest --format \
        "value(image_summary.digest)")
    sed -i.bak -e "s/\[PROJECT_ID\]/${PROJECT_ID}/" \
        -e "s/\[CONNECTION_NAME\]/${connection_name}/" \
        -e "s/\[DIGEST\]/${digest_safeimage}/" \
        config/safeimage-deployment.yaml
    

创建部署资源

  1. 创建名为 safeimage-deployment 的部署资源以部署 safeimage-service 主题:

    kubectl create -f config/safeimage-deployment.yaml
    
  2. 检查结果:

    kubectl get pods
    

    在输出中,确认有 3 个 safeimage-worker Pod 的 STATUS 值为 Running

    NAME                                READY     STATUS    RESTARTS   AGE
    photoalbum-app-555f7cbdb7-cp8nw     2/2       Running   0          30m
    photoalbum-app-555f7cbdb7-ftlc6     2/2       Running   0          30m
    photoalbum-app-555f7cbdb7-xsr4b     2/2       Running   8          30m
    safeimage-worker-7dc8c84f54-6sqzs   1/1       Running   0          2m
    safeimage-worker-7dc8c84f54-9bskw   1/1       Running   0          2m
    safeimage-worker-7dc8c84f54-b7gtp   1/1       Running   0          2m
    thumbnail-worker-86bd95cd68-9wrpv   2/2       Running   0          30m
    thumbnail-worker-86bd95cd68-kbhsn   2/2       Running   2          30m
    thumbnail-worker-86bd95cd68-n4rj7   2/2       Running   0          30m
    

    safeimage-worker Pod 会通过 safeimage-workers 订阅来订阅不当图片检测请求。如需了解详情,请参阅如何在源代码中使用 callback 函数。

测试不当图片检测功能

在此部分中,您需要上传一张测试图片,以验证安全搜索检测功能是否对不当图片进行了模糊处理。测试图片是一张装扮成僵尸的女孩的照片(经 Pixaby CC0 许可授权使用)。

  1. 下载测试图片
  2. 如需上传图片,请转到 http://EXTERNAL_IP,然后点击上传
  3. 点击刷新。此时,该应用会显示经过模糊处理的缩略图。

    经过模糊处理的缩略图。

    要查看上传的图片是否也经过了模糊处理,请点击缩略图。

清理

如果您不想保留为示例应用创建的 Google Cloud 资源,则可以移除这些资源,以免日后继续为这些资源付费。您可以彻底删除项目,也可以删除集群资源,然后删除集群。

删除项目

  1. 在 Google Cloud 控制台中,进入管理资源页面。

    转到“管理资源”

  2. 在项目列表中,选择要删除的项目,然后点击删除
  3. 在对话框中输入项目 ID,然后点击关闭以删除项目。

逐个删除资源

除了删除项目之外,您也可以逐个删除自己创建的资源。

  1. 删除 GKE 中的资源:

    kubectl delete -f config/safeimage-deployment.yaml
    kubectl delete -f config/photoalbum-service.yaml
    kubectl delete -f config/thumbnail-deployment.yaml
    kubectl delete -f config/photoalbum-deployment.yaml
    
  2. 删除 GKE 中的集群:

    gcloud container clusters delete photoalbum-cluster --quiet
    
  3. 从 Artifact Registry 中删除代码库:

    gcloud artifacts repositories delete photoalbum-repo --location us-central1 --quiet
    
  4. 删除 Pub/Sub 中的订阅和主题:

    gcloud pubsub subscriptions delete safeimage-workers
    gcloud pubsub topics delete safeimage-service
    gcloud pubsub subscriptions delete thumbnail-workers
    gcloud pubsub topics delete thumbnail-service
    
  5. 删除 Cloud SQL 实例:

    gcloud sql instances delete photoalbum-db --quiet
    
  6. 删除 Cloud Storage 存储分区:

    gsutil rm -r gs://${PROJECT_ID}-photostore
    gsutil rm -r gs://${PROJECT_ID}_cloudbuild
    
  7. 删除文件:

    cd ..
    rm -rf gke-photoalbum-example
    

后续步骤

  • 了解 DevOps,并详细了解与此参考架构相关的架构功能。
  • 进行 DevOps 快速检查,了解您与业界其他公司相比所处的位置。
  • 如需查看更多参考架构、图表和最佳实践,请浏览云架构中心