+86 189 8218 1436 周一至五 10:00-22:00

Cloud Run 是什么:新手入门

TL;DR:用小白能懂的话说明 Cloud Run 是什么、能省哪些运维事、如何部署,并对比常见替代方案与最佳实践。

它是什么

你可以把 Cloud Run 想象成一个「自动餐厅」:你只需要把做好的菜(容器镜像)交给它,它就会帮你端上桌,变成一个谁都能访问的 https:// 网址。这就是「把容器镜像变成可访问的 HTTPS 服务」的意思,证书和域名平台都帮你配好了。

它是 Google Cloud(GCP)的全托管无服务器容器运行平台。说人话就是:你不用自己创建 VM、装 Linux、配 Nginx/Apache,也不用维护 Kubernetes 集群。这些「脏活」平台全包了——自动启动容器、按访问量扩容缩容、没人访问就缩到零、底层系统补丁也由 Google 打。你只负责写业务代码并打包成镜像,按实际用到的计算时间付钱。

它最适合跑这些「来了请求就干活、干完就歇着」的轻量服务:

  • 网站后端接口、REST / GraphQL API
  • 接收第三方回调的 Webhook(支付通知、GitHub 推送等)
  • 由定时任务(Cloud Scheduler)触发的脚本服务
  • 轻量后台接口、小工具、数据清洗接口

想直观感受一下,可以直接复制这条命令,用 Google 官方示例镜像部署一个服务:

gcloud run deploy hello-service 
  --image gcr.io/cloudrun/hello 
  --platform managed 
  --region asia-east1 
  --allow-unauthenticated

为什么这么写:--image 告诉平台用哪个已打包好的镜像;--platform managed 选全托管模式,才不用自己管机器;--region asia-east1 选离用户近的台湾机房,延迟更低;--allow-unauthenticated 允许公网直接访问,不加这条会返回 403。执行完终端会打印一个 https://xxx.run.app 链接,点开就能看到页面,整个过程不用碰任何一台服务器。

小白最容易踩的坑:

  • 容器里的程序必须监听环境变量 PORT(默认 8080),千万别写死 80 或 3000,否则健康检查过不了、部署一直失败。
  • 第一次用先执行 gcloud auth login 和 gcloud config set project 你的项目ID,不然会报「未登录」或「未设置项目」。
  • 别在启动时跑几分钟的初始化,启动太慢请求会超时;缩容到零后首次访问有「冷启动」延迟,特别在意速度就设最小实例数。

解决什么问题

把 Cloud Run 是什麼讲成人话:它是「按请求开门的柜台」。传统 VM 要长期开机、打补丁、配防火墙、盯负载,涨流量还得加机器;Cloud Run 把这些底层工作交给 GCP,你给容器镜像或源代码,平台管机器、入口、证书和扩缩容。

最直观是省钱:流量波动时按请求自动扩容,没有请求时可缩到零,小网站、API、Webhook、活动页等常见场景更省钱,不用为空转 VM 付费。坑是缩到零后第一次访问会冷启动,等几秒不是故障;持续高负载、SSH、常驻进程或长连接不一定适合,也要另算价。

上线也少搭发布系统:内置版本管理,每次部署留下一个版本,流量分配可 100% 切新版或 10%/90% 灰度;服务页自带日志和监控入口。回滚别删服务,在「版本、流量」切回旧版本,小白第一次上线和回滚都不慌。

先别传自己的代码。装好 Google Cloud CLI、有已启用结算的 GCP 项目后,复制整段:前两条登录选项目,中间启用服务、部署官方示例、打印网址,后面列版本、看日志、切流量。问默认区域按提示跳过或选 asia-east1,命令里已指定区域。

gcloud auth login
gcloud init
gcloud services enable run.googleapis.com cloudbuild.googleapis.com logging.googleapis.com monitoring.googleapis.com
gcloud run deploy hello-run 
  --image=gcr.io/cloudrun/hello 
  --region=asia-east1 
  --platform=managed 
  --allow-unauthenticated
