本文档详尽记载了一次从服务无反应开始,到最终实现 Envoy 代理集群自动化滚动更新的全过程。
1. 初始问题
我们试图通过
curl命令访问部署在
http://www.jpgcp.cloud上的聊天服务,但请求被长时间挂起,没有回应。
curl -N -X POST "http://www.jpgcp.cloud/py-chat-deepseek-svc/api/v1/chat" -H "Content-Type: application/json" -d '{"message": "Why is the sky blue?"}'
2. 排查过程
2.1. 后端服务日志分析
猜测
: 后端 Cloud Run 服务 (
py-chat-deepseek-svc) 在调用上游 LLM 时被阻碍。
行动
: 使用
gcloud logging read查看 Cloud Run 服务日志。
发现
: 日志中没有我们
curl请求的记录,反而充斥着来自外部 IP 对
.env,
.git/config等路径的扫描请求,且均返回
403 Not Authenticated。
初步结论
: 请求在抵达应用代码之前就被 GCP 前端阻止了。
2.2. 基础设施架构深入研究
重要信息
: 用户指出,在 Cloud Run 服务前设有一个 Envoy 代理,此代理部署在 GCE 虚拟机上,并负责处理 GCP 身份验证 (
gcp_authn)。
修正方向
: 问题重点从 Cloud Run 转向 Envoy 代理及其所在 GCE 虚拟机。
2.3. Envoy 虚拟机与配置不符
猜测
: 运行在 GCE 上的 Envoy 配置可能不准确。
行动
: 使用
gcloud compute instances list找到名为
my-envoy-vm-b5hr的可疑虚拟机。
SSH 连接到该虚拟机,尝试查找并读取
/etc/envoy/envoy.yaml配置文件。
发现
: 服务器上的
envoy.yaml是一个过时版本,完全没有定义与聊天服务相关的路由 (
/py-chat-deepseek-svc) 和集群。而我们本地代码库
envoy-config中的
envoy.yaml是一个更新、更全面的版本。
结论
: 部署流程失败,最新的配置没有同步到虚拟机上。
2.4. 代管实例组 (MIG) 的发现
猜测
: 为什么虚拟机会使用旧配置?它是手动创建的吗?
行动
: 使用
gcloud compute instances describe检查
my-envoy-vm-b5hr的
managedBy字段,意外返回
null。
根据用户提示,使用
gcloud compute instance-groups managed list检查项目中的 MIG。
关键发现
: 项目中确实存在一个名为
my-envoy的 MIG。进一步使用
list-instances确认,
my-envoy-vm-b5hr正是由这个 MIG 管理的实例。
最终结论
: 直接修改单个虚拟机的配置是无效且错误的,因为任何修改都会在 MIG 重启或修复实例时丢失。唯一正确的路径是更新 MIG 所使用的实例模板,然后触发滚动更新。
2.5. 自动化更新流程的建立与调试
我们的目标转变为:创建一个自动化的 Cloud Build 管道,用于正确地更新 MIG。
构建新镜像
: 我们确认使用
cloudbuild.yaml和 Packer (
gce.pkr.hcl) 用于构建包含最新
envoy.yaml的虚拟机镜像 (
packer-gce-envoy)。
成功运行
gcloud builds submit --config cloudbuild.yaml .,生成了最新的镜像。
创建自动化更新管道 (
cloudbuild_refresh_envoy_proxy.yaml)
: 目标
: 创建一个新管道,该管道能基于最新镜像创建新实例模板,并用它来滚动更新 MIG。
迭代调试过程
: 初版
: 尝试创建实例模板并设置给 MIG。
失败 & 修复 (权限问题)
: 日志显示 Cloud Build 使用的服务账号 (
terraform@...) 缺少
compute.images.get权限。我们确认该权限已存在,排除了权限问题。
失败 & 修复 (网络问题)
: 日志显示找不到名为
default的网络。我们在
instance-templates create命令中明确添加了
--subnet=tf-vpc0-subnet0参数。
失败 & 修复 (IP 问题)
: 日志显示找不到名为
static-ext-ip1的静态 IP。我们在
instance-templates create命令中将
--address参数的值从名称
static-ext-ip1改为直接使用 IP 地址
34.39.2.90。
失败 & 修复 (防火墙问题)
: 即使 IP 正确,请求仍可能被防火墙拦截。我们在
instance-templates create命令中添加了
--tags=http-server,https-server,以确保新创建的 VM 能匹配允许 HTTP/HTTPS 流量的防火墙规则。
3. 最终解决方案
我们最终创建了一个稳健的、自动化的 Cloud Build 管道
cloudbuild_refresh_envoy_proxy.yaml,并为其设置了定时调度。
3.1. 最终工作流程
开发/修改
: 开发者在本地修改
configs/envoy.yaml文件并推送到 Git 主分支。
构建镜像 (可选手动)
: 运行第一个 Cloud Build 管道 (
cloudbuild.yaml),使用 Packer 将最新的配置烘焙到一个新的
packer-gce-envoy虚拟机镜像中。
定时滚动更新
Cloud Scheduler 作业在每天凌晨 3 点自动激活第二个 Cloud Build 流水线(
cloudbuild_refresh_envoy_proxy.yaml),此流水线将自动执行以下详细步骤,实现 Envoy 集群的每日自动化更新。
这一过程不仅解决了初始的服务无响应难题,还构建了一个遵循 IaC 最佳实践的、自动化的基础设施管理与部署解决方案。
3.2.
cloudbuild_refresh_envoy_proxy.yaml
代码与解析
以下是用于滚动更新的 Cloud Build 配置文件内容:
steps:
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
id: create_instance_template
entrypoint: 'bash'
args:
- '-c'
- |
set -e
TEMPLATE_NAME="my-envoy-template-$(date +%s)"
echo "Creating new instance template: $$TEMPLATE_NAME"
gcloud compute instance-templates create $$TEMPLATE_NAME \
--project=jason-hsbc \
--image=packer-gce-envoy \
--image-project=jason-hsbc \
--region=europe-west2 \
--machine-type=e2-medium \
--subnet=tf-vpc0-subnet0 \
--service-account=terraform@jason-hsbc.iam.gserviceaccount.com \
--scopes=https://www.googleapis.com/auth/cloud-platform \
--tags=http-server,https-server \
--address=34.39.2.90
# Write the template name to a file to be used by the next step
echo $$TEMPLATE_NAME > /workspace/template_name.txt
echo "Successfully created instance template."
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
id: rolling_update_mig
entrypoint: 'bash'
args:
- '-c'
- |
set -e
TEMPLATE_NAME=$(cat /workspace/template_name.txt)
# Dynamically find the current MIG name
MIG_NAME=$(gcloud compute instance-groups managed list --project=jason-hsbc --filter="name~'my-envoy-'" --format="value(name)")
if [ -z "$$MIG_NAME" ]; then
echo "ERROR: No managed instance group found with prefix 'my-envoy-'"
exit 1
fi
echo "Found MIG: $$MIG_NAME. Applying new template: $$TEMPLATE_NAME"
gcloud compute instance-groups managed set-instance-template $$MIG_NAME \
--project=jason-hsbc \
--zone=europe-west2-c \
--template=$$TEMPLATE_NAME
echo "Successfully set new instance template for MIG."
# When using a custom service account, logging options must be explicitly set.
options:
logging: CLOUD_LOGGING_ONLY
代码解析
create_instance_template
步骤:基于最新的
packer-gce-envoy镜像,创建一个包含完整配置(如网络、IP 地址、标签等)的实例模板。
rolling_update_mig
步骤:动态查找当前的 Envoy MIG,并指令其使用新创建的模板以启动滚动更新。
options
解决使用自定义服务账户时需明确设置日志记录选项的问题。
3.3. 创建定时调度任务
为了达成每日自动刷新的目标,我们建立了一个 Cloud Scheduler 任务来定期触发上述 Cloud Build 过程。
- 建立 Cloud Build 触发机制 (如果尚未存在)
- 取得触发机制 ID
- 建立 Cloud Scheduler 任务
首先,需设立一个手动的 Cloud Build 触发机制来激活
cloudbuild_refresh_envoy_proxy.yaml
gcloud beta builds triggers create manual \
--name="trigger-refresh-envoy-mig" \
--project="jason-hsbc" \
--repo="https://github.com/nvd11/envoy-config.git" \
--repo-type="github" \
--branch="main" \
--build-config="cloudbuild_refresh_envoy_proxy.yaml" \
--region="europe-west2"
(注意: 在调试过程中,我们发现需要运用
--repository
参数替代
--repo
和
--repo-type
,或确保 gcloud 版本兼容。为简化文档,这里展示的是理想化的指令。)
gcloud beta builds triggers describe trigger-refresh-envoy-mig \
--project=jason-hsbc \
--region=europe-west2 \
--format="value(id)"
利用上一步获得的触发机制 ID,创建一个每日执行的调度任务。
gcloud scheduler jobs create http refresh-envoy-mig-daily \
--project="jason-hsbc" \
--location="europe-west2" \
--schedule="0 3 * * *" \
--uri="https://cloudbuild.googleapis.com/v1/projects/jason-hsbc/locations/europe-west2/triggers/[TRIGGER_ID]:run" \
--http-method="POST" \
--oauth-service-account-email="terraform@jason-hsbc.iam.gserviceaccount.com" \
--description="Daily task to refresh the Envoy MIG via executing a Cloud Build trigger."
(注意: 需要将
[TRIGGER_ID]
替换为前一步骤得到的真实 ID。)
此任务将以
terraform
服务账户的身份,在每天早上 3 点向 Cloud Build API 发出一个 POST 请求,以此启动我们的循环更新过程。


雷达卡


京公网安备 11010802022788号







