深度解析 autoscaler 内置的 Gophercloud:OpenStack Go SDK 的认证、客户端与容器集群实战指南
2026/9/16 15:36:06 网站建设 项目流程

深度解析 autoscaler 内置的 Gophercloud:OpenStack Go SDK 的认证、客户端与容器集群实战指南

【免费下载链接】autoscalerAutoscaling components for Kubernetes项目地址: https://gitcode.com/GitHub_Trending/au/autoscaler

本篇技术指南以 autoscaler 仓库中随 Magnum 云提供商 一起内置(vendor)的 Gophercloud 源码及其 README 为核心,系统讲解这个 OpenStack Go SDK 的安装方式、凭证准备、认证机制、ProviderClient / ServiceClient 双层客户端模型,以及如何调用 Compute API 创建云主机。在此基础上,我们会深入仓库源码,展示 Gophercloud 的 containerinfra 扩展包如何被 magnum_manager_impl.go 复用,实现集群节点组的自动扩缩容——读完后你将同时掌握 SDK 的基础用法与它在 Kubernetes Autoscaler 中的真实落地方式。

一、Gophercloud 是什么:为什么 autoscaler 仓库里会有一份 SDK 源码

Gophercloud 是一个用 Go 编写的 OpenStack SDK。它的设计目标是把 OpenStack 庞大的 REST API(Identity、Compute、Network、Object Storage、Container Infra 等)封装成类型安全的 Go 包,让开发者用几行代码就能完成认证、查询资源、创建虚拟机等操作,而无需直接拼接 HTTP 请求。

在 autoscaler 仓库中,Gophercloud 以 vendor 形式存放于 cluster-autoscaler/cloudprovider/magnum/gophercloud 目录,其作用是为 OpenStack Magnum 云提供商提供 OpenStack API 访问能力。从目录结构可以清晰看到本仓库裁剪后保留的子包:

  • openstack/identity/v2、v3:Keystone 认证与 Token 获取;
  • openstack/compute/v2/flavors:查询虚拟机规格(flavor);
  • openstack/containerinfra/v1/clusters、nodegroups:Magnum 容器集群与节点组管理(自动扩缩容的核心依赖);
  • openstack/orchestration/v1/stacks、stackresources:Heat 编排栈查询(用于跟踪节点组内每台服务器的创建/删除状态);
  • pagination:通用分页框架;
  • testhelper:SDK 自带测试辅助工具。

因此,阅读这份 README 不仅能学会使用 Gophercloud,还能顺带理解 Kubernetes Autoscaler 的 Magnum 扩展是怎么通过它跟 OpenStack 打交道的。

二、安装与依赖管理:GOPATH、go get 与 vendor 化

Gophercloud 官方推荐的做法是先将 GOPATH 指向一个合适的目录:

mkdir $HOME/go export GOPATH=$HOME/go

由于 Gophercloud 对上游 API 的变更比较敏感,官方建议引入依赖管理方案(如 godep)来锁定版本,防止依赖漂移:

go get github.com/gophercloud/gophercloud # Edit your code to import relevant packages from "github.com/gophercloud/gophercloud" godep save ./...

上述命令会把所需的全部源码安装进Godeps/_workspace目录,之后用godep go编译即可引用。而在 autoscaler 仓库中,Gophercloud 已经被直接内置(vendored)进cluster-autoscaler/cloudprovider/magnum/gophercloud,Magnum 云提供商通过k8s.io/autoscaler/cluster-autoscaler/cloudprovider/magnum/gophercloud/...的导入路径直接使用(见 magnum_manager_impl.go 的 import 段),无需额外执行go get,这正是"vendor 它并自己写测试覆盖所需部分"这一官方建议的落地。

三、准备凭证:OpenStack 访问凭据与 OS_* 环境变量

因为要调用 API,你首先需要拿到 OpenStack 的访问凭据,官方推荐将其保存为环境变量而不是写死在代码里,这样源码可以安全地提交到版本控制系统。最少需要以下三项:

  • username(用户名)
  • password(密码)
  • 一个有效的 Keystone identity URL(认证端点)

如果你有 OpenStack 仪表盘(Horizon),可以直接访问project/access_and_security路径,点击右上角的 "Download OpenStack RC File" 按钮下载一个 bash 文件,它会把所有访问信息导出为环境变量。然后执行:

source admin-openrc.sh