gcloud run services describe hello-run --region=asia-east1 --format='value(status.url)'
gcloud run revisions list --service=hello-run --region=asia-east1
gcloud logging read 'resource.type="cloud_run_revision" AND resource.labels.service_name="hello-run"' --limit=20 --format='table(timestamp, severity, textPayload, httpRequest.requestUrl)'
gcloud run services update-traffic hello-run --region=asia-east1 --to-latest

为什么先这样?API 没启用就像柜台没开门;官方示例能先排掉项目、权限、账单、区域问题,看到网址后再换镜像,排错更简单。

  • 坑:没开账单、选错项目或切错区域,会报权限错或以为服务消失;登录时看清项目名,本文固定 asia-east1。
  • 坑:公开访问参数等于网址谁都能开;内部接口别保留,先配 IAM。
  • 坑:GCP 只管基础设施补丁,镜像依赖、框架、密钥仍要自己管;日志空时先确认有请求。

怎么上手

先别急着部署。Cloud Run 启动容器时会注入 PORT,程序要读它并监听 0.0.0.0;Node 用 process.env.PORT,Python 用 os.environ["PORT"]。小白最常踩的坑,是本地写死 3000/8080 或只监听 127.0.0.1,云端就会启动失败。不想自己打镜像,也可把源码交给 Cloud Build 自动构建。

按官网装好 Google Cloud CLI,终端能运行 gcloud 即可。下面命令会登录、选项目并开 API:Cloud Run 跑服务,Artifact Registry 存镜像,Cloud Build 构建源码。看清输出的项目 ID,别把资源开到旧项目。

gcloud auth login
gcloud init
gcloud config get-value project
gcloud services enable run.googleapis.com artifactregistry.googleapis.com cloudbuild.googleapis.com

控制台可进 Cloud Run → 创建服务:测试时填示例镜像 us-docker.pkg.dev/cloudrun/container/hello,或选“从源代码部署”让 Cloud Build 构建;选区域、服务名,先勾“允许未身份验证的调用”,完成会给 HTTPS 地址。命令行二选一更省事:

REGION="asia-east1"
SERVICE_NAME="hello-run"
IMAGE="us-docker.pkg.dev/cloudrun/container/hello"
gcloud run deploy "$SERVICE_NAME" 
  --image "$IMAGE" 
  --region "$REGION" 
  --platform managed 
  --allow-unauthenticated 
  --quiet

若走源码构建,先切到代码目录,只执行这条,别和上一条重复;没 Dockerfile 时 Cloud Build 会按语言猜,猜错就补 Dockerfile。

REGION="asia-east1"
SERVICE_NAME="hello-run"
gcloud run deploy "$SERVICE_NAME" 
  --source . 
  --region "$REGION" 
  --platform managed 
  --allow-unauthenticated 
  --quiet

先用测试服务验证访问,别急着接数据库。下面命令会取出部署后的 HTTPS 地址并请求一次;若前面改过区域或服务名,这里要改成一样。

REGION="asia-east1"
SERVICE_NAME="hello-run"
SERVICE_URL="$(gcloud run services describe "$SERVICE_NAME" --region "$REGION" --format='value(status.url)')"
curl "$SERVICE_URL"

看到欢迎页后再逐步加:先关掉公开访问并配身份验证;普通配置用环境变量,密码和 API Key 用 Secret Manager,别写进代码;并发、超时按真实请求慢慢调。改动会生成新修订版本,不是改一台常开服务器。

与替代方案对比

理解 Cloud Run 是什么,先记一句:VM 给机器,App Engine 给应用托管规则,Cloud Functions 给事件小代码,GKE 给 Kubernetes 集群;Cloud Run 是「给容器,就帮你跑成 Web 服务」。

  • 对比 VM:VM 控制力最强,能装系统、开长期进程、SSH 改配置,适合长期进程和自定义系统;但补丁、监控、扩容都要管。Cloud Run 更省运维,适合无状态服务。
  • 对比 App Engine:App Engine 更偏应用托管,省事但运行时、依赖受平台范围影响;Cloud Run 允许自带容器,语言和系统库都能打进镜像,依赖更自由。
  • 对比 Cloud Functions:Cloud Functions 适合「上传图片后生成缩略图」这类小段事件代码;Cloud Run 适合完整 Web 服务、API 或容器化应用,有稳定网址和路由。
  • 对比 GKE:GKE 适合复杂微服务和集群治理,但节点、Pod、Ingress 概念多;Cloud Run 适合快速上线、少管基础设施。

