1. 简介
上次更新日期:2024 年 11 月 1 日
如何将旧版 PHP 应用迁移到 Google Cloud?
通常,本地运行的旧版应用需要进行现代化改造。这意味着要让它们可扩缩、安全且可部署在不同环境中。
在本研讨会中,您将:
- 将 PHP 应用容器化。
- 改用托管式数据库服务 ( Cloud SQL)。
- 部署到 Cloud Run(这是 GKE/Kubernetes 的零运维替代方案)。
- 使用 Identity and Access Management (IAM) 和 Secret Manager 保护应用。
- 通过 Cloud Build 定义 CI/CD 流水线。Cloud Build 可以与托管在热门 Git 提供商(例如 GitHub 或 GitLab)上的 Git 代码库相关联,并且可以在任何推送到主分支时触发。
- 在 Cloud Storage 上托管应用图片。这是通过装载实现的,无需任何代码即可更改应用。
- 通过 Gemini 引入 Gen AI 功能,通过 Cloud Functions(无服务器)进行编排。
- 熟悉 SLO 并了解如何运营新版应用。
按照这些步骤操作,您可以逐步实现 PHP 应用的现代化改造,从而提高其可伸缩性、安全性和部署灵活性。此外,迁移到 Google Cloud 后,您可以利用其强大的基础设施和服务来确保应用在云原生环境中顺畅运行。
我们相信,您通过以下简单步骤学到的知识可以应用于您自己的应用和组织,即使它们使用不同的语言/堆栈,具有不同的使用情形。
应用简介
您将 fork 的应用(代码,采用 MIT 许可)是一个基本的 PHP 5.7 应用,具有 MySQL 身份验证功能。该应用的主要理念是提供一个平台,供用户上传照片,并让管理员能够标记不当图片。该应用包含两个表格:
- 用户。已预编译并附带管理员。新用户可以注册。
- 图片。附带一些示例图片。已登录的用户可以上传新图片。我们将在本部分中添加一些神奇之处。
您的目标
我们希望对旧应用进行现代化改造,以便将其迁移到 Google Cloud。我们将利用其工具和服务来提高可伸缩性、增强安全性、自动执行基础设施管理任务,并使用 Cloud SQL、Cloud Run、Cloud Build、Secret Manager 等服务集成图像处理、监控和数据存储等高级功能。

更重要的是,我们希望逐步完成这些任务,以便您了解每个步骤背后的思路,并且通常每个步骤都会为后续步骤带来新的可能性(例如:模块 2 -> 3 和 6 -> 7)。
还不确定?请观看这段 7 分钟的 YouTube 视频。
所需条件
- 装有浏览器的联网计算机。
- 部分 GCP 赠金。请参阅后续步骤。
- 您将使用 Cloud Shell。它预安装了您需要的所有命令,并提供 IDE。
- GitHub 账号。您需要使用此功能,才能通过自己的 Git 代码库对原始代码 🧑🏻💻 gdgpescara/app-mod-workshop 进行分支。这是拥有自己的 CI/CD 流水线(自动提交 -> 构建 -> 部署)所必需的
如需查看示例解决方案,请点击此处:
- 作者代码库:https://github.com/Friends-of-Ricc/app-mod-workshop
.solutions/文件夹下的原始研讨会代码库(按章节划分)。
本研讨会旨在通过 Cloud Shell(在浏览器中)完成。
不过,您也可以尝试从本地计算机进行恢复。
2. 信用设置和 Fork

兑换 GCP 赠金并设置 GCP 环境 [可选]
如需参加此研讨会,您需要拥有一个有一定信用额度的结算账号。如果您已有自己的结算方式,则可以跳过此步骤。
创建一个全新的 Google Gmail 账号 (*),以便与您的 GCP 抵扣金额相关联。向您的教师索取兑换 GCP 抵用金的链接,或点击此处兑换抵用金:bit.ly/PHP-Amarcord-credits。
使用新创建的账号登录,然后按照说明操作。

(
) 为什么我需要一个全新的 Gmail 账号?*
我们发现,有些用户无法完成此 Codelab,是因为其账号(尤其是工作或学生电子邮件地址)之前曾使用过 GCP,并且组织政策 限制了他们完成此 Codelab 的能力。我们建议您创建一个新的 Gmail 账号,或使用之前未接触过 GCP 的现有 Gmail 账号 (gmail.com)。
点击相应按钮即可兑换抵用金。

在以下表单中填写您的姓名和姓氏,并同意条款及条件。
您可能需要等待几秒钟,结算账号才会显示在此处:https://console.cloud.google.com/billing
完成后,打开 Google Cloud 控制台,然后点击左上角下拉菜单中的项目选择器(显示“无组织”的位置),创建新项目。如下所示

如果您没有项目,请创建一个新项目,如下面的屏幕截图所示。右上角有一个“新建项目”选项。

请务必按如下方式将新项目与 GCP 试用结算账号相关联。

您已准备就绪,可以使用 Google Cloud Platform 了。如果您是初学者,或者只是想在云环境中完成所有操作,可以通过左上角的以下按钮访问 Cloud Shell 及其编辑器。

确保您已在左上角选择了新项目:
未选择(错误):

已选择(良好):

从 GitHub 复刻应用
- 前往演示版应用:https://github.com/gdgpescara/app-mod-workshop
- 点击 🍴 分叉。
- 如果您没有 GitHub 账号,则需要创建一个新账号。
- 根据需要修改内容。

- 使用以下命令克隆应用代码
git clonehttps://github.com/YOUR-GITHUB-USER/YOUR-REPO-NAME
- 使用您喜欢的编辑器打开克隆的项目文件夹。如果您选择 Cloud Shell,可以点击“打开编辑器”(如下所示)来完成此操作。

如图所示,您可以使用 Google Cloud Shell 编辑器完成所有操作

您可以通过点击“打开文件夹”并选择相应文件夹(可能位于主文件夹中的 app-mod-workshop 中)来直观地实现此目的。
3. 模块 1:创建 SQL 实例
创建 Google Cloud SQL 实例
我们的 PHP 应用将连接到 MySQL 数据库,因此我们需要将其复制到 Google Cloud,以便顺利完成迁移。Cloud SQL 非常适合,因为它允许您在云端运行全托管式 MySQL 数据库。以下是具体步骤:
- 前往 Cloud SQL 页面:https://console.cloud.google.com/sql/instances
- 点击“创建实例”
- 启用 API(如果需要)。此过程可能需要几秒钟的时间。
- 选择 MySQL。
- (我们会尽力为您提供最便宜的版本,以便您使用更长时间):
- 版本:企业版
- 预设:开发(我们试过沙盒,但对我们来说没什么效果)
- MySQL 版本:5.7(哇,这可是老版本了!)
- 实例 ID:选择
appmod-phpapp(如果您更改此值,请务必相应地更改未来的脚本和解决方案)。 - 密码:任意密码,但请记下该密码,并将其命名为 CLOUDSQL_INSTANCE_PASSWORD
- 地区:与您为应用的其余部分选择的地区保持一致(例如,米兰 =
europe-west8) - 可用区级可用性:单可用区(为了演示,我们节省了费用)
点击“创建实例”按钮以部署 Cloud SQL 数据库;⌛ 完成此操作大约需要 10 分钟⌛。在此期间,请继续阅读文档;您也可以开始解决下一个模块(“将 PHP 应用容器化”),因为该模块在第一部分(直到您修复数据库连接)中不依赖于此模块。
注意:此实例的费用约为每天 7 美元。请务必在研讨会结束后进行分拆。
在 Cloud SQL 中创建 image_catalog 数据库和用户
应用项目随附一个 db/ 文件夹,其中包含两个 SQL 文件:
- 01_schema.sql:包含用于创建两个表格的 SQL 代码,这两个表格包含用户和图片数据。
- 02_seed.sql:包含用于将数据植入之前创建的表中的 SQL 代码。
这些文件将在创建 image_catalog 数据库后使用。为此,您可以按以下步骤操作:
- 打开您的实例,然后点击“数据库”标签页:
- 点击“创建数据库”
- 将其称为
image_catalog(与 PHP 应用配置中一样)。

