You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过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权限

准备工作

  1. 添加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>
  1. 权限配置
  • 本地运行:执行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注意事项

  1. 选择Java 11+运行时
  2. 编写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());
        }
    }
}
  1. 确保Cloud Function的服务账号拥有roles/run.admin权限
  2. 可配置事件触发器(如Pub/Sub、Cloud Scheduler)来自动触发状态切换

内容的提问来源于stack exchange,提问作者Dmitrii Semikin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 03:17:36