为什么动手跑一次?只看文字很难感受差别。打开控制台右上角 Cloud Shell,它已登录,不用装软件。复制第一段,按提示输入项目 ID;先启用 API、固定区域,是为了少踩「服务没开」「没选区域」的错。

read -r -p "请输入 Google Cloud 项目 ID: " PROJECT_ID
gcloud config set project "$PROJECT_ID"
gcloud services enable run.googleapis.com artifactregistry.googleapis.com
gcloud config set run/region asia-east1

再用官方示例镜像部署最小服务。先不写 Dockerfile,是为了抓住重点:Cloud Run 只关心容器能否监听端口,不关心你有没有先建服务器。输出网址后能打开页面,就代表上线成功。

gcloud run deploy hello-compare 
  --image us-docker.pkg.dev/cloudrun/container/hello 
  --platform managed 
  --region asia-east1 
  --allow-unauthenticated
gcloud run services describe hello-compare 
  --region asia-east1 
  --format='value(status.url)'

常见坑:项目 ID 不是项目名,在控制台首页复制;--allow-unauthenticated 会让任何人访问,练习可以,生产要收紧;别当 VM 用,不能 SSH 改文件,上传文件也别永久写本地,应放 Cloud Storage 或数据库;自己的容器要监听 PORT 并绑定 0.0.0.0;请求少时可能缩到 0,首次访问有冷启动。练完删掉,避免忘记:

gcloud run services delete hello-compare --region asia-east1 --quiet

最佳实践

Cloud Run 会随时扩缩、换机器,服务尽量无状态:文件放 Cloud Storage,会话放缓存或数据库,别写容器本地 /tmp。否则实例一回收,数据就“没了”,这是小白最常踩的坑。

权限按“够用就好”给:下面只给专用服务账号一个存储桶、一个密钥的读取权;密码由 Secret Manager 注入成 DB_PASSWORD,绝不写进镜像、代码或 Dockerfile。执行时盲输一次密码,不回显,别回车留空,也别贴进命令历史。

第一次部署整段复制,把 你的项目ID 换成自己的;示例镜像是官方 gcr.io/cloudrun/hello,换成自己的镜像地址即可。桶名全球唯一,报已存在就改后缀。--allow-unauthenticated 适合公开站,内部服务请去掉并另给调用者 Cloud Run Invoker。

export PROJECT_ID="你的项目ID"
export REGION="asia-east1"
export SERVICE="hello-run"
export SA_NAME="${SERVICE}-sa"
export BUCKET="${PROJECT_ID}-hello-run-files"
export IMAGE="gcr.io/cloudrun/hello"

gcloud config set project "$PROJECT_ID"
gcloud services enable run.googleapis.com storage-api.googleapis.com secretmanager.googleapis.com logging.googleapis.com monitoring.googleapis.com

gcloud iam service-accounts create "$SA_NAME" --display-name="Cloud Run least privilege SA" || true
export SA_EMAIL="${SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com"

export USER_EMAIL="$(gcloud config get-value account 2>/dev/null)"
case "$USER_EMAIL" in
  *.gserviceaccount.com) MEMBER="serviceAccount:${USER_EMAIL}" ;;
  *) MEMBER="user:${USER_EMAIL}" ;;
esac
gcloud iam service-accounts add-iam-policy-binding "$SA_EMAIL" 
  --member="$MEMBER" --role="roles/iam.serviceAccountUser" || true

gcloud storage buckets create "gs://${BUCKET}" --location="$REGION" || true
gcloud storage buckets add-iam-policy-binding "gs://${BUCKET}" 
  --member="serviceAccount:${SA_EMAIL}" --role="roles/storage.objectUser"

read -r -s -p "输入数据库密码(不会显示):" DB_PASS; echo
if gcloud secrets describe db-password >/dev/null 2>&1; then
  printf '%s' "$DB_PASS" | gcloud secrets versions add db-password --data-file=-
else
  printf '%s' "$DB_PASS" | gcloud secrets create db-password --data-file=-
fi
unset DB_PASS
gcloud secrets add-iam-policy-binding db-password 
  --member="serviceAccount:${SA_EMAIL}" --role="roles/secretmanager.secretAccessor"