按提示输入密码即可完成环境变量注入。SDK 会读取的标准环境变量在 openstack/auth_env.go 的 AuthOptionsFromEnv 中有完整定义,主要包括:

环境变量对应字段说明
OS_AUTH_URLIdentityEndpointKeystone 认证端点,必填
OS_USERNAME/OS_USERIDUsername / UserID用户名或用户 ID,至少其一(应用凭证场景可豁免)
OS_PASSWORDPassword密码,必填(应用凭证场景可豁免)
OS_PROJECT_ID/OS_PROJECT_NAMETenantID / TenantName项目(租户)信息,v3 认证下优先使用前者;OS_TENANT_ID/OS_TENANT_NAME为已弃用的旧名称
OS_DOMAIN_ID/OS_DOMAIN_NAMEDomainID / DomainName域信息,v3 用户名认证下必填其一
OS_APPLICATION_CREDENTIAL_ID/_NAME/_SECRETApplicationCredential*应用凭证认证(替代密码的更安全方式)

从 auth_env.go 的实现可以看到 SDK 还会做一系列输入校验:缺少OS_AUTH_URL、缺少用户名/密码、应用凭证缺少 secret、只填OS_PROJECT_NAME却未提供域信息或项目 ID 等情况都会直接返回对应的ErrMissingEnvironmentVariable错误,帮助你尽早发现问题。

四、认证机制:AuthOptions、ProviderClient 与版本协商

拿到凭证后的第一步是认证,认证由底层的 Provider 结构负责。有两种方式构造认证选项:

import ( "github.com/gophercloud/gophercloud" "github.com/gophercloud/gophercloud/openstack" "github.com/gophercloud/gophercloud/openstack/utils" ) // Option 1: Pass in the values yourself opts := gophercloud.AuthOptions{ IdentityEndpoint: "https://openstack.example.com:5000/v2.0", Username: "{username}", Password: "{password}", } // Option 2: Use a utility function to retrieve all your environment variables opts, err := openstack.AuthOptionsFromEnv()

gophercloud.AuthOptions是认证选项的聚合结构,完整字段定义见 auth_options.go,除 README 用到的三个字段外,还支持UserIDDomainID/DomainName(v3 必须)、TenantID/TenantName(项目作用域)、TokenID(直接用已有 Token 认证)、Scope(限定 Token 作用到某个项目/域)、AllowReauth(允许 SDK 缓存凭证并自动重新认证)以及三个应用凭证字段。它同时实现 v2 与 v3 两种 Token 请求体的构造逻辑:ToTokenV2CreateMap组装经典的passwordCredentials结构,而ToTokenV3CreateMap(见 auth_options.go)则支持passwordtokenapplication_credential三种认证方法,并对"用户名与用户 ID 同时给出"、"密码认证但缺域信息"等冲突组合返回明确错误。

拿到opts后,调用openstack.AuthenticatedClient(opts)得到ProviderClient

provider, err := openstack.AuthenticatedClient(opts)

其内部实现(openstack/client.go 的 AuthenticatedClient)先调用NewClient解析并规范化认证端点,再调用Authenticate完成实际认证。认证阶段最关键的是身份服务版本协商Authenticate(openstack/client.go)声明了v2.0(优先级 20)与v3(优先级 30)两个候选版本,交给 utils.ChooseVersion 处理。该函数的逻辑是:

  1. 若你给的端点已带明确的版本后缀(如/v3/),直接按后缀匹配,不再探测;
  2. 否则向IdentityBase发起GET,读取服务公布的版本列表(versions.values),
  3. 在状态为currentsupportedstablegoodStatus白名单)的版本中,选择优先级最高的那个。

因此,只要你的OS_AUTH_URL不带版本后缀,SDK 会自动优先选用 Keystone v3。

认证成功后返回的ProviderClient是"顶层客户端"——所有 OpenStack 服务客户端都从它派生,它持有访问 API 所需的全部认证信息(基地址、Token ID、端点定位器等)。其结构定义见 provider_client.go,关键字段包括:

  • IdentityBase/IdentityEndpoint:身份服务根地址与端点;
  • TokenID:最近一次签发的有效 Token;
  • EndpointLocator:从服务目录(service catalog)发现各服务端点的函数;
  • HTTPClient:可替换的http.Client,用于注入自定义传输行为;
  • UserAgent:请求头中的 UA 字符串,默认值为gophercloud/2.0.0(见 provider_client.go);
  • ReauthFunc:收到 401 时自动重新认证的函数。

