GCP Go开发:如何获取资源实例对应SKU以查询其定价
实现方案
GCP 资源的 SKU 不需要资源结构体自带字段返回,可以通过资源所属服务标识+资源属性+地域/可用区三个维度组合,调用 Cloud Billing API 匹配得到对应 SKU,具体实现步骤如下:
步骤1:确定资源所属的 Billing 服务ID
不同类别的 GCP 资源对应固定的 Billing 服务父级ID,例如所有计算引擎类资源(虚拟机、云硬盘等)的服务ID为 services/6F81-5844-456A,你现有代码中Parent字段填写的services/<SKU>是错误的,需要替换为对应资源的服务ID。
步骤2:从资源实例提取匹配所需的关键属性
以你提到的computepb.Disk为例,只需要从结构体中提取以下几个字段即可完成SKU匹配:
Type:从返回的磁盘类型完整URL中解析出短标识,比如pd-ssd/pd-standard/pd-balancedZone/Region:解析出资源所属的区域,比如可用区us-central1-a对应的区域为us-central1ReplicaZones:判断该磁盘是否为区域级冗余磁盘
步骤3:调用 ListSkus 接口传入过滤条件匹配SKU
调用接口时通过Filter参数缩小SKU范围,不需要拉取全量SKU再遍历,性能更高。
完整实现代码示例
package main import ( "context" "fmt" "strings" billing "cloud.google.com/go/billing/apiv1" billingpb "google.golang.org/genproto/googleapis/cloud/billing/v1" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) // GetDiskSku 输入云硬盘实例,返回对应匹配的SKU func GetDiskSku(ctx context.Context, disk *computepb.Disk) (*billingpb.Sku, error) { client, err := billing.NewCloudCatalogClient(ctx) if err != nil { return nil, err } defer client.Close() // 提取磁盘类型短标识 diskType := disk.GetType() segments := strings.Split(diskType, "/") diskTypeShort := segments[len(segments)-1] // 提取资源所属区域 zone := disk.GetZone() zoneSegments := strings.Split(zone, "/") zoneName := zoneSegments[len(zoneSegments)-1] region := zoneName[:strings.LastIndex(zoneName, "-")] // 构造过滤条件 var filterBuilder strings.Builder filterBuilder.WriteString("category.serviceDisplayName = \"Compute Engine\" AND category.resourceFamily = \"Storage\" AND ") // 判断是否为区域级磁盘 if disk.GetReplicaZones() != nil && len(disk.GetReplicaZones()) > 0 { filterBuilder.WriteString("description: \"Regional\" AND ") } // 匹配磁盘类型 switch diskTypeShort { case "pd-ssd": filterBuilder.WriteString("description: \"PD SSD\"") case "pd-standard": filterBuilder.WriteString("description: \"PD Standard\"") case "pd-balanced": filterBuilder.WriteString("description: \"PD Balanced\"") } // 匹配区域 filterBuilder.WriteString(fmt.Sprintf(" AND geoRegions: %s", region)) req := &billingpb.ListSkusRequest{ Parent: "services/6F81-5844-456A", Filter: filterBuilder.String(), } it := client.ListSkus(ctx, req) for { sku, err := it.Next() if err != nil { break } // 可在此处添加额外匹配逻辑保证唯一命中 return sku, nil } return nil, fmt.Errorf("未找到匹配的SKU") }
注意事项
- 建议对匹配得到的SKU做本地缓存,SKU更新频率极低,无需每次查询都调用Cloud Billing API,可大幅降低请求耗时
- 其他类型的GCP资源(虚拟机、负载均衡等)都可以参考这个逻辑,调整过滤条件和提取的属性即可实现SKU匹配
内容的提问来源于stack exchange,提问作者Ari
相关产品推荐
相关产品推荐