gcloud logging metrics create cloud_run_error_rate 
  --description="Cloud Run ERROR 日志数" 
  --log-filter='resource.type="cloud_run_revision" AND severity>=ERROR' || true

export NOTIFY_EMAIL="$(gcloud config get-value account)"
gcloud alpha monitoring channels create --channel-from-file=- <<EOF || true
type: email
displayName: "Cloud Run 告警邮箱"
labels:
  email_address: "${NOTIFY_EMAIL}"
EOF
export CHANNEL_ID="$(gcloud alpha monitoring channels list 
  --filter='displayName="Cloud Run 告警邮箱"' --format='value(name)' | head -n1)"
gcloud alpha monitoring policies create --policy-from-file=- <<EOF || true
displayName: "Cloud Run 错误日志告警"
conditions:
- displayName: "出现 ERROR 日志"
  conditionThreshold:
    filter: 'metric.type="logging.googleapis.com/user/cloud_run_error_rate" AND resource.type="cloud_run_revision"'
    comparison: COMPARISON_GT
    thresholdValue: 0
    duration: 300s
    aggregations:
    - alignmentPeriod: 60s
      perSeriesAligner: ALIGN_RATE
notificationChannels:
- "${CHANNEL_ID}"
EOF

gcloud run deploy "$SERVICE" --image "$IMAGE" --region "$REGION" 
  --service-account "$SA_EMAIL" --set-secrets="DB_PASSWORD=db-password:latest" 
  --min-instances=1 --concurrency=80 --memory=512Mi --cpu=1 --timeout=60s 
  --allow-unauthenticated --quiet

--min-instances=1 留热实例减冷启动,但一直计费,练手可改 0;--concurrency=80 太高会压垮数据库;512Mi / 1 CPU / 60s 是起步值,超时太大,卡住会白占资源。日志默认收 stdout/stderr,上面也开了日志、监控 API,建了 ERROR 指标和邮件告警,记得去邮箱确认订阅。

发新版别一把梭。接着同一终端执行(变量已重设):先 --no-traffic 部署,再只切 5% 流量,剩下 95% 自动留在旧版。

export REGION="asia-east1"
export SERVICE="hello-run"
export PROJECT_ID="$(gcloud config get-value project)"
export SA_NAME="${SERVICE}-sa"
export SA_EMAIL="${SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com"
export IMAGE="gcr.io/cloudrun/hello"

gcloud run deploy "$SERVICE" --image "$IMAGE" --region "$REGION" 
  --service-account "$SA_EMAIL" --set-secrets="DB_PASSWORD=db-password:latest" 
  --min-instances=1 --concurrency=80 --memory=512Mi --cpu=1 --timeout=60s 
  --no-traffic --quiet

export NEW_REV="$(gcloud run revisions list --service "$SERVICE" --region "$REGION" 
  --sort-by='~metadata.creationTimestamp' --limit=1 --format='value(metadata.name)')"

gcloud run services update-traffic "$SERVICE" --region "$REGION" 
  --to-revisions="${NEW_REV}=5" --quiet

去「Cloud Run → 日志 / 指标」看 5xx、ERROR、延迟,并看告警邮件。确认无误再全量;有问题先别执行最后一行,在控制台切回旧修订版,别急着删服务。

export REGION="asia-east1"; export SERVICE="hello-run"
gcloud run services update-traffic "$SERVICE" --region "$REGION" --to-latest --quiet

常见问题(FAQ)

Cloud Run 是什么,适合小白吗?

适合。只要会打包简单容器或用源码构建,就能快速上线一个 HTTPS 服务。

Cloud Run 可以一直运行后台任务吗?

不建议用服务常驻后台;长任务可考虑 Cloud Run 任务、批处理、VM 或 GKE。

没有流量时还会收费吗?

通常可缩到零,主要按使用量计费;若设置最小实例,会产生持续费用。

Cloud Run 能连数据库吗?

可以,但要配置网络、账号和连接池,避免每次请求都新建连接。

不想自己折腾 GCP?我们提供云平台代维护、上云迁移与账单代付服务,一对一技术支持。

查看代维服务 →

发表评论