SwiftkubeModel
是一个零依赖的 Swift 包,用于 Kubernetes API 对象。
Codable
支持Hashable
资源Sendable
支持UnstructuredResource
类型,用于处理任何 Kubernetes 资源1.25.9 | 1.26.4 | 1.28.0 | 1.28.3 | 1.29.6 | 1.32.0 | 1.32.0 | |
---|---|---|---|---|---|---|---|
0.9.x |
✓ | - | - | - | - | - | - |
0.10.x |
- | ✓ | - | - | - | - | - |
0.11.x |
- | ✓ | - | - | - | - | - |
0.12.x |
- | - | ✓ | - | - | - | - |
0.13.x |
- | - | - | ✓ | ✓ | - | - |
0.14.x |
- | - | - | - | ✓ | - | - |
0.15.x |
- | - | - | - | - | ✓ | ✓ |
0.16.x |
- | - | - | - | - | ✓ | ✓ |
✓
模型和 Kubernetes 版本中的 API 对象完全匹配。-
API 对象不匹配,原因是旧 API 被移除或添加了新 API。但是,模型和 Kubernetes 共有的所有内容要使用 Kubernetes 对象,只需导入 SwiftkubeModel
import SwiftkubeModel
let metadata = meta.v1.ObjectMatadata(name: "swiftkube")
let pod = core.v1.Pod(metadata: metadata)
所有对象都根据其 API 组和版本进行命名空间划分,例如 apps.v1.Deployment
或 networking.v1beta1.Ingress
。这意味着,例如 rbac.v1.Role
和 rbac.v1beta1.Role
是完全不同的对象。
任何 Kubernetes 对象都可以使用模型结构体直接构建。这是一个 Deployment
清单的示例
let deployment = apps.v1.Deployment(
metadata: meta.v1.ObjectMeta(
name: "nginx"
),
spec: apps.v1.DeploymentSpec(
replicas: 1,
selector: meta.v1.LabelSelector(
matchLabels: ["app": "nginx"]
),
template: core.v1.PodTemplateSpec (
spec: core.v1.PodSpec(
containers: [
core.v1.Container(
image: "nginx",
name: "nginx",
)
]
)
)
)
)
这是一个 ConfigMap
let configMap = core.v1.ConfigMap(
metadata: meta.v1.ObjectMeta(
name: "config"
),
data: [
"env": "dev",
"log_leve": "debug"
]
)
一个更完整的 Deployment
示例,它定义了 Probes
、ResourceRequirements
、Volumes
和 VolumeMounts
,看起来像这样
let deployment = apps.v1.Deployment(
metadata: meta.v1.ObjectMeta(
name: "opa",
namespace: "default"
),
spec: apps.v1.DeploymentSpec(
replicas: 2,
selector: meta.v1.LabelSelector(
matchLabels: ["app": "opa"]
),
template: core.v1.PodTemplateSpec (
spec: core.v1.PodSpec(
containers: [
core.v1.Container(
image: "openpolicyagent/opa",
name: "opa",
readinessProbe: core.v1.Probe(
failureThreshold: 1,
httpGet: core.v1.HTTPGetAction(
path: "/health",
port: 8080
),
initialDelaySeconds: 10,
periodSeconds: 20,
successThreshold: 2,
timeoutSeconds: 5
),
resources: core.v1.ResourceRequirements(
limits: [
"ram": "512MB"
],
requests: [
"ram": "128MB",
"cpu": "200m",
]
),
volumeMounts: [
core.v1.VolumeMount(
mountPath: "/etc/test",
name: "data"
)
]
)
],
imagePullSecrets: [
core.v1.LocalObjectReference(name: "secret-name")
],
volumes: [
core.v1.Volume(
name: "data",
persistentVolumeClaim: core.v1.PersistentVolumeClaimVolumeSource(
claimName: "pvc",
readOnly: true
)
)
]
)
)
)
)
所有资源都是 Sendable
结构体。
但是,当处理具有 JSONObject
字段的资源时,有一个需要注意的地方
apiextensions.v1.CustomResourceValidation
apps.v1.ControllerRevision
meta.v1.ManagedFieldsEntry
meta.v1.WatchEvent
resource.v1alpha3.AllocatedDeviceStatus
resource.v1alpha3.OpaqueDeviceConfiguration
或者当使用 UnstructuredResource
时。
它们将其属性存储为 Dictionary<String, any Sendable>
。因此,字典字面量必须显式转换为 [String: any Sendable]
。
例如
UnstructuredResource(properties: [
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": meta.v1.ObjectMeta(name: "configs", namespace: "default"),
"data": [
"foo": 42,
"bar": "baz"
] as [String: any Sendable]
])
从上面的例子可以清楚地看出,为了编写完整的清单,需要对所有子类型及其 API 组有一定的了解。此外,Swift 不允许任意的参数顺序。
为此,SwiftkubeModel
提供了简单的基于闭包的构建器函数,以方便使用。所有这些函数都位于 sk
命名空间下。
⚠️ 语法尚未最终确定,并且在 v1.0.0 发布之前可能会多次更改。这也可以用 Function/Result Builders 替换,目前正在开发中 (WIP)。
⚠️ SwiftkubeModel
目前仅为最常见的 Kubernetes 对象提供便捷的构建器。
上面的例子看起来像这样
let deployment = sk.deployment(name: "opa") {
$0.metadata = sk.metadata {
$0.namespace = "default"
}
$0.spec = sk.deploymentSpec {
$0.replicas = 1
$0.selector = sk.match(labels: ["app": "nginx"])
$0.template = sk.podTemplate {
$0.spec = sk.podSpec {
$0.containers = [
sk.container(name: "opa") {
$0.image = "openpolicyagent/opa"
$0.readinessProbe = sk.probe(action: .httpGet(path: "/health", port: 8080)) {
$0.failureThreshold = 1
$0.initialDelaySeconds = 10
$0.periodSeconds = 20
$0.successThreshold = 2
$0.failureThreshold = 5
}
$0.resources = sk.requirements {
$0.requests = [
"ram": "512MB"
]
$0.limits = [
"ram": "128MB",
"cpu": "200m",
]
}
$0.volumeMounts = [
sk.volumeMount(name: "data", mountPath: "/etc/test")
]
}
]
$0.imagePullSecrets = [
sk.localObjectReference(name: "secret-name")
]
$0.volumes = [
sk.volume(name: "data", from: .persistentVolumeClaim(claimName: "pvc", readOnly: true))
]
}
}
}
}
除了基于闭包的构建器之外,SwiftkubeModel
还使用一些便捷函数扩展了 Model 对象,灵感来自 cdk8s
ConfigMap
let configMap: core.v1.ConfigMap = sk.configMap(name: "test")
// populate the config map
configMap.add(data: "stuff", forKey: "foo")
configMap.add(binaryData: <binary>, forKey: "foo")
configMap.add(file: URL(fileURLWithPath: "/some/path"), forKey: "foo")
configMap.add(binaryFile: URL(fileURLWithPath: "/some/path"), forKey: "foo")
let container: core.v1.Container = ...
let volume: core.v1.Volume = ...
// mount a volume in a container
container.mount(volume: volume, on: "/data")
container.mount(volume: "dataVolume", on: "/data")
let namespace: core.v1.Namespace = ...
// add/remove finalizers
namespace.add(finalizer: "foo")
namespace.remove(finalizer: "foo")
Secret
:值会自动进行 Base64 编码let secret: core.v1.Secret = sk.secret(name: "test")
// populate the secret
configMap.add(data: "stuff", forKey: "foo")
configMap.add(file: URL(fileURLWithPath: "/some/path"), forKey: "foo")
let service: core.v1.Service = ...
// add a service port entry
service.serve(port: 8080, targetPort: 80)
let serviceAccount: core.v1.ServiceAccount = ...
// add an object reference for a secret
serviceAccount.use(imagePullSecret: "pullSecret")
serviceAccount.use(secret: "secret", namespace: "ns")
Deployment
let deployment: apps.v1.Deployment = ...
// expose a deployment instance to create a service
let service = deployment.expose(on: 8080, type: .clusterIP)
通常,在使用 Kubernetes 时,资源的具体类型是未知的或不相关的,例如,当从 YAML 清单文件创建资源时。在其他情况下,必须在运行时根据其字符串表示形式推导出资源的类型或种类。
SwiftkubeModel
提供了类型擦除的资源实现 UnstructuredResource
及其对应的 List-Type UnstructuredResourceList
,以解决这些用例。
UnstruturedResource
允许通用地操作未注册 KubernetesAPIResource
的对象。这可以用于处理来自插件或 CRD 的 API 对象。
以下是一些示例,以阐明其用途
// Given a JSON string, e.g. at runtime, containing some Kubernetes resource
let json = """
{
"apiVersion": "stable.example.com/v1",
"kind": "CronTab",
"metadata": {
"name": "my-new-cron-object",
"namespace": "default"
},
"spec": {
"cronSpec": "* * * * */5",
"image": "my-awesome-cron-image"
}
}
"""
// We can still decode it without knowing the concrete type
let data = str.data(using: .utf8)!
let resource = try? JSONDecoder().decode(UnstructuredResource.self, from: data)
// When encoding the previous instance, it serializes the underlying resource
let encoded = try? JSONEncoder().encode(resource)
UnstruturedResource
公开其内部字典表示形式,并提供动态下标支持
let json = """
{
"apiVersion": "stable.example.com/v1",
"kind": "CronTab",
"metadata": {
"name": "my-new-cron-object",
"namespace": "default"
},
"spec": {
"cronSpec": "* * * * */5",
"image": "my-awesome-cron-image"
}
}
"""
let data = str.data(using: .utf8)!
let cron = try? JSONDecoder().decode(UnstructuredResource.self, from: data)
// Shortcut vars
print(cron.apiVersion)
print(cron.kind)
print(cron.metadata)
// The internal Dictionary<String: Any> representation
print(cron.properties)
// Dynamic member lookup
let spec: [String: Any]? = cron.spec
print(spec?["cronSpec"])
要在 SwiftPM 项目中使用 SwiftkubeModel
,请将以下行添加到 Package.swift
文件中的依赖项中
.package(name: "SwiftkubeModel", url: "https://github.com/swiftkube/model.git", from: "0.16.0")
然后将其作为依赖项包含在您的目标中
import PackageDescription
let package = Package(
// ...
dependencies: [
.package(name: "SwiftkubeModel", url: "https://github.com/swiftkube/model.git", from: "0.16.0")
],
targets: [
.target(name: "<your-target>", dependencies: [
.product(name: "SwiftkubeModel", package: "SwiftkubeModel"),
])
]
)
然后运行 swift build
。
Swiftkube 项目根据 Apache License 2.0 版本获得许可。有关更多详细信息,请参阅 LICENSE。