如何通过Java API切换Google Cloud Run服务的公私有状态
编程切换Google Cloud Run服务公/私有状态(Java API实现)
核心原理
Cloud Run没有直接禁用服务流量的接口,通过IAM权限控制实现等效效果:
Cloud Run不提供直接停止服务流量的方式,但可通过撤销调用服务的身份权限实现类似效果。若服务为“公开”状态,需从Cloud Run Invoker角色(roles/run.invoker)中移除allUsers。
简单来说:
- 设为私有:移除
allUsers主体的roles/run.invoker权限 - 设为公开:给
allUsers主体添加roles/run.invoker权限
准备工作
- 添加Java客户端依赖
在Maven项目的pom.xml中引入Cloud Run IAM相关依赖:
<dependencies> <dependency> <groupId>com.google.cloud</groupId> <artifactId>google-cloud-run</artifactId> <version>2.3.0</version> <!-- 请使用最新稳定版 --> </dependency> <dependency> <groupId>com.google.auth</groupId> <artifactId>google-auth-library-oauth2-http</artifactId> <version>1.19.0</version> </dependency> </dependencies>
- 权限配置
- 本地运行:执行
gcloud auth application-default login完成账号认证,确保账号拥有roles/run.admin权限(Cloud Run管理员) - Cloud Function部署:使用默认服务账号时,需为其添加
roles/run.admin权限;或自定义服务账号并配置该权限
核心代码示例
以下是封装好的工具类,包含切换公私状态的核心逻辑:
import com.google.cloud.run.v2.RunClient; import com.google.cloud.run.v2.ServiceName; import com.google.iam.v1.Binding; import com.google.iam.v1.GetIamPolicyRequest; import com.google.iam.v1.Policy; import com.google.iam.v1.SetIamPolicyRequest; import com.google.protobuf.FieldMask; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class CloudRunIamManager { private static final String RUN_INVOKER_ROLE = "roles/run.invoker"; private static final String ALL_USERS_PRINCIPAL = "allUsers"; // 将Cloud Run服务设为私有(移除allUsers的调用权限) public static void setServicePrivate(String projectId, String region, String serviceId) throws IOException { try (RunClient client = RunClient.create()) { ServiceName serviceName = ServiceName.of(projectId, region, serviceId); // 获取当前IAM策略 Policy currentPolicy = client.getIamPolicy(GetIamPolicyRequest.newBuilder() .setResource(serviceName.toString()) .build()); // 过滤掉包含allUsers的run.invoker绑定 List<Binding> updatedBindings = new ArrayList<>(); for (Binding binding : currentPolicy.getBindingsList()) { if (!binding.getRole().equals(RUN_INVOKER_ROLE) || !binding.getMembersList().contains(ALL_USERS_PRINCIPAL)) { updatedBindings.add(binding); } } // 更新IAM策略 Policy updatedPolicy = Policy.newBuilder(currentPolicy) .clearBindings() .addAllBindings(updatedBindings) .build(); client.setIamPolicy(SetIamPolicyRequest.newBuilder() .setResource(serviceName.toString()) .setPolicy(updatedPolicy) .setUpdateMask(FieldMask.newBuilder().addPaths("bindings").build()) .build()); } } // 将Cloud Run服务设为公开(添加allUsers的调用权限) public static void setServicePublic(String projectId, String region, String serviceId) throws IOException { try (RunClient client = RunClient.create()) { ServiceName serviceName = ServiceName.of(projectId, region, serviceId); // 获取当前IAM策略 Policy currentPolicy = client.getIamPolicy(GetIamPolicyRequest.newBuilder() .setResource(serviceName.toString()) .build()); boolean hasInvokerBinding = false; List<Binding> updatedBindings = new ArrayList<>(); for (Binding binding : currentPolicy.getBindingsList()) { if (binding.getRole().equals(RUN_INVOKER_ROLE)) { hasInvokerBinding = true; // 如果已有该绑定,添加allUsers成员 Binding updatedBinding = Binding.newBuilder(binding) .addMembers(ALL_USERS_PRINCIPAL) .build(); updatedBindings.add(updatedBinding); } else { updatedBindings.add(binding); } } // 如果没有run.invoker绑定,新建一个并添加allUsers if (!hasInvokerBinding) { Binding newBinding = Binding.newBuilder() .setRole(RUN_INVOKER_ROLE) .addMembers(ALL_USERS_PRINCIPAL) .build(); updatedBindings.add(newBinding); } // 更新IAM策略 Policy updatedPolicy = Policy.newBuilder(currentPolicy) .clearBindings() .addAllBindings(updatedBindings) .build(); client.setIamPolicy(SetIamPolicyRequest.newBuilder() .setResource(serviceName.toString()) .setPolicy(updatedPolicy) .setUpdateMask(FieldMask.newBuilder().addPaths("bindings").build()) .build()); } } // 本地测试入口 public static void main(String[] args) throws IOException { String projectId = "your-project-id"; String region = "us-central1"; String serviceId = "your-run-service-id"; // 切换为私有 setServicePrivate(projectId, region, serviceId); // 切换为公开 // setServicePublic(projectId, region, serviceId); } }
部署到Cloud Function注意事项
- 选择Java 11+运行时
- 编写Cloud Function入口函数,例如:
import com.google.cloud.functions.HttpFunction; import com.google.cloud.functions.HttpRequest; import com.google.cloud.functions.HttpResponse; import java.io.IOException; import java.io.PrintWriter; public class ToggleRunService implements HttpFunction { @Override public void service(HttpRequest request, HttpResponse response) throws IOException { String projectId = "your-project-id"; String region = "us-central1"; String serviceId = "your-run-service-id"; String action = request.getFirstQueryParameter("action").orElse("private"); PrintWriter writer = response.getWriter(); try { if ("public".equals(action)) { CloudRunIamManager.setServicePublic(projectId, region, serviceId); writer.write("Service set to public successfully"); } else { CloudRunIamManager.setServicePrivate(projectId, region, serviceId); writer.write("Service set to private successfully"); } } catch (Exception e) { response.setStatusCode(500); writer.write("Error: " + e.getMessage()); } } }
- 确保Cloud Function的服务账号拥有
roles/run.admin权限 - 可配置事件触发器(如Pub/Sub、Cloud Scheduler)来自动触发状态切换
内容的提问来源于stack exchange,提问作者Dmitrii Semikin
相关产品推荐
相关产品推荐

