Swiftkube Client

repository·main·Indexed 41 days ago

https://github.com/swiftkube/client

A high-performance Swift client for Kubernetes built on SwiftNIO and AsyncHTTPClient. It provides a fluent, type-safe DSL for interacting with all Kubernetes API groups, supporting resource operations (Read, List, Delete, /scale, /status), resource watching, pod log following, and Custom Resource Definitions (CRDs). Includes automatic configuration discovery and integration with Swift-Logging and Swift Metrics.

Tokens
3.6K
Snippets
10
Records
13
Agent score
1%

What's inside Swiftkube Client

  1. Overview of Swiftkube Client

    main

    Swiftkube Client is a Swift-based client for interacting with Kubernetes clusters. It is built on top of SwiftNIO and AsyncHTTPClient, providing a fluent DSL for all Kubernetes API Groups and Versions.

    Key features include:

    • Automatic configuration discovery for Kubernetes clusters.
    • Fluent DSL style API for interacting with all API Groups/Versions.
    • Generic client support and CRD support.
    • Resource operations: Support for Read, List, Delete, /scale, and /status APIs.
    • Advanced features: Resource watch support, following pod logs, and Discovery API.
    • Observability: Integration with Swift-Logging and Swift Metrics.
    • External loading: Ability to load resources from files or URLs.
  2. Monitor KubernetesClient performance with SwiftMetrics

    main

    The KubernetesClient integrates with SwiftMetrics to track request counts and latencies. To enable collection, you must bootstrap a metrics backend (such as SwiftPrometheus) in your application.

    Available Metrics

    • sk_http_requests_total(counter): Total count of requests made by the client.
    • sk_http_request_errors_total(counter): Total number of requests that returned an HTTP error.
    • sk_request_errors_total(counter): Total number of requests that failed to dispatch due to non-HTTP errors.
    • sk_http_request_duration_seconds(timer): Complete request durations.
    import Metrics
    import Prometheus
    
    let prom = PrometheusClient()
    MetricsSystem.bootstrap(prom)
  3. Use Type-erased resources (Unstructured)

    main

    When the concrete type of a resource is unknown or needs to be derived at runtime, use UnstructuredResource. You can interact with these via a GroupVersionResource (GVR).

    GroupVersionResource and GroupVersionKind can be initialized from a resource instance, a type, or a string (e.g., plural resource name like "configmaps").

    // Initialize GVR from a string
    let gvr = GroupVersionResource(for: "configmaps")
    
    // Get unstructured resource
    let resource: UnstructuredResource = try await client.for(gvr: gvr).get(in: .default, name: "nginx")
    
    // List unstructured resources
    let resources: UnstructuredResourceList = try await client.for(gvr: gvr).list(in: .allNamespaces)
  4. Extend the client with Custom Resource Definitions (CRDs)

    main

    The client supports CRDs natively. You can manage custom resources in two ways:

    1. Unstructured: Use UnstructuredResource with a specific GroupVersionResource.
    2. Typed (Marker Protocols): Define custom Swift structs that implement specific marker protocols to enable full DSL support (get, list, watch, create, etc.).

    Supported Marker Protocols

    • KubernetesAPIResource: Marks the object as a Kubernetes resource.
    • NamespacedResource / ClusterScopedResource: Defines scope.
    • ReadableResource: Enables get, list, and watch.
    • CreatableResource: Enables create.
    • ReplaceableResource: Enables update.
    • DeletableResource: Enables delete.
    • MetadataHavingResource: Indicates presence of metadata: ObjectMeta?.
    • StatusHavingResource: Indicates presence of a state field.
    // Example of a typed Custom Resource
    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
    }
    
    // Using the typed client
    let gvr = GroupVersionResource(group: "example.com", version: "v1", resource: "crontabs")
    let cronTabClient = client.for(CronTab.self, gvr: gvr)
    
    let newCron = try await cronTabClient.create(in: .default, myCronTabInstance)
  5. Watch and Follow Kubernetes resources

    main

    Watching resources

    watch opens a persistent connection to the API server. It returns a SwiftkubeClientTask which must be explicitly started via .start() to receive an AsyncThrowingStream of events.

    • Reconnection: The client automatically reconnects on non-recoverable errors using a RetryStrategy. The default is 10 attempts with a 5s fixed delay (initial 1s, 0.2s jitter).
    • Cancellation: You must call task.cancel() when the watch is no longer needed.

    Following logs

    follow emits log lines instead of events.

    Warning: Unlike watch, the client does not reconnect on errors in follow mode.

    // Watch
    let task: SwiftkubeClientTask = try await client.pods.watch(in: .allNamespaces)
    let stream = await task.start()
    for try await event in stream { print(event) }
    task.cancel()
    
    // Follow logs
    let logTask = try await client.pods.follow(in: .default, name: "nginx", container: "app")
    for try await line in await logTask.start() { print(line) }
    logTask.cancel()
  6. Configure the KubernetesClient

    main

    The client automatically resolves kube config from the KUBECONFIG environment variable, the $HOME/.kube/config directory, or via a ServiceAccount token if running inside Kubernetes.

    You can also load configuration manually using KubeConfig methods and then initialize a KubernetesClientConfig.

    // Manual KubeConfig loading
    let kubeConfig = try KubeConfig.fromDefaultLocalConfig()
    let config = KubernetesClientConfig.from(
      kubeConfig: kubeConfig,
      contextName: "some-context" // defaults to "current-context"
    )
    
    // Fully manual configuration
    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)
  7. Create and shut down a KubernetesClient

    main

    To use the client, import SwiftkubeClient and initialize a KubernetesClient.

    Important: You must shut down the client instance when finished to close the underlying HTTPClient. Do not call shutdown() until all pending requests have completed. You can shut down the client synchronously, asynchronously using async/await, or via a DispatchQueue callback.

    import SwiftkubeClient
    
    let client = try KubernetesClient()
    
    // 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)
    }
  8. Install SwiftkubeClient via SwiftPM

    main

    To use SwiftkubeClient in a SwiftPM project, add the repository as a dependency in your Package.swift file and include the SwiftkubeClient product in your target dependencies.

    import PackageDescription
    
    let package = Package(
        // ...
        dependencies: [
            .package(name: "SwiftkubeClient", url: "https://github.com/swiftkube/client.git", from: "0.23.0")
        ],
        targets: [
            .target(name: "<your-target>", dependencies: [
                .product(name: "SwiftkubeClient", package: "SwiftkubeClient"),
            ])
        ]
    )
  9. Use the Client DSL for CRUD operations

    main

    The client provides a type-safe DSL for interacting with Kubernetes resources using Swift concurrency.

    List resources

    Use .list() with optional ListOptions to filter by label selectors, field selectors, or limit results.

    Get a resource

    Use .get() to retrieve a specific resource by name. You can provide ReadOptions like .pretty() or .exact().

    Delete a resource

    Use .delete() to remove a resource. You can pass meta.v1.DeleteOptions to control propagation and grace periods.

    Create and Update

    Resources can be created by passing an instance or using convenience builders provided by SwiftkubeModel.

    // List
    let deployments = try await client.appsV1.deployments.list(in: .allNamespaces, options: [
      .labelSelector(.eq(["app": "nginx"])),
      .limit(20)
    ])
    
    // Get
    let deployment = try await client.appsV1.deployments.get(in: .namespace("ns"), name: "nginx")
    
    // Delete
    try await client.appsV1.deployments.delete(in: .namespace("ns"), name: "nginx")
    
    // Create (using 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" }] } 
       } 
    }
  10. Expose metrics via a Vapor endpoint

    main

    If you are using the Vapor framework, you can expose your collected metrics by creating a /metrics endpoint that scrapes the MetricsSystem.

    // 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
    }
  11. Discover API Server information

    main

    Use the discovery interface to retrieve metadata about the Kubernetes API server, including its version, available API groups, and resources available within a specific group version.

    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")
  12. Configure Client Authentication

    main

    The client supports the following authentication schemes via KubernetesClientAuthentication:

    • Basic Auth: .basicAuth(username: String, password: String)
    • Bearer Token: .bearer(token: String)
    • Client Certificate: .x509(clientCertificate: NIOSSLCertificate, clientKey: NIOSSLPrivateKey)