需要特别注意的几点实现细节:

  • Token 的线程安全访问:应用若并发使用 ProviderClient,应调用UseTokenLock()(provider_client.go),此后通过Token()/SetTokenAndAuthResult()读写 Token 都会加锁;AuthenticatedHeaders 会把 Token 放进X-Auth-Token请求头,且会先等待正在进行的重认证完成。
  • 自动重认证AllowReauth开启时,认证过程会创建一个"一次性客户端"(throwaway client,把 Token 和 ReauthFunc 清零)用于重试,ReauthFunc内通过CopyTokenFrom把新 Token 拷回主客户端(见 openstack/client.go 的 v3auth)。Request收到 401 且设置了 ReauthFunc 时会自动重认证并重放请求,但通过hasReauthenticated标志保证单次请求最多重试一次,避免死循环(provider_client.go 的 doRequest)。
  • 默认成功状态码Request未显式指定OkCodes时,按 HTTP 方法取默认值:GET→200,POST/PUT→201/202,PATCH→200/202/204,DELETE→202/204(见 defaultOkCodes),并在响应码不符合预期时返回带响应体的ErrUnexpectedResponseCode

五、服务客户端:把 Provider 注入 Compute 等具体服务

有了 Provider 之后,把它作为依赖注入到具体的 OpenStack 服务中。以 Compute API 为例,创建 Compute 服务客户端:

client, err := openstack.NewComputeV2(provider, gophercloud.EndpointOpts{ Region: os.Getenv("OS_REGION_NAME"), })

openstack.NewComputeV2 的内部实现(initClientOpts,见 openstack/client.go)会调用ProviderClient.EndpointLocator,根据认证时从服务目录中抽取的 catalog 和传入的EndpointOpts(如 Region)解析出该服务在当前区域的访问端点。本仓库的 openstack/client.go 还提供了NewIdentityV2/V3NewBareMetalV1NewNetworkV2NewBlockStorageV2/V3NewOrchestrationV1NewContainerInfraV1(Magnum 容器基础设施服务,见 openstack/client.go)等一批构造函数。

所有服务客户端都基于gophercloud.ServiceClient(service_client.go),它内嵌了*ProviderClient,并额外持有:

  • Endpoint:服务 API 基地址(来自服务目录,必须以/结尾);
  • ResourceBase:资源级基地址(可含 API 版本);
  • Type:服务类型标识(如computecontainer-infra),用于设置微版本请求头;
  • Microversion:服务微版本号;
  • MoreHeaders:作用域为整个服务客户端的额外请求头。

ServiceClient封装了Get/Post/Put/Patch/Delete/Head六个方法(service_client.go),统一处理 JSON 请求体编码、JSON 响应解码、微版本头注入(如 Compute 用X-OpenStack-Nova-API-Version,见 setMicroversionHeader),并最终委托给ProviderClient.Request执行真正的 HTTP 请求。分页数据则由 pagination.Pager 管理:AllPages()会把一个 List 操作的所有页合并成单页返回(pager.go),配合各资源包的Extract*方法即可取出结构化对象。

六、实战:用 Compute API 创建一台云主机

拿到服务客户端后,就可以执行任何 Compute API 操作了。例如创建一台新服务器,只需调用Create方法并传入 flavor ID(硬件规格)和 image ID(操作系统镜像):

import "github.com/gophercloud/gophercloud/openstack/compute/v2/servers" server, err := servers.Create(client, servers.CreateOpts{ Name: "My new server!", FlavorRef: "flavor_id", ImageRef: "image_id", }).Extract()

上述代码创建了一台带指定参数的服务器,并把新资源封装进server变量(servers.Server结构体)。这里的Create会经由ServiceClient.Post/servers端点发送请求体,Extract()负责把 JSON 响应解码为强类型的Server对象——这就是 Gophercloud "结果对象 + Extract" 的经典用法:每个 API 操作返回一个携带原始响应的Result类型,通过Extract/ExtractErr得到最终结果或错误。

七、仓库中的进阶用法:containerinfra 扩展与 Magnum 节点组自动扩缩容

README 是面向通用 OpenStack 场景的入门教程,而 autoscaler 仓库真正让 Gophercloud 发挥价值的地方,是它额外维护的 containerinfra/v1 扩展包——这正是 Magnum 容器集群管理 API 的 Go 封装。其中两个包与自动扩缩容直接相关:

nodegroups 包提供节点组的 CRUD:

  • Get:按 ID/名称获取某个集群下的节点组详情(只接受 200 成功码);
  • List:列出节点组,ListOpts支持marker/limit分页、sort_key/sort_dir排序以及按role过滤(ListOpts);
  • Create:创建节点组,CreateOpts支持NameNodeCountMinNodeCountMaxNodeCount(不设置则无上限)、Role(默认worker)、ImageIDFlavorID等字段(CreateOpts);
  • Update:通过 JSON Patch 语义(add/remove/replace)修改/min_node_count/max_node_count(UpdateOpts);
  • Delete:删除节点组。

节点组对象NodeGroup(results.go)包含NodeCountMinNodeCountMaxNodeCount(指针类型,未设置时为 nil)、RoleIsDefaultStackIDStatus等字段。注意List返回的字段是不完整的(不含 min/max 节点数),所以需要再对每个节点组单独Get一次。

clusters 包提供集群级操作,其中Resize是实现扩缩容的关键:

type ResizeOpts struct { NodeCount *int `json:"node_count" required:"true"` NodesToRemove []string `json:"nodes_to_remove,omitempty"` NodeGroup string `json:"nodegroup,omitempty"` }

(见 ResizeOpts 定义)——它允许对指定NodeGroup调整目标节点数NodeCount,并可通过NodesToRemove精确指定要删除的节点。

这些 API 在 magnum_manager_impl.go 中如何被使用:

  1. 节点组自动发现autoDiscoverNodeGroups(magnum_manager_impl.go)先用nodegroups.List分页拉取全部节点组,跳过master角色,再对每个组Get详情并校验MaxNodeCount是否已设置(未设置即不参与扩缩容),最后按自动发现配置里的角色列表做匹配。
  2. 查询当前规模nodeGroupSize(magnum_manager_impl.go)直接Get节点组并读取NodeCount
  3. 扩容updateNodeCount(magnum_manager_impl.go)构造clusters.ResizeOpts{NodeCount, NodeGroup}后调用clusters.Resize
  4. 缩容deleteNodes(magnum_manager_impl.go)把要删除的节点按 server ID(或 minion 索引,用于还在创建中/处于错误态的节点)填入NodesToRemove,连同缩减后的NodeCount一起Resize
  5. 节点状态跟踪getNodes(magnum_manager_impl.go)利用 orchestration/v1/stacks、stackresources 读取 Heat 栈的refs_map输出和 minion 资源状态,把每个 minion 映射为openstack:///<server-id>形式的 ProviderID,并区分InstanceCreating/InstanceRunning/InstanceDeleting/ 失败(quota 超限被归类为OutOfResourcesErrorClass),从而支持对"即将创建/已失败"节点做背压处理。

而 Magnum 云提供商的部署与参数(--cluster-name--nodes--node-group-auto-discovery=magnum:role=worker,autoscalingmax_node_count的 openstack CLI 设置命令等),在 Magnum 云提供商 README 中有完整说明,其中 examples 目录 提供了 ServiceAccount、Secret、Deployment 和 Helm values 等可直接参考的配置样例。

八、向后兼容性保证与注意事项

Gophercloud 官方的立场非常明确:不提供向后兼容性保证——"None. Vendor it and write tests covering the parts you use." 也就是说,升级 SDK 前必须自行评估 API 变化,通过 vendor 锁定版本,并用测试覆盖你所依赖的接口。autoscaler 仓库正是这一策略的实践者:把 Gophercloud 整个内置进cluster-autoscaler/cloudprovider/magnum/gophercloud,由仓库自身维护版本;SDK 内部也自带了 testhelper 与各包下的测试代码(如 nodegroups、clusters 的 fixtures),便于在改动后进行验证。

九、延伸阅读

  • 继续阅读同目录下的 CHANGELOG.md 了解该内置版本的演进记录,LICENSE 查看许可条款;
  • 想了解 Gophercloud 在真实扩缩容场景中的完整调用链,可精读 magnum_manager_impl.go 与 Magnum 云提供商 README;
  • 需要为 OpenStack 之外的云(AWS、Azure、GCE、阿里云、华为云等)编写类似扩缩容逻辑时,可对照 cloudprovider 目录 下的其他云提供商实现,体会不同 SDK 在"认证 → 服务客户端 → 节点组抽象"三层结构上的共性设计。

【免费下载链接】autoscalerAutoscaling components for Kubernetes项目地址: https://gitcode.com/GitHub_Trending/au/autoscaler

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询