从 OpenAPI 生成 Kubernetes API Delphi 客户端
每个 Kubernetes 集群都以 OpenAPI 形式发布其 API——与 kubectl 和每个官方语言客户端使用的描述相同。将 sgcOpenAPI 指向该规范,即可生成一个类型化的 Delphi 单元,让 Pascal 应用程序通过常规 HTTPS API 列出 Pod、扩展 Deployment、观察事件和应用清单。
每个 Kubernetes 集群都以 OpenAPI 形式发布其 API——与 kubectl 和每个官方语言客户端使用的描述相同。将 sgcOpenAPI 指向该规范,即可生成一个类型化的 Delphi 单元,让 Pascal 应用程序通过常规 HTTPS API 列出 Pod、扩展 Deployment、观察事件和应用清单。
Kubernetes API 服务器在 /openapi/v2 公开自己的 OpenAPI 2.0 文档,在 /openapi/v3 公开 OpenAPI 3 文档。sgcOpenAPI 同时接受这两种格式,并将它们转换为通用内部模型。
GET https://<cluster>/openapi/v3
Bearer 令牌 / 客户端证书 / kubeconfig
sgcOpenAPI_Kubernetes
Windows、macOS、Linux、iOS、Android
每个集群都提供自己的规范,这意味着生成的客户端与该集群上安装的 API 版本、CRD 和聚合 API 完全同步。针对不同的集群重新生成以支持不同的版本。
uses sgcOpenAPI_Parser, sgcOpenAPI_Generator; var vParser: TsgcOpenAPIParser; vGen: TsgcOpenAPIGenerator; begin vParser := TsgcOpenAPIParser.Create(nil); try // Load directly from the cluster (mTLS or bearer) vParser.LoadFromURL('https://10.0.0.1:6443/openapi/v3', ['Authorization: Bearer ' + vToken]); Memo1.Lines.Add(Format('k8s spec: %d paths, %d schemas', [vParser.Paths.Count, vParser.Schemas.Count])); vGen := TsgcOpenAPIGenerator.Create(nil); try vGen.Parser := vParser; vGen.OutputUnit := 'sgcOpenAPI_Kubernetes'; vGen.OutputFolder := 'C:\Generated\k8s'; vGen.GroupBy := gbTag; vGen.Generate; finally vGen.Free; end; finally vParser.Free; end; end;
生成器为每个 Kubernetes API 组/版本发出一个类——TsgcK8s_CoreV1、TsgcK8s_AppsV1、TsgcK8s_BatchV1、TsgcK8s_NetworkingV1、TsgcK8s_StorageV1、TsgcK8s_RbacV1 等——加上顶层 TsgcKubernetes 门面。
身份验证设置完成后,只需三行代码。结果是一个类型化的 TsgcK8sPodList,其项目公开官方 API 参考中的每个容器、条件和状态字段。
uses sgcOpenAPI_Kubernetes; var vK8s: TsgcKubernetes; vPods: TsgcK8sPodList; vPod: TsgcK8sPod; begin vK8s := TsgcKubernetes.Create(nil); try vK8s.Server := 'https://10.0.0.1:6443'; vK8s.Token := vToken; vK8s.ClientCertFile := 'C:\kube\client.crt'; vK8s.ClientKeyFile := 'C:\kube\client.key'; vK8s.CACertFile := 'C:\kube\ca.crt'; vPods := vK8s.CoreV1.ListNamespacedPod( Namespace := 'production', LabelSelector := 'app=api,tier=backend'); try for vPod in vPods.Items do Memo1.Lines.Add(Format('%-30s %s node=%s', [vPod.Metadata.Name, vPod.Status.Phase, vPod.Spec.NodeName])); finally vPods.Free; end; finally vK8s.Free; end; end;
扩展 Deployment 是针对 /scale 子资源的 PATCH。观察事件是一个长期存在的 HTTP/1.1 分块 GET,生成的客户端将其公开为类型化的可枚举对象。
// Scale "api" Deployment in "production" to 5 replicas var vScale: TsgcK8sScale; begin vScale := vK8s.AppsV1.ReadNamespacedDeploymentScale( Name := 'api', Namespace := 'production'); try vScale.Spec.Replicas := 5; vK8s.AppsV1.ReplaceNamespacedDeploymentScale( Name := 'api', Namespace := 'production', Body := vScale); finally vScale.Free; end; // Watch events on Pods in the same namespace for vEvent in vK8s.CoreV1.WatchNamespacedPodList( Namespace := 'production', ResourceVersion := vPods.Metadata.ResourceVersion, TimeoutSeconds := 600) do begin Memo1.Lines.Add(Format('[%s] %s — %s', [vEvent.EventType, vEvent.&Object.Metadata.Name, vEvent.&Object.Status.Phase])); end; end;
由于规范是从集群获取的,因此该集群上安装的每个 API 组、版本和 CRD 都会出现在 Delphi 单元中。
AppsV1——Deployment、StatefulSet、DaemonSet、ReplicaSet。BatchV1——Job、CronJob。CoreV1——Pod、ReplicationController。
CoreV1——Service、Endpoint、ConfigMap、Secret。NetworkingV1——Ingress、IngressClass、NetworkPolicy。DiscoveryV1——EndpointSlice。
StorageV1——StorageClass、VolumeAttachment、CSIDriver、CSINode。CoreV1——PersistentVolume、PersistentVolumeClaim。
RbacV1——Role、RoleBinding、ClusterRole、ClusterRoleBinding。PolicyV1——PodDisruptionBudget。AdmissionRegistrationV1——ValidatingWebhookConfiguration。
集群中安装的 CRD 会自动出现。Argo Rollouts、Cert Manager Certificates、Istio VirtualServices——只要 operator 注册了 OpenAPI 模式,sgcOpenAPI 就会为其生成类型化类。
长时间运行的端点(watch=true、容器日志 follow=true)被公开为可枚举对象,一旦服务器刷新就会产生类型化事件。
大多数集群使用自签名集群 CA。通过 CACertFile 提供来自 ~/.kube/config 的 CA 包,或使用 InsecureSkipTLSVerify := True 完全禁用验证——对开发集群有用,但绝不用于生产环境。
绑定的 ServiceAccount 令牌(自 Kubernetes 1.21 起的默认值)在一小时后过期。通过从集群内重新读取 /var/run/secrets/kubernetes.io/serviceaccount/token,或从外部调用 TokenRequest API 来刷新令牌。
现代控制器更喜欢使用 Content-Type: application/apply-patch+yaml 的 Server-Side Apply。生成器会发出两种辅助方法——对传统的策略性合并补丁使用 PatchNamespacedDeployment,对 SSA 使用显式的 Apply 方法。