用于通过基于 SwiftNIO 和 AysncHTTPClient 的流畅 DSL 与 Kubernetes 集群通信的 Swift 客户端。
/scale
API/status
API1.24.10 | 1.26.4 | 1.28.0 | 1.28.3 | 1.29.6 | 1.32.0 | |
---|---|---|---|---|---|---|
0.14.x |
✓ | - | - | - | - | - |
0.15.x |
- | ✓ | - | - | - | - |
0.16.x |
- | - | ✓ | - | - | - |
0.17.x |
- | - | - | ✓ | - | - |
0.18.x |
- | - | - | - | ✓ | - |
0.19.x |
- | - | - | - | - | ✓ |
✓
客户端和 Kubernetes 版本中 API 对象的精确匹配。-
API 对象不匹配,原因是旧 API 的移除或新 API 的添加。但是,客户端和 Kubernetes 之间共有的所有内容都将正常工作。使用 Swiftkube
工具的具体示例位于 Swiftkube:Examples 仓库中。
要创建客户端,只需导入 SwiftkubeClient
并初始化一个实例。
import SwiftkubeClient
let client = try KubernetesClient()
当您完成使用 KubernetesClient
实例后,应将其关闭,这也会关闭底层的 HTTPClient
。因此,在所有请求完成之前,您不应调用 client.syncShutdown()
。您还可以在 async/await 上下文中或通过为完成回调提供 DispatchQueue
来异步关闭客户端。
// when finished close the client
try client.syncShutdown()
// async/await
try await client.shutdown()
// DispatchQueue
let queue: DispatchQueue = ...
client.shutdown(queue: queue) { (error: Error?) in
print(error)
}
客户端尝试从以下不同来源自动解析 kube config
配置
$HOME/.kube/config
目录中的 Kube config 文件/var/run/secrets/kubernetes.io/serviceaccount/token
的 ServiceAccount
令牌和已挂载的 CA 证书,或者,可以手动配置,例如
let caCert = try NIOSSLCertificate.fromPEMFile(caFile)
let authentication = KubernetesClientAuthentication.basicAuth(
username: "admin",
password: "admin"
)
let config = KubernetesClientConfig(
masterURL: "https://kubernetesmaster",
namespace: "default",
authentication: authentication,
trustRoots: NIOSSLTrustRoots.certificates(caCert),
insecureSkipTLSVerify: false,
timeout: HTTPClient.Configuration.Timeout.init(connect: .seconds(1), read: .seconds(10)),
redirectConfiguration: HTTPClient.Configuration.RedirectConfiguration.follow(max: 5, allowCycles: false)
)
let client = KubernetesClient(config: config)
支持以下身份验证方案
.basicAuth(username: String, password: String)
.bearer(token: String)
.x509(clientCertificate: NIOSSLCertificate, clientKey: NIOSSLPrivateKey)
SwiftkubeClient
定义了用于处理 Kubernetes 资源的便捷 API。对于所有资源,使用此 DSL 都是相同的。
客户端使用新的 Swift 并发模型公开异步函数。
let namespaces = try await client.namespaces.list()
let deployments = try await client.appsV1.deployments.list(in: .allNamespaces)
let roles = try await client.rbacV1.roles.list(in: .namespace("ns"))
您可以使用 ListOptions
过滤列出的资源或限制返回的列表大小
let deployments = try await client.appsV1.deployments.list(in: .allNamespaces, options: [
.labelSelector(.eq(["app": "nginx"])),
.labelSelector(.notIn(["env": ["dev", "staging"]])),
.labelSelector(.exists(["app", "env"])),
.fieldSelector(.eq(["status.phase": "Running"])),
.resourceVersion("9001"),
.limit(20),
.timeoutSeconds(10)
])
let namespace = try await client.namespaces.get(name: "ns")
let deployment = try await client.appsV1.deployments.get(in: .namespace("ns"), name: "nginx")
let roles = try await client.rbacV1.roles.get(in: .namespace("ns"), name: "role")
您还可以提供以下 ReadOptions
let deployments = try await client.appsV1.deployments.get(in: .allNamespaces, options: [
.pretty(true),
.exact(false),
.export(true)
])
try await client.namespaces.delete(name: "ns")
try await client.appsV1.deployments.delete(in: .namespace("ns"), name: "nginx")
try await client.rbacV1.roles.delete(in: .namespace("ns"), name: "role")
您可以传递 meta.v1.DeleteOptions
的实例来控制删除操作的行为
let deletOptions = meta.v1.DeleteOptions(
gracePeriodSeconds: 10,
propagationPolicy: "Foreground"
)
try await client.pods.delete(in: .namespace("ns"), name: "nginx", options: deleteOptions)
可以直接创建/更新资源,也可以通过 SwiftkubeModel 中定义的便捷构建器创建/更新资源
// Create a resource instance and post it
let configMap = core.v1.ConfigMap(
metadata: meta.v1.ObjectMeta(name: "test"),
data: ["foo": "bar"]
)
try cm = try await client.configMaps.create(inNamespace: .default, configMap)
// Or inline via a builder
let pod = try await client.pods.create(inNamespace: .default) {
sk.pod {
$0.metadata = sk.metadata(name: "nginx")
$0.spec = sk.podSpec {
$0.containers = [
sk.container(name: "nginx") {
$0.image = "nginx"
}
]
}
}
}
您可以通过 watch
API 监视有关特定对象的 Kubernetes 事件。
监视资源会打开与 API 服务器的持久连接。该连接由 SwiftkubeClientTask
实例表示,该实例充当事件流的活动“订阅”。
必须通过 SwiftkubeClientTask/start()
显式启动任务实例,该实例返回一个 AsyncThrowingStream
,它会在从 Kubernetes API 服务器接收到项目后立即开始产生项目。
如果没有活动的消费者,异步流会缓冲其结果。使用
AsyncThrowingStream.BufferingPolicy.unbounded
缓冲策略,应考虑到这一点。
let task: SwiftkubeClientTask = client.pods.watch(in: .allNamespaces)
let stream = await task.start()
for try await event in stream {
print(event)
}
您还可以传递 ListOptions
来过滤,即选择所需的对象
let options = [
.labelSelector(.eq(["app": "nginx"])),
.labelSelector(.exists(["env"]))
]
let task = client.pods.watch(in: .default, options: options)
客户端会自动重新连接并在遇到不可恢复的错误时重新启动 watch。重新连接行为可以通过传递 RetryStrategy
的实例来控制。
默认策略是 10 次重试尝试,每次尝试之间固定延迟 5 秒。初始延迟为一秒。应用 0.2 秒的抖动。
传递 RetryStrategy.never
将禁用任何重新连接尝试。
let strategy = RetryStrategy(
policy: .maxAttemtps(20),
backoff: .exponentiaBackoff(maxDelay: 60, multiplier: 2.0),
initialDelay = 5.0,
jitter = 0.2
)
let task = client.pods.watch(in: .default, retryStrategy: strategy)
for try await event in await task.stream() {
print(event)
}
当不再需要任务时,必须取消任务
task.cancel()
follow
API 类似于 watch
,但它发出的是日志行而不是事件。
follow
模式下,客户端不会在错误时重新连接。
let task = client.pods.follow(in: .default, name: "nginx", container: "app")
for try await line in task.start() {
print(line)
}
// The task can be cancelled later to stop following logs
task.cancel()
客户端为 API 服务器提供了一个 discovery 接口,可用于检索服务器版本、API 组和特定组版本的 API 资源。
let version: Info = try await client.discovery.serverVersion()
let groups: meta.v1.APIGroupList = try await client.discovery.serverGroups()
let resources: meta.v1.APIResourceList = try await client.discovery.serverResources(forGroupVersion: "apps/v1")
可以从文件或 URL 加载资源
// Load from URL, e.g. a file
let url = URL(fileURLWithPath: "/path/to/manifest.yaml")
let deployment = try apps.v1.Deployment.load(contentsOf: url)
通常,在使用 Kubernetes 时,资源的具体类型是未知的或不相关的,例如,从 YAML 清单文件创建资源时。有时,必须在运行时根据资源的字符串表示形式派生资源的类型或种类。
利用 SwiftkubeModel
的类型擦除资源实现 UnstructuredResource
及其对应的 List-Type UnstructuredResourceList
,可以拥有一个通用客户端实例,该实例必须使用 GroupVersionResource
类型进行初始化
guard let gvr = try? GroupVersionResource(for: "deployment") else {
// handle this
}
// Get by name
let resource: UnstructuredResource = try await client.for(gvr: gvr).get(in: .default , name: "nginx")
// List all
let resources: UnstructuredResourceList = try await client.for(gvr: gvr).list(in: .allNamespaces)
可以从以下项初始化 GroupVersionKind
& GroupVersionResource
KubernetesAPIResource
实例KubernetesAPIResource
类型let deployment = ..
let gvk = GroupVersionKind(of: deployment)
let gvr = GroupVersionResource(of: deployment)
let gvk = GroupVersionKind(of: apps.v1.Deployment.self)
let gvr = GroupVersionResource(for: "configmaps")
let gvk = GroupVersionKind(for: "cm")
let gvr = GroupVersionResource(for: "cm")
// etc.
SwiftkubeClient
原生支持自定义资源定义 (CRD)。例如,可以从 YAML 文件加载 CRD 清单或以编程方式创建 CRD 清单,然后通过客户端 DSL 创建。
let crd = apiextensions.v1.CustomResourceDefinition.load(contentsOf: URL(filePath: "/path/to/crd.yaml"))
try await client.apiExtensionsV1.customResourceDefinitions.create(crd)
现在可以“扩展” KubernetesClient
,以便管理自定义资源。一种方法是使用上一节中描述的 UnstructuredResource
,并给定一些 GroupVersionResource
。
但是,客户端可以与任何实现相关标记协议的对象一起使用,这允许定义和直接使用自定义类型。
这是一个完整的示例以进行说明。
给定以下 CRD
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: crontabs.example.com
spec:
group: example.com
names:
plural: crontabs
singular: crontab
kind: CronTab
shortNames:
- ct
scope: Namespaced
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
cronSpec:
type: string
image:
type: string
replicas:
type: integer
标记协议是
KubernetesAPIResource
将对象标记为具有相应 API 端点的 Kubernetes 资源NamespacedResource
& ClusterScopedResource
指示资源是命名空间作用域还是集群作用域ReadableResource
激活资源的 get
、list
和 watch
APICreatableResource
激活资源的 create
APIReplaceableResource
激活资源的 update
APIDeletableResource
激活资源的 delete
APICollectionDeletableResource
激活资源的 deleteAll
APIScalableResource
激活资源的 scale
APIMetadataHavingResource
指示资源具有类型为 meta.v1.ObjectMeta?
的 metadata
字段StatusHavingResource
指示资源具有 state
字段(不假设其类型)可以定义以下自定义结构
struct CronTab: KubernetesAPIResource, NamespacedResource, MetadataHavingResource,
ReadableResource, CreatableResource, ListableResource {
typealias List = CronTabList
var apiVersion = "example.com/v1"
var kind = "CronTab"
var metadata: meta.v1.ObjectMeta?
var spec: CronTabSpec
}
struct CronTabSpec: Codable, Hashable, Sendable {
var cronSpec: String
var image: String
var replicas: Int
}
struct CronTabList: KubernetesResourceList {
var apiVersion = "example.com/v1"
var kind = "crontabs"
var items: [CronTab]
}
现在,新的自定义资源可以像任何其他 Kubernetes 资源一样使用
let gvr = GroupVersionResource(
group: "example.com",
version: "v1",
resource: "crontabs"
)
let cronTabClient = client.for(CronTab.self, gvr: gvr)
let cronTab = CronTab(
metadata: meta.v1.ObjectMeta(name: "new-cron"),
spec: CronTabSpec(
cronSpec : "* * * * */5",
image: "some-cron-image",
replicas: 2
)
)
let new = try await cronTabClient.create(in: .default, cronTab)
let cronTabs: CronTabList = try await cronTabClient.list(in: .allNamespaces)
KubernetesClient
使用 SwiftMetrics 来收集有关请求计数和延迟的指标信息。
收集以下指标
sk_http_requests_total(counter)
:客户端发出的请求总数。sk_http_request_errors_total(counter)
:返回 http 错误的请求总数。sk_request_errors_total(counter)
:由于非 http 错误而无法调度的请求总数。sk_http_request_duration_seconds(timer)
:完整的请求持续时间。要收集指标,您必须在应用程序中引导指标后端。例如,您可以通过 SwiftPrometheus
将指标收集到 prometheus
import Metrics
import Prometheus
let prom = PrometheusClient()
MetricsSystem.bootstrap(prom)
并公开 /metrics
端点以进行抓取
// if using vapor
app.get("metrics") { request -> EventLoopFuture<String> in
let promise = request.eventLoop.makePromise(of: String.self)
try MetricsSystem.prometheus().collect(into: promise)
return promise.futureResult
}
要在 SwiftPM 项目中使用 SwiftkubeClient
,请将以下行添加到 Package.swift
文件中的依赖项中
.package(name: "SwiftkubeClient", url: "https://github.com/swiftkube/client.git", from: "0.19.0")
然后将其作为依赖项包含在您的目标中
import PackageDescription
let package = Package(
// ...
dependencies: [
.package(name: "SwiftkubeClient", url: "https://github.com/swiftkube/client.git", from: "0.19.0")
],
targets: [
.target(name: "<your-target>", dependencies: [
.product(name: "SwiftkubeClient", package: "SwiftkubeClient"),
])
]
)
然后运行 swift build
。
Swiftkube 项目根据版本 2.0 的 Apache 许可证 获得许可。 有关更多详细信息,请参阅 LICENSE。