然后,我们创建数据库用户。这样,我们就可以对 image_catalog 数据库进行身份验证。
- 现在,点击用户标签页
- 点击“添加用户账号”。
- 用户:我们来创建一个:
- 用户名:
appmod-phpapp-user - 密码:选择一个您能记住的密码,或点击“生成”
- 保留“允许任何主机 (%)”。
- 点击“添加”。
打开数据库以获取已知 IP。
请注意,Cloud SQL 中的所有数据库都是“隔离”创建的。您需要明确设置可访问的网络。
- 点击您的实例
- 打开“连接”菜单
- 点击“网络”标签页。
- 点击“已获授权的网络”下方的链接。现在,添加一个网络(即子网)。
- 目前,我们先选择一个快速但不安全的设置,以便让应用正常运行 - 您可能需要在稍后将其限制为可信的 IP:
- 名称:“Everyone in the world - INSECURE”。
- 网络:“
0.0.0.0/0"”(注意:这是不安全的部分!) - 点击“完成”
- 点击“保存”。
您应该会看到与以下类似的内容:

注意:此解决方案可很好地兼顾在 O(小时) 内完成研讨会。不过,请查看安全性文档,以帮助您保护生产环境中的解决方案!
现在来测试数据库连接!
我们来看看之前创建的 image_catalog 用户是否有效。
访问实例中的“Cloud SQL Studio”,然后输入要进行身份验证的数据库、用户和密码,如下所示:

现在,您已登录,可以打开 SQL 编辑器并继续学习下一部分。
从代码库导入数据库
使用 SQL 编辑器导入 image_catalog 表及其数据。复制代码库中文件 ( 01_schema.sql 和 02_seed.sql) 中的 SQL 代码,然后按顺序依次执行这些代码。
之后,您应该会在 image_catalog 中获得两个表,即 users 和 images,如下所示:

您可以在编辑器中运行以下代码来测试该功能:select * from images;
另请务必记下 Cloud SQL 实例的公共 IP 地址,您稍后会用到它。如需获取 IP,请前往 概览页面下的 Cloud SQL 实例主页面。(概览 > 连接到此实例 > 公共 IP 地址)。
4. 模块 2:将 PHP 应用容器化

我们希望为云端构建此应用。
这意味着将代码打包到某种 ZIP 文件中,其中包含在云端高效运转所需的所有信息。
您可以通过以下几种方式打包应用:
- Docker。 非常受欢迎,但正确设置起来相当复杂。
- Buildpack。不太受欢迎,但往往会“自动猜测”要构建和运行的内容。通常情况下,只需执行此操作即可!
在此研讨会中,我们将假设您使用 Docker。
如果您选择使用 Cloud Shell,现在可以重新打开它(点击 Cloud 控制台右上角)。

这应该会在页面底部打开一个便捷的 shell,您应该已在设置步骤中派生了代码。

Docker
如果您想掌控一切,那么此解决方案非常适合您。如果您需要配置特定库并注入某些不明显的行为(例如上传中的 chmod、应用中的非标准可执行文件等),那么这样做是有意义的。
由于我们最终希望将容器化应用部署到 Cloud Run,因此请参阅以下文档。如何从 PHP 8 向后移植到 PHP 5.7?或许你可以使用 Gemini 来完成这项任务。或者,您也可以使用此预构建版本:
# Use the official PHP image: https://hub.docker.com/_/php
FROM php:5.6-apache
# Configure PHP for Cloud Run.
# Precompile PHP code with opcache.
# Install PHP's extension for MySQL
RUN docker-php-ext-install -j "$(nproc)" opcache mysqli pdo pdo_mysql && docker-php-ext-enable pdo_mysql
RUN set -ex; \
{ \
echo "; Cloud Run enforces memory & timeouts"; \
echo "memory_limit = -1"; \
echo "max_execution_time = 0"; \
echo "; File upload at Cloud Run network limit"; \
echo "upload_max_filesize = 32M"; \
echo "post_max_size = 32M"; \
echo "; Configure Opcache for Containers"; \
echo "opcache.enable = On"; \
echo "opcache.validate_timestamps = Off"; \
echo "; Configure Opcache Memory (Application-specific)"; \
echo "opcache.memory_consumption = 32"; \
} > "$PHP_INI_DIR/conf.d/cloud-run.ini"
# Copy in custom code from the host machine.
WORKDIR /var/www/html
COPY . .
# Setup the PORT environment variable in Apache configuration files: https://cloud.google.com/run/docs/reference/container-contract#port
ENV PORT=8080
# Tell Apache to use 8080 instead of 80.
RUN sed -i 's/80/${PORT}/g' /etc/apache2/sites-available/000-default.conf /etc/apache2/ports.conf
# Note: This is quite insecure and opens security breaches. See last chapter for hardening ideas.
# Uncomment at your own risk:
#RUN chmod 777 /var/www/html/uploads/
# Configure PHP for development.
# Switch to the production php.ini for production operations.
# RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
# https://github.com/docker-library/docs/blob/master/php/README.md#configuration
RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"
# Expose the port
EXPOSE 8080
点击此处可查看最新的 Dockerfile 版本。
为了在本地测试我们的应用,我们需要更改 config.php 文件,以便我们的 PHP 应用能够连接到 Google CloudSQL 上可用的 MySQL 数据库。根据您之前的设置,填写以下空白:
<?php
// Database configuration
$db_host = '____________';
$db_name = '____________';
$db_user = '____________';
$db_pass = '____________';
try {
$pdo = new PDO("mysql:host=$db_host;dbname=$db_name", $db_user, $db_pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("Errore di connessione: " . $e->getMessage());
}
session_start();
?>
DB_HOST是 Cloud SQL 公共 IP 地址,您可以在 SQL 控制台中找到它:

DB_NAME应该保持不变:image_catalogDB_USER应为appmod-phpapp-userDB_PASS是您选择的内容。用英文单引号将其括起来,并根据需要进行转义。
此外,欢迎借助 Gemini 将这几篇 🇮🇹 意大利语文章翻译成英语!
好的,现在您已经拥有 Dockerfile,并且已配置 PHP 应用以连接到数据库,接下来让我们来试一下!
如果您还没有安装 Docker,请进行安装(链接)。如果您使用的是 Cloud Shell,则无需执行此操作(是不是很酷?)。
现在,尝试使用相应的 Docker 构建和运行命令来构建并运行容器化的 PHP 应用。
# Build command - don't forget the final . This works if Dockerfile is inside the code folder:
$ docker build -t my-php-app-docker .
# Local Run command: most likely ports will be 8080:8080
$ docker run -it -p <CONTAINER_PORT>:<LOCAL_MACHINE_PORT> my-php-app-docker
如果一切正常,您应该能够在连接到本地主机时看到以下网页!现在,您的应用正在端口 8080 上运行,点击“网页预览”图标(带有眼睛的浏览器),然后点击在端口 8080 上预览(或“更改端口”以使用任何其他端口)

在浏览器中测试结果
现在,您的应用应如下所示:

如果您使用 Admin/admin123 登录,则会看到类似如下的内容。

太棒了!!!除了意大利语文本外,其他一切正常!🎉🎉🎉
如果您的 Docker 化没问题,但数据库凭据有误,您可能会看到类似以下内容的错误消息:

再试一次,你快成功了!
保存到 Artifact Registry [可选]
到目前为止,您应该已经拥有一个可正常运行的容器化 PHP 应用,可以将其部署到云端。接下来,我们需要在云端找到一个位置来存储 Docker 映像,并使其可用于部署到 Google Cloud 服务(例如 Cloud Run)。此存储解决方案称为 Artifact Registry,是一项全托管式 Google Cloud 服务,旨在存储应用制品,包括 Docker 容器映像、Maven 软件包、npm 模块等。
我们来使用相应的按钮在 Google Cloud Artifact Registry 中创建一个制品库。

选择有效的名称、格式和适合存储制品的区域。

返回到本地开发环境,标记应用容器映像并将其推送到刚刚创建的 Artifact Registry 代码库。为此,请完成以下命令。
- docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
- docker push TARGET_IMAGE[:TAG]
结果应如下列屏幕截图所示。

恭喜 🎉🎉🎉,您可以进入下一级别了。在此之前,您可以花 2 分钟时间尝试上传/登录/退出,熟悉应用端点。您稍后会用到它们。
可能出现的错误
如果您遇到容器化错误,请尝试使用 Gemini 解释并修正该错误,并提供以下信息:
- 您当前的 Dockerfile
- 收到的错误
- [如果需要] 正在执行的 PHP 代码。
上传权限。您还可以尝试使用 /upload.php 端点,并尝试上传图片。您可能会收到以下错误。如果是,您需要在 Dockerfile 中进行一些 chmod/chown 修复。
警告:move_uploaded_file(uploads/image (3).png):无法打开流:权限被拒绝,位于 /var/www/html/upload.php 的第 11 行
PDOException“找不到驱动程序”(或“Errore di connessione: could not find driver”)。确保您的 Dockerfile 具有适用于 mysql (pdo_mysql) 的适当 PDO 库,以便连接到数据库。点击此处,从解决方案中获取灵感。
无法将您的请求转发到后端。无法连接到端口 8080 上的服务器。这意味着您可能公开了错误的端口。确保您公开的是 Apache/Nginx 实际提供服务的端口。这并非易事。如果可以,请尝试将该端口设为 8080(这样可以更轻松地使用 Cloud Run)。如果您想保留端口 80(例如,因为 Apache 需要这样做),请使用其他命令来运行它:
$ docker run -it -p 8080:80 # force 80
# Use the PORT environment variable in Apache configuration files.
# https://cloud.google.com/run/docs/reference/container-contract#port
RUN sed -i 's/80/${PORT}/g' /etc/apache2/sites-available/000-default.conf /etc/apache2/ports.conf
5. 第 3 模块:将应用部署到 Cloud Run

为何选择 Cloud Run?
这个问题问得好!几年前,您肯定会选择 Google App Engine。
简而言之,如今的 Cloud Run 具有更新的技术堆栈,部署起来更轻松、更便宜,并且在您不使用时会缩容至 0。它可灵活运行任何无状态容器,并与各种 Google Cloud 服务集成,因此非常适合以最小的开销和最高的效率部署微服务和现代应用。
更具体地说,Cloud Run 是 Google Cloud 提供的一项全托管式平台,可让您在无服务器环境中运行无状态容器化应用。它会自动处理所有基础架构,根据传入流量从零开始扩缩,并在空闲时缩减,从而实现经济高效。Cloud Run 支持任何语言或库,只要它们打包在容器中即可,从而在开发方面提供极大的灵活性。它可与其他 Google Cloud 服务完美集成,非常适合构建微服务、API、网站和事件驱动型应用,而无需管理服务器基础架构。
前提条件
若要完成此任务,您应在本地机器上安装 gcloud。如果未看到,请点击此处查看相关说明。如果您使用的是 Google Cloud Shell,则无需采取任何行动。
部署之前…
如果您在本地环境中工作,请使用以下命令向 Google Cloud 进行身份验证
$ gcloud auth login –update-adc # not needed in Cloud Shell
这应该会通过浏览器上的 OAuth 登录对您进行身份验证。请确保您通过 Chrome 使用已启用结算功能的 Google Cloud 账号所对应的用户(例如 vattelapesca@gmail.com)登录。
使用以下命令启用 Cloud Run API:
$ gcloud services enable run.googleapis.com cloudbuild.googleapis.com
此时,一切都已准备就绪,可以部署到 Cloud Run 了。
通过 gcloud 将应用部署到 Cloud Run
您可以使用 gcloud run deploy 命令在 Cloud Run 上部署应用。您可以设置多个选项来实现自己的目标。您可以通过命令行提供以下最低限度的选项,也可以通过交互式提示让工具询问您:
- 您要为应用部署的 Cloud Run 服务的名称。Cloud Run 服务将返回一个网址,该网址可为您的应用提供一个端点。
- 应用将运行的 Google Cloud 区域。(
--region区域) - 封装应用的容器映像。
- 应用在执行期间需要使用的环境变量。
- 允许未经身份验证的访问的标志,允许所有人无需进一步的身份验证即可访问您的应用。
请参阅文档(或向下滚动查看可能的解决方案),了解如何将此选项应用于命令行。
部署需要几分钟时间。如果一切正常,您应该会在 Google Cloud 控制台中看到类似以下内容。


点击 Cloud Run 提供的网址,测试您的应用。通过身份验证后,您应该会看到类似如下的内容。

不带任何实参的“gcloud run deploy”
您可能已经注意到,gcloud run deploy 会询问您合适的问题,并填写您留下的空白。太棒了!
不过,在接下来的几个模块中,我们将把此命令添加到 Cloud Build 构建触发器,因此不能使用互动式问题。我们需要填写命令中的每个选项。因此,您想打造金色 gcloud run deploy --option1 blah --foo bar --region your-fav-region。如何实现?
- 重复执行第 2-3-4 步,直到 gcloud 停止提问:
- [LOOP]
gcloud run deploy(包含目前找到的选项) - [循环] 系统要求提供选项 X
- [LOOP] 在公开文档中搜索如何通过添加选项
--my-option [my-value]从 CLI 设置 X。 - 现在返回到第 2 步,除非 gcloud 在没有进一步问题的情况下完成。
- 这个 gcloud run deploy BLAH BLAH BLAH 太棒了!将该命令保存到某个位置,您稍后会在 Cloud Build 步骤中用到它!
恭喜 🎉🎉🎉 您已成功在 Google Cloud 中部署应用,完成了现代化改造的第一步。
6. 第 4 模块:使用 Secret Manager 清理密码

在上一步中,我们已成功在 Cloud Run 中部署并运行应用。不过,我们采用了一种不安全的做法:以明文形式提供一些 Secret。
首次迭代:更新 config.php 以使用 ENV
您可能已经注意到,我们在 config.php 文件中将数据库密码直接放入了代码中。这对于测试目的和查看应用是否正常运行来说是没问题的。但您无法提交/使用此类代码,因为它们不适合在生产环境中使用。密码(和其他数据库连接参数)应在运行时动态读取并提供给应用。更改 config.php 文件,使其从 ENV 变量中读取数据库参数。如果失败,您应考虑设置默认值。如果您无法加载 ENV,这会很有用,因为网页输出会告知您是否使用了默认值。填写空白处,并替换 config.php 中的代码。
<?php
// Database configuration with ENV variables. Set default values as well
$db_host = getenv('DB_HOST') ?: 'localhost';
$db_name = getenv('DB_NAME') ?: 'image_catalog';
$db_user = getenv('DB_USER') ?: 'appmod-phpapp-user';
$db_pass = getenv('DB_PASS') ?: 'wrong_password';
// Note getenv() is PHP 5.3 compatible
try {
$pdo = new PDO("mysql:host=$db_host;dbname=$db_name", $db_user, $db_pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("Errore di connessione: " . $e->getMessage());
}
session_start();
?>
由于您的应用已容器化,因此您需要提供一种方式来向应用提供 ENV 变量。这可以通过以下几种方式实现:
- 在 build 时,在 Dockerfile 上。使用语法 ENV DB_VAR=ENV_VAR_VALUE 将 4 个参数添加到之前的 Dockerfile 中。这将设置可在运行时替换的默认值。例如,您可以在此处设置“DB_NAME”和“DB_USER”,而不能在其他任何位置设置。
- 在运行时。您可以为 Cloud Run 设置这些变量,无论是通过 CLI 还是界面都可以。这是放置所有 4 个变量的正确位置(除非您想保留 Dockerfile 中设置的默认值)。
在 localhost 中,您可能需要将 ENV 变量放在 .env 文件中(请查看 solutions 文件夹)。
另请确保已将 .env 添加到 .gitignore 中:您不希望将密钥推送到 GitHub!
echo .env >> .gitignore
之后,您可以在本地测试实例:
docker run -it -p 8080:8080 --env-file .env my-php-app-docker
现在,您已实现以下目标:
- 您的应用将从 ENV 中动态读取变量
- 您已从代码中移除数据库密码,从而提高了安全性)
现在,您可以将新修订版本部署到 Cloud Run。我们来跳到界面上,手动设置环境变量:
- 前往 https://console.cloud.google.com/run
- 点击您的应用
- 点击“修改和部署新的修订版本”
- 在第一个标签页“容器”中,点击下方的标签页“变量和密钥”
- 点击“+ 添加变量”,然后添加所有需要的变量。最终结果应如下所示:


这是否完美?不会。大多数运营商仍会看到您的 PASS。不过,Google Cloud Secret Manager 可以缓解此问题。
第二次迭代:Secret Manager
您的密码已从您自己的代码中消失:成功!不过,等一下,我们安全了吗?
任何有权访问 Google Cloud 控制台的用户仍可查看您的密码。事实上,如果您访问 Cloud Run YAML 部署文件,便可以检索到该文件。或者,如果您尝试修改或部署新的 Cloud Run 修订版本,密码会显示在“变量和 Secret”部分,如下面的屏幕截图所示。
Google Cloud Secret Manager 是一项安全、集中的服务,用于管理 API 密钥、密码、证书和其他机密信息等敏感信息。
借助该服务,您可以存储、管理和访问具有精细权限和强大加密功能的密文。Secret Manager 与 Google Cloud 的 Identity and Access Management (IAM) 集成,可让您控制哪些用户可以访问特定 Secret,从而确保数据安全和监管合规。
它还支持自动 Secret 轮换和版本控制,从而简化 Secret 生命周期管理并增强 Google Cloud 服务中应用的安全性。
如需访问 Secret Manager,请从汉堡菜单前往安全性服务,然后在数据保护部分下找到它,如下面的屏幕截图所示。

进入该页面后,按照下图所示启用 Secret Manager API。

- 现在,点击“创建密钥”:我们来合理地命名一下:
- 名称:
php-amarcord-db-pass - 密钥值:“您的数据库密码”(忽略“上传文件”部分)。
- 为该 Secret 链接添加注释,应如下所示:
projects/123456789012/secrets/php-amarcord-db-pass。这是指向您的 Secret 的唯一指针(适用于 Terraform、Cloud Run 等)。该数字是您的唯一项目编号。
提示:尝试为您的密钥使用一致的命名惯例,从左到右进行细化,例如:cloud-devrel-phpamarcord-dbpass
- 组织(公司)
- 团队(组织内)
- 应用(在团队内)
- 变量名称(在应用内)
这样一来,您就可以使用简单的正则表达式来查找单个应用的所有密钥。
创建新的 Cloud Run 修订版本
现在我们已经有了新的 Secret,需要移除 DB_PASS 环境变量并将其替换为新的 Secret。因此:
- 使用 Google Cloud 控制台访问 Cloud Run
- 选择相应应用。
- 点击“修改和部署新修订版本”
- 找到“变量和密钥”标签页。
- 使用“+ 引用密文”按钮重置 DB_PASS 环境变量。
- 为引用的 Secret 使用相同的“DB_PASS”,并使用最新版本。

完成后,您应该会收到以下错误

尝试找出解决办法。如需解决此问题,您需要访问 IAM 和管理部分,然后更改授予权限。祝您调试顺利!
找出问题后,返回 Cloud Run 并重新部署新修订版本。结果应如图所示:

提示:开发者控制台(界面)非常擅长指出权限问题。请花时间浏览 Cloud 实体的所有链接!
7. 第 5 模块:使用 Cloud Build 设置 CI/CD

为什么要使用 CI/CD 流水线?
到目前为止,您应该已经输入过几次 gcloud run deploy,可能还反复回答了相同的问题。
厌倦了使用 gcloud run deploy 手动部署应用?如果您每次将新更改推送到 Git 代码库时,应用都能自动部署,那岂不是很棒?
如需使用 CI/CD 流水线,您需要做好以下两项准备:
- 个人 Git 代码库:幸运的是,您应该已在第 2 步中将研讨会代码库克隆到自己的 GitHub 账号。如果未完成,请返回并完成该步骤。您的派生代码库应如下所示:
https://github.com/<YOUR_GITHUB_USER>/app-mod-workshop - Cloud Build。这项出色的廉价服务可让您为几乎所有内容配置 build 自动化:Terraform、容器化应用等。
本部分将重点介绍如何设置 Cloud Build。
进入 Cloud Build!
我们将使用 Cloud Build 来实现此目的:
- 使用 Dockerfile 构建源代码。您可以将其视为一个“大型 .zip 文件”,其中包含构建和高效运转应用所需的一切内容(您的“build 工件”)。
- 将此制品推送到 Artifact Registry (AR)。
- 然后,从 AR 向 Cloud Run 发布应用“php-amarcord”的部署
- 这会为现有应用创建一个新的版本(“修订版本”)(可将其视为包含新代码的层),如果推送成功,我们会将其配置为将流量转移到新版本。
以下是我的 php-amarcord 应用的一些 build 示例:

我们如何实现所有这些目标?
- 通过精心制作一个完美的 YAML 文件:
cloudbuild.yaml - 通过创建 Cloud Build 构建触发器。
- 通过 Cloud Build 界面连接到我们的 GitHub 代码库。
创建触发器(并连接代码库)
- 前往 https://console.cloud.google.com/cloud-build/triggers
- 点击“创建触发器”。
- 编译:
- 名称:有意义的名称,例如
on-git-commit-build-php-app - 事件:推送到分支
- 来源:“关联新代码库”

- 这会在右侧打开一个窗口:“关联代码库”
- 来源提供方:“Github”(第一个)
- “继续”
- Authenticate 将在 GitHub 上打开一个窗口以进行交叉身份验证。按照流程操作,并耐心等待。如果您有很多代码库,可能需要一段时间。
- “选择代码库”选择您的账号/代码库,然后勾选“我了解...”部分。
- 如果您收到错误:“未针对您的任何代码库安装 GitHub 应用”,请继续点击“安装 Google Cloud Build”,然后按照说明操作。
点击“连接”
- 答对了!您的代码库现已连接。
- 回到“触发器”部分…
- 配置:自动检测 (*)
- 高级:选择服务账号“[PROJECT_NUMBER]- compute@developer.gserviceaccount.com”
- xxxxx 是您的项目 ID
- 默认计算服务账号适合实验室方法,但请勿在生产环境中使用!(了解详情)。
- 其他所有内容均保持不变。
- 点击“创建”按钮。
(*) 这是最简单的方法,因为它会检查 Dockerfile 或 cloudbuild.yaml。不过,cloudbuild.yaml 确实能让您决定在哪个步骤执行什么操作。
我拥有了力量!
现在,除非您向 Cloud Build 服务账号(什么是服务账号?代表您执行任务(在本例中是在云端构建内容)的“机器人”的电子邮件地址。
除非您授权 SA 执行此操作,否则 SA 将无法构建和部署。幸运的是,这很容易!
- 前往“Cloud Build”>“设置”。
- “[PROJECT_NUMBER]- compute@developer.gserviceaccount.com”服务账号
- 勾选以下复选框:
- Cloud Run
- Secret Manager
- 服务账号
- Cloud Build
- 同时勾选“设置为首选服务账号”

Cloud Build YAML 在哪里?
我们强烈建议您花一些时间创建自己的 Cloud Build YAML。
不过,如果您没有时间或不想抽出时间,可以在此解决方案文件夹中获取一些灵感:.solutions
现在,您可以将更改推送到 GitHub,并观察 Cloud Build 的运行情况。
设置 Cloud Build 可能比较棘手。预计往返时间:
- 在 https://console.cloud.google.com/cloud-build/builds;region=global 中查看日志
- 正在查找错误。
- 在代码中修复,然后重新发出 git commit / git push。
- 有时,错误不在代码中,而是在某些配置中。在这种情况下,您可以通过界面(云端 build >“触发器”>“运行”)发布新的 build

请注意,如果您使用此解决方案,仍需完成一些工作。例如,您需要为新创建的开发/生产端点设置环境变量:

可以通过以下两种方法实现此目的:
- 通过 UI - 通过再次设置环境变量
- 通过 CLI 为您打造“完美”脚本。您可以在此处找到示例:gcloud-run-deploy.sh。您需要调整一些内容,例如端点和项目编号;您可以在 Cloud 概览中找到项目编号。
如何将代码提交到 GitHub?
本研讨会不涉及如何以最佳方式 git push 到 GitHub。不过,如果您遇到问题,并且正在使用 Cloud Shell,则可以通过以下两种方式解决:
- CLI。在本地添加 SSH 密钥,并添加一个远程代码库,其网址为 git@github.com:YOUR_USER/app-mod-workshop.git(而不是 http)
- VSCode。如果您使用 Cloud Shell 编辑器,可以使用“源代码控制”(Ctrl-Shift-G) 标签页,点击“同步更改”,然后按照说明操作。您应该能够向 VS Code 验证您的 GitHub 账号,然后轻松地从 VS Code 中拉取/推送代码。

请务必将 git add clodubuild.yaml 添加到其他文件中,否则该功能将无法正常运行。
深层与浅层“开发/生产对等性”[可选]
如果您从此处复制了模型版本,那么您将拥有两个相同的开发版本和正式版。这很棒,而且符合十二要素应用的第 10 条规则。
不过,我们使用两个不同的 Web 端点,让应用指向同一数据库。这对于工作坊来说已经足够了;不过,在现实生活中,您需要花一些时间来创建合适的生产环境。这意味着您需要有两个数据库(一个用于开发,一个用于生产),还需要选择将它们放在哪里,以实现灾难恢复 / 高可用性。这超出了本研讨会的范围,但值得思考。
如果您有时间制作“深度”版本的广告,请务必考虑需要复制的所有资源,例如:
- Cloud SQL 数据库(可能还有 SQL 实例)。
- GCS 存储桶
- Cloud Functions。
- 您可以在开发中使用 Gemini 1.5 Flash 作为模型(更便宜、更快),并使用 Gemini 1.5 Pro(功能更强大)。
一般来说,每次您对应用执行操作时,都要进行批判性思考:生产环境是否应具有相同的值?如果不是,请加倍努力。当然,使用 Terraform 可以更轻松地实现这一点,您只需将环境(-dev、-prod)作为后缀注入到资源中即可。
8. 第 6 单元:迁移到 Google Cloud Storage

存储

目前,应用将状态存储在 Docker 容器中。如果机器出现故障、应用崩溃,或者您只是推送了新的修订版本,系统会安排新的修订版本,并使用新的空存储空间:🙈
如何解决此问题?方法有很多。
- 将图片存储在数据库中。我之前的 PHP 应用就是这样做的。这是最简单的解决方案,不会增加复杂性。但它肯定会增加数据库的延迟时间和负载!
- 将 Cloud Run 应用迁移到存储友好型解决方案:GCE + 永久性磁盘?也许是 GKE + 存储?注意:控制力越强,灵活性越差。
- 移至 GCS。Google Cloud Storage 为整个 Google Cloud 提供一流的存储服务,是最符合云理念的解决方案。不过,这需要我们使用 PHP 库。我们是否有适用于 GCS 的 PHP 5.7 库?
PHP 5.7是否支持Composer(Composer 支持的最早版本似乎是 PHP 5.3.2)? - 或许可以使用 Docker Sidecar?
- 或者,您也可以使用 GCS Cloud Run 卷装载。这听起来很棒。
🤔 迁移存储空间(开放式)
[开放式] 在本练习中,我们希望您找到一种解决方案,以某种方式持久地移动图片。
验收测试
我不想告诉你答案,但希望实现以下效果:
- 您上传
newpic.jpg。您可以在应用中看到。 - 您将应用升级到新版本。
newpic.jpg仍存在,且可见。
💡 可能的解决方案(GCS Cloud Run 卷装载)
这是一个非常优雅的解决方案,可让我们实现有状态的文件上传,而无需触及任何代码(除了显示图片说明,但这微不足道,只是为了让用户满意)。
这样一来,您应该就可以将 Cloud Run 中的文件夹挂载到 GCS,因此:
- 上传到 GCS 的所有内容实际上都会在您的应用中显示。
- 实际上,您应用的所有上传内容都将上传到 GCS
- 在 GCS 中上传的对象将发生神奇的变化(第 7 章)。
注意:请仔细阅读 FUSE 细则。如果性能存在问题,则不应这样做。
创建 GCS 存储分区
GCS 是 Google Cloud 无处不在的存储服务。它经过实战检验,并且被需要存储空间的每个 GCP 服务所使用。
请注意,Cloud Shell 会将 PROJECT_ID 导出为 GOOGLE_CLOUD_PROJECT:
$ export PROJECT_ID=$GOOGLE_CLOUD_PROJECT
#!/bin/bash
set -euo pipefail
# Your Cloud Run Service Name, eg php-amarcord-dev
SERVICE_NAME='php-amarcord-dev'
BUCKET="${PROJECT_ID}-public-images"
GS_BUCKET="gs://${BUCKET}"
# Create bucket
gsutil mb -l "$GCP_REGION" -p "$PROJECT_ID" "$GS_BUCKET/"
# Copy original pictures there - better if you add an image of YOURS before.
gsutil cp ./uploads/*.png "$GS_BUCKET/"
将 Cloud Run 配置为将存储分区装载到 /uploads/ 文件夹中
现在,我们来介绍一下优雅的部分。我们创建卷 php_uploads,并指示 Cloud Run 对 MOUNT_PATH 执行 FUSE 装载(类似于 /var/www/html/uploads/):
#!/bin/bash
set -euo pipefail
# .. keep variables from previous script..
# Uploads folder within your docker container.
# Tweak it for your app code.
MOUNT_PATH='/var/www/html/uploads/'
# Inject a volume mount to your GCS bucket in the right folder.
gcloud --project "$PROJECT_ID" beta run services update "$SERVICE_NAME" \
--region $GCP_REGION \
--execution-environment gen2 \
--add-volume=name=php_uploads,type=cloud-storage,bucket="$BUCKET" \
--add-volume-mount=volume=php_uploads,mount-path="$MOUNT_PATH"
现在,针对要指向 Cloud Storage 的所有端点重复此步骤。
您也可以通过界面实现相同的目标
- 在“卷”标签页下,创建一个指向您的存储分区的卷挂载,类型为“Cloud Storage 存储分区”,例如名称为“php_uploads”。
- 在“容器”>“卷装载”下,将您刚刚创建的卷装载到应用请求的卷点。这取决于 Dockerfile,但可能类似于
var/www/html/uploads/。
无论哪种方式,如果一切正常,您在修改新的 Cloud Run 修订版本时应该会看到类似如下的内容:

现在,通过向 /upload.php 端点上传一张新图片来测试新应用。
图片应在 GCS 上无缝流动,无需编写任何 PHP 代码:

刚才发生了什么?
发生了一些非常神奇的事情。
具有旧代码的旧应用仍在正常运行。借助新的现代化堆栈,我们可以将应用中的所有图片/照片轻松存储在有状态的 Cloud 存储分区中。现在,您可以尽情发挥创意:
- 想在每次收到包含“危险”或“裸体”内容的图片时发送电子邮件吗?您无需修改 PHP 代码即可实现此目的。
- 是否希望在每次收到图片时都使用 Gemini 多模态模型来描述图片,并将数据库及其描述上传?您无需修改 PHP 代码即可实现此目的。你不相信我?请继续阅读第 7 章。
我们刚刚在这里发掘了一个巨大的机遇空间。
9. 第 7 单元:使用 Google Gemini 赋能您的应用

现在,您拥有一个出色的现代化全新 PHP 应用(例如 2024 年款 Fiat 126),并已实现云端存储。
您可以用它来做些什么呢?
前提条件
在上一章中,我们通过一个模型解决方案将 GCS 上的图片 /uploads/ 装载到应用中,事实上将应用逻辑与图片存储分离开来。
本练习要求您执行以下操作:
- 已成功完成第 6 章(存储)中的练习。
- 拥有一个包含图片上传内容的 GCS 存储分区,用户可以在您的应用中上传图片,而图片会流入您的存储分区。
设置 Cloud Functions 函数(使用 Python)
您是否曾想过如何实现事件驱动型应用?例如:
- 当发生 <event> 时 => 发送电子邮件
- 当 <event> 发生时 => 如果 <condition> 为 true,则更新数据库。
事件可以是任何内容,例如 BigQuery 中有新记录可用、GCS 中某个文件夹中的新对象发生更改,或者 Pub/Sub 中的队列中有新消息等待处理。
Google Cloud 支持多种范式来实现这一目标。最值得注意的是:
- EventArc。了解如何接收 GCS 事件。非常适合在云端创建 DAG 并根据 if-then-else 语句编排操作。
- Cloud Scheduler。非常适合在云端运行午夜 cron 作业。
- Cloud Workflows。与 Event Arc 类似,可让您
- Cloud Run Functions(俗称
lambdas)。 - Cloud Composer。基本上是 Google 版本的 Apache Airflow,也非常适合 DAG。
在此练习中,我们将深入探讨 Cloud Functions 函数,以实现相当出色的结果。我们还会为您提供选做练习。
请注意,示例代码在 .solutions/ 下提供
设置 Cloud Functions 函数 (🐍 Python)
我们正尝试创建一个非常宏大的 GCF。
- 在 GCS 上创建新映像时...(可能是因为有人已在应用中上传了该内容 - 但不仅限于此)
- .. 调用 Gemini 来描述图片并获取图片的文本说明 ..(最好检查 MIME 并确保它是图片,而不是 PDF、MP3 或文本)
- .. 并使用此说明更新数据库。(这可能需要修补数据库,以向
images表添加description列)。
修补数据库以向图片添加 description
- 打开 Cloud SQL Studio:

- 输入图片数据库的用户名和密码
- 注入以下 SQL,以添加用于图片说明的列:
ALTER TABLE images ADD COLUMN description TEXT;

宾果!现在尝试检查是否成功:
SELECT * FROM images;
您应该会看到新的说明列:

写出 Gemini f(x)
注意:此函数实际上是在 Gemini Code Assist 的帮助下创建的。
注意:创建此函数可能会导致 IAM 权限错误。部分错误记录在下方的“可能出现的错误”段落中。
- 启用 API
- 前往 https://console.cloud.google.com/functions/list
- 点击“创建函数”
- 通过 API 向导启用 API:

您可以通过界面或命令行创建 GCF。在此,我们将使用命令行。
您可以在 .solutions/ 下找到可能的代码
- 创建一个用于托管代码的文件夹,例如“gcf/”。进入相应文件夹。
- 创建
requirements.txt文件:
google-cloud-storage
google-cloud-aiplatform
pymysql
- 创建 Python 函数。示例代码:gcf/main.py。
#!/usr/bin/env python
"""Complete this"""
from google.cloud import storage
from google.cloud import aiplatform
import vertexai
from vertexai.generative_models import GenerativeModel, Part
import os
import pymysql
import pymysql.cursors
# Replace with your project ID
PROJECT_ID = "your-project-id"
GEMINI_MODEL = "gemini-1.5-pro-002"
DEFAULT_PROMPT = "Generate a caption for this image: "
def gemini_describe_image_from_gcs(gcs_url, image_prompt=DEFAULT_PROMPT):
pass
def update_db_with_description(image_filename, caption, db_user, db_pass, db_host, db_name):
pass
def generate_caption(event, context):
"""
Cloud Function triggered by a GCS event.
Args:
event (dict): The dictionary with data specific to this type of event.
context (google.cloud.functions.Context): The context parameter contains
event metadata such as event ID
and timestamp.
"""
pass
- 推送函数。您可以使用类似于以下内容的脚本:gcf/push-to-gcf.sh。
备注 1:请务必使用正确的值获取环境变量,或直接在顶部添加这些变量(GS_BUCKET=blah,...):
注意 2. 这会推送所有本地代码 (.),因此请务必将代码放在特定文件夹中,并像专业人士一样使用 .gcloudignore,以避免推送大型库。(示例)。
#!/bin/bash
set -euo pipefail
# add your logic here, for instance:
source .env || exit 2
echo "Pushing ☁️ f(x)☁ to 🪣 $GS_BUCKET, along with DB config.. (DB_PASS=$DB_PASS)"
gcloud --project "$PROJECT_ID" functions deploy php_amarcord_generate_caption \
--runtime python310 \
--region "$GCP_REGION" \
--trigger-event google.cloud.storage.object.v1.finalized \
--trigger-resource "$BUCKET" \
--set-env-vars "DB_HOST=$DB_HOST,DB_NAME=$DB_NAME,DB_PASS=$DB_PASS,DB_USER=$DB_USER" \
--source . \
--entry-point generate_caption \
--gen2
注意:在此示例中,generate_caption 将是调用的方法,Cloud Functions 会将 GCS 事件连同所有相关信息(存储分区名称、对象名称等)传递给该方法。请花一些时间调试该事件 Python 字典。
测试函数
单元测试
该函数包含许多可变部分。您可能希望能够测试所有单个广告素材。
示例位于 gcf/test.py 中。
Cloud Functions 界面
您还可以花一些时间在界面上探索该函数。每个标签页都值得探索,尤其是 Source(我的最爱)、Variables、Trigger 和 Logs;您将花费大量时间在 Logs 中进行问题排查(另请参阅本页底部的可能错误)。另请务必检查 Permissions。

端到端测试
现在可以手动测试该函数了!
- 前往应用并登录
- 上传一张图片(不要太大,我们发现大图片存在问题)
- 在界面上检查图片是否已上传。
- 在 Cloud SQL Studio 中检查说明是否已更新。登录并运行以下查询:
SELECT * FROM images。

效果非常好!我们可能还需要更新前端以显示该说明。
更新 PHP 以显示 [可选]
我们已证明该应用可以正常运行。不过,如果用户也能看到该说明,那就更好了。
我们无需成为 PHP 专家,即可将说明添加到 index.php。此代码应执行以下操作(没错,也是 Gemini 为我编写的!):
<?php if (!empty($image['description'])): ?>
<p class="font-bold">Gemini Caption:</p>
<p class="italic"><?php echo $image['description']; ?></p>
<?php endif; ?>
您可以根据自己的喜好将此代码放置在 foreach 内。
在后续步骤中,我们还会看到一个更美观的界面版本,这要归功于 Gemini Code Assist。美观的版本可能如下所示:

结论
您获得了一个在 GCS 上有新对象时触发的 Cloud Function,该函数能够像人类一样注释图片的内容,并自动更新数据库。哇哦!
接下来该怎么做?您可以按照相同的推理来实现两项出色的功能。
[可选] 添加更多 Cloud Functions [开放式]
我想到了几个附加功能。
📩 电子邮件触发器
一种电子邮件触发器,每次有人发送图片时都会向您发送电子邮件。
- 过于频繁?添加进一步的限制:大图片,或 Gemini 内容包含“裸体/裸露/暴力”字样的图片。
- 不妨查看
EventArc。
🚫 自动审核不当图片
目前,人工管理员会标记“不当”图片。让 Gemini 承担繁重的工作并审核聊天室内容怎么样?添加一项测试,以标记不当的触发内容,并按照我们在上一个函数中学到的知识更新数据库。这意味着,基本上就是采用之前的函数,更改提示,并根据回答更新数据库。
注意事项。生成式 AI 的输出不可预测。确保 Gemini 的“创意输出”受到“限制”。您可能会要求确定性回答,例如介于 0 到 1 之间的置信度分数、JSON 等。您可以通过多种方式实现此目的,例如:* 使用 Python 库 pydantic、langchain 等。* 使用 Gemini 结构化输出。
提示。您可以有多个函数,也可以使用单个提示来强制生成 JSON 回答(与上述“Gemini 结构化输出”功能搭配使用效果极佳),例如:
生成此图片需要使用什么提示?
{
"description": "This is the picture of an arrosticino",
"suitable": TRUE
}
您可以在提示中添加其他字段,以获取以下数据分析:该商品是否有什么优点?缺点?您认识这个地方吗?是否有一些文字(OCR 从未如此简单):
goods:“看起来像美味的食物”bads:“看起来像是不健康的食物”OCR: "Da consumare preferibilmente prima del 10 Novembre 2024"location:“佩斯卡拉,海滨大道”
虽然通常最好为 N 个结果提供 N 个函数,但如果能提供一个可执行 10 项操作的函数,回报会非常丰厚。请参阅这篇 Riccardo 的文章,了解具体操作方法。
可能出现的错误(主要是 IAM / 权限问题)
我首次开发此解决方案时,遇到了一些 IAM 权限问题。我将在此处添加这些问题,以表达同情并提供一些有关如何解决这些问题的想法。
错误:服务账号权限不足
- 请注意,如需部署监听 GCS 存储分区的 GCF 函数,您需要为作业所用的服务账号设置适当的权限,如图所示:

您可能还需要启用 EventArc API,这需要几分钟时间才能完全可用。
错误:缺少 Cloud Run Invoker
- 界面中有关 GCF 权限的另一条注释是(Cloud Run Invoker 角色):

此错误可通过运行图片中的命令来修复,该命令类似于 fix-permissions.sh
如需了解此问题的相关信息,请访问以下网址:https://cloud.google.com/functions/docs/securing/authenticating
错误:内存用量超出上限
我第一次运行它时,日志可能会显示:“内存限制为 244 MiB,已使用 270 MiB,超出内存限制。请考虑提高内存限制,详情请参阅 https://cloud.google.com/functions/docs/configuring/memory。”。再次向 GCF 添加 RAM。在界面中执行此操作非常简单。以下是可能的加推:

或者,您也可以修复 Cloud Run 部署脚本以增加内存/CPU。这需要更长时间。
错误:PubSub 已发布
使用 GCF v1 创建触发器时,曾出现以下错误:

同样,您只需前往 IAM 并向您的服务账号授予“Pub/Sub 发布者”角色,即可轻松解决此问题。
错误:尚未使用 Vertex AI
如果您收到此错误,请执行以下操作:
Permission Denied: 403 Vertex AI API has not been used in project YOUR_PROJECT before or it is disabled. 如需启用此 API,请访问 https://console.developers.google.com/apis/api/aiplatform.googleapis.com/overview?project=YOR_PROJECT
您只需启用 Vertex AI API 即可。启用所有必需 API 的最简单方法如下:
- https://console.cloud.google.com/vertex-ai
- 点击“启用所有推荐的 API”。

错误:未找到 EventArc 触发器。
如果遇到此问题,请重新部署函数。

错误:400 正在配置服务代理
400 Service agents are being provisioned ( https://cloud.google.com/vertex-ai/docs/general/access-control#service-agents ). Service agents are needed to read the Cloud Storage file provided. 因此,请过几分钟后再试。
如果出现这种情况,请等待一段时间或咨询 Google 员工。
10. 第 8 模块:创建可用性 SLO
在本章中,我们将尝试实现以下目标:
- 创建 SLI
- 根据 SLI 创建 SLO
- 基于 SLO 创建提醒

这是作者非常喜欢的一个主题,因为 Riccardo 在 Google Cloud 的 SRE / DevOps 领域工作。
(开放式)为此应用创建 SLI 和 SLO
如果无法判断应用是否出现故障,那么该应用有多好?
什么是 SLO?
噢,太巧了!Google 发明了 SLO!如需详细了解,您可以参阅以下文章:
- SRE 图书 - 第 2 章 - 实现 SLO。(👉 更多 SRE 书籍)
- SLO 的艺术(精彩视频)。这是一项出色的培训,可帮助您详细了解如何为服务打造完美的 SLO。
- Coursera 上的 SRE 课程。我为此做出了贡献!
第 1 步:创建可用性 SLI/SLO
我们先从可用性 SLO 开始,因为它是最简单且可能也是最重要的衡量指标。
幸运的是,借助 Istio,Cloud Run 预先构建了 SLO 支持。
将应用部署到 Cloud Run 后,实现此目的非常简单,只需 30 秒即可完成。
- 前往 Cloud Run 页面。
- 点击/选择您的应用。
- 选择
SLOs标签。 - 点击“+ 创建 SLO”。
- 适用范围:需提出申请
- 继续
- 日历月 / 99%。
- 点击“创建 SLO”。

第 2 步:针对此 SLO 设置提醒
建议您创建 2 个提醒:
- 一个具有低消耗率(“Slowburn”),可通过电子邮件提醒您(模拟低优先级工单)。
- 一种是高消耗率(“快速消耗”),通过短信提醒您(模拟高优先级工单 / 寻呼机)
前往之前的 SLO tab。
重复两次以下操作:

- 点击“创建 SLO 提醒”(右侧带有加号的 🔔 按钮)
- 回溯期、消耗率阈值:
- [FAST]。前
60分钟:10倍 - [SLOW]。第二:
720分钟 /2次 - 通知渠道:点击“管理通知渠道”
- 首先,“电子邮件” -> 添加新电子邮件地址 -> ..
- 其次,“短信” -> 添加新号码 -> 在手机上验证。
- 提示:我喜欢在名称中使用表情符号!非常适合用于演示。
- 完成后,点击右上角的大号 X。
- 先选择电话(快速),再选择电子邮件(慢速)。
- 添加一些示例文档,例如:
[PHP Amarcord] Riccardo told me to type sudo reboot or to check documentation in http://example.com/playbooks/1.php but I guess he was joking。
答对了!
最终结果
当您拥有 1 个有效的 SLO,并且可用性有 2 个提醒,且提醒会发送到您的电子邮件地址和手机时,我们可以认为此练习已完成。
您可以添加延迟时间(我强烈建议您这样做),甚至可以添加更复杂的延迟时间。对于延迟时间,请选择您认为合理的延迟时间;如果不确定,请选择 200 毫秒。
11. 后续步骤
您已完成所有操作,还缺少什么?
以下是一些值得思考的问题:
游戏期间使用 Gemini
您可以使用两种版本的 Gemini:
- Vertex AI。“企业方式”,与我们在第 7 章(GCF+Gemini)中探讨的 GCP 紧密相关。所有身份验证都能神奇地正常运行,服务也能完美地互联。
- Google AI。“消费者方式”。您可以从此处获取 Gemini API 密钥,然后开始构建可以绑定到您已有的任何工作负载(专有工作、其他云、本地主机等)的小脚本。您只需替换 API 密钥,代码就会神奇地开始运行。
我们建议您尝试在自己的宠物项目中探索 (2)。
界面提升
我不擅长界面设计。但 Gemini 可以!您只需创建一个 PHP 页面,然后添加类似如下的代码:
I have a VERY old PHP application. I want to touch it as little as possible. Can you help me:
1. add some nice CSS to it, a single static include for tailwind or similar, whatever you prefer
2. Transform the image print with description into cards, which fit 4 per line in the canvas?
Here's the code:
-----------------------------------
[Paste your PHP page, for instance index.php - mind the token limit!]
您只需使用 Cloud Build,即可在不到 5 分钟的时间内轻松实现此目标!:)
Gemini 的回答非常完美(也就是说,我无需做任何更改):

以下是作者个人应用中的新布局:

注意:由于我们不想鼓励您直接使用该代码,而是希望您让 Gemini 根据您自己的创意界面/前端限制条件为您编写代码,因此我们以图片形式粘贴了该代码;请相信我,之后您只需进行非常细微的更改。
安全性
妥善保护此应用并非此 4 小时研讨会的目标,因为这样做会使完成此研讨会所需的时间增加 1-2 个数量级。
不过,这个主题非常重要!我们在 SECURITY 中收集了一些想法。
12. 恭喜!
恭喜 🎉🎉🎉!您已成功使用 Google Cloud 对旧版 PHP 应用进行了现代化改造。

总结一下,在此 Codelab 中,您学习了以下内容:
- 如何在 Google Cloud SQL 中部署数据库,以及如何将现有数据库迁移到其中。
- 如何使用 Docker 和 Buildpack 将 PHP 应用容器化,并将其映像存储到 Google Cloud Artifact Registry
- 如何将容器化应用部署到 Cloud Run 并使其与 Cloud SQL 一起运行
- 如何使用 Google Secret Manager 以秘密方式存储/使用敏感配置参数(例如数据库密码)
- 如何使用 Google Cloud Build 设置 CI/CD 流水线,以便在每次将代码推送到 GitHub 代码库时自动构建和部署 PHP 应用。
- 如何使用 Cloud Storage 将应用资源“云端化”
- 如何利用无服务器技术在 Google Cloud 上构建出色的工作流,而无需修改应用代码。
- 在合适的应用场景中使用多模态 Gemini 功能。
- 在 Google Cloud 中实施 SRE 原则
这是您开始使用 Google Cloud 进行应用现代化改造的绝佳起点!
🔁 反馈
如果您想告诉我们您对本次研讨会的体验,请考虑填写此反馈表单。
我们欢迎您提供反馈,也欢迎您针对自己特别满意的代码片段提交 PR。
🙏 谢谢
作者谨在此感谢 Datatonic 的 Mirko Gilioli 和 Maurizio Ipsale 在撰写本文和测试解决方案方面提供的帮助。
