KubeClient.Extensions.DependencyInjection 2.5.12

dotnet add package KubeClient.Extensions.DependencyInjection --version 2.5.12                
NuGet\Install-Package KubeClient.Extensions.DependencyInjection -Version 2.5.12                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="KubeClient.Extensions.DependencyInjection" Version="2.5.12" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add KubeClient.Extensions.DependencyInjection --version 2.5.12                
#r "nuget: KubeClient.Extensions.DependencyInjection, 2.5.12"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install KubeClient.Extensions.DependencyInjection as a Cake Addin
#addin nuget:?package=KubeClient.Extensions.DependencyInjection&version=2.5.12

// Install KubeClient.Extensions.DependencyInjection as a Cake Tool
#tool nuget:?package=KubeClient.Extensions.DependencyInjection&version=2.5.12                

KubeClient

Build Status

KubeClient is an extensible Kubernetes API client for .NET Core (targets netstandard2.0).

Note - there is also an official .NET client for Kubernetes (both clients actually share code in a couple of places). These two clients are philosophically-different (from a design perspective) but either can be bent to fit your needs. For more information about how KubeClient differs from the official client, see the section below on extensibility.

Prerequisites

Note: If you need WebSocket / exec you'll need to target netcoreapp2.1.

Packages

  • KubeClient (netstandard2.0 or newer)
    The main client and models.
    KubeClient

  • KubeClient.Extensions.Configuration (netstandard2.0 or newer)
    Support for sourcing Microsoft.Extensions.Configuration data from Kubernetes Secrets and ConfigMaps.
    KubeClient.Extensions.KubeConfig

  • KubeClient.Extensions.DependencyInjection (netstandard2.0 or newer)
    Dependency-injection support.
    KubeClient.Extensions.KubeConfig

  • KubeClient.Extensions.KubeConfig (netstandard2.0 or newer)
    Support for loading and parsing configuration from ~/.kube/config.
    KubeClient.Extensions.KubeConfig

  • KubeClient.Extensions.WebSockets (netstandard2.1 or newer)
    Support for multiplexed WebSocket connections used by Kubernetes APIs (such as exec).
    This package also extends resource clients to add support for those APIs.

    Note that, due to a dependency on the new managed WebSockets implementation in .NET Core, this package targets netcoreapp2.1 (which requires SDK version 2.1.300 or newer) and therefore only works on .NET Core 2.1 or newer (it won't work on the full .NET Framework / UWP / Xamarin until they support netstandard2.1).
    KubeClient.Extensions.WebSockets

If you want to use the latest (development) builds of KubeClient, add the following feed to NuGet.config: https://www.myget.org/F/dotnet-kube-client/api/v3/index.json

Usage

The client can be used directly or injected via Microsoft.Extensions.DependencyInjection.

Use the client directly

The simplest way to create a client is to call KubeApiClient.Create(). There are overloads if you want to provide an access token, client certificate, or customise validation of the server's certificate:

// Assumes you're using "kubectl proxy", and no authentication is required.
KubeApiClient client = KubeApiClient.Create("http://localhost:8001");

PodListV1 pods = await client.PodsV1().List(
    labelSelector: "k8s-app=my-app"
);

For more flexible configuration, use the overload that takes KubeClientOptions:

KubeApiClient client = KubeApiClient.Create(new KubeClientOptions
{
    ApiEndPoint = new Uri("http://localhost:8001"),
    AuthStrategy = KubeAuthStrategy.BearerToken,
    AccessToken = "my-access-token",
    AllowInsecure = true // Don't validate server certificate
});

You can enable logging of requests and responses by passing an ILoggerFactory to KubeApiClient.Create() or KubeClientOptions.LoggerFactory:

ILoggerFactory loggers = new LoggerFactory();
loggers.AddConsole();

KubeApiClient client = KubeApiClient.Create("http://localhost:8001", loggers);

Configure the client from ~/.kube/config

using KubeClient.Extensions.KubeConfig;

KubeClientOptions clientOptions = K8sConfig.Load(kubeConfigFile).ToKubeClientOptions(
    kubeContextName: "my-cluster",
    defaultKubeNamespace: "kube-system"
);

KubeApiClient client = KubeApiClient.Create(clientOptions);

Make the client available for dependency injection

The client can be configured for dependency injection in a variety of ways.

To use a fixed set of options for the client, use the overload of AddKubeClient() that takes KubeClientoptions:

void ConfigureServices(IServiceCollection services)
{
    services.AddKubeClient(new KubeClientOptions
    {
        ApiEndPoint = new Uri("http://localhost:8001"),
        AuthStrategy = KubeAuthStrategy.BearerToken,
        AccessToken = "my-access-token",
        AllowInsecure = true // Don't validate server certificate
    });
}

To add a named instance of the client:

void ConfigureServices(IServiceCollection services)
{
    services.AddNamedKubeClients();
    services.AddKubeClientOptions("my-cluster", clientOptions =>
    {
        clientOptions.ApiEndPoint = new Uri("http://localhost:8001");
        clientOptions.AuthStrategy = KubeAuthStrategy.BearerToken;
        clientOptions.AccessToken = "my-access-token";
        clientOptions.AllowInsecure = true; // Don't validate server certificate
    });
    
    // OR:

    services.AddKubeClient("my-cluster", clientOptions =>
    {
        clientOptions.ApiEndPoint = new Uri("http://localhost:8001");
        clientOptions.AuthStrategy = KubeAuthStrategy.BearerToken;
        clientOptions.AccessToken = "my-access-token";
        clientOptions.AllowInsecure = true; // Don't validate server certificate
    });
}

// To use named instances of KubeApiClient, inject INamedKubeClients.

class MyClass
{
    public MyClass(INamedKubeClients namedKubeClients)
    {
        KubeClient1 = namedKubeClients.Get("my-cluster");
        KubeClient2 = namedKubeClients.Get("another-cluster");
    }

    IKubeApiClient KubeClient1 { get; }
    IKubeApiClient KubeClient2 { get; }
}

Design philosophy

Use of code generation is limited; generated clients tend to wind up being non-idiomatic and, for a Swagger spec as large as that of Kubernetes, wind up placing too many methods directly on the client class.

KubeClient's approach is to generate model classes (see src/swagger for the Python script that does this) and hand-code the actual operation methods to provide an improved consumer experience (i.e. useful and consistent exception types).

KubeResultV1

Some operations in the Kubernetes API can return a different response depending on the arguments passed in. For example, a request to delete a v1/Pod returns the existing v1/Pod (as a PodV1 model) if the caller specifies DeletePropagationPolicy.Foreground but returns a v1/Status (as a StatusV1 model) if any other type of DeletePropagationPolicy is specified.

To handle this type of polymorphic response KubeClient uses the KubeResultV1 model (and its derived implementations, KubeResourceResultV1<TResource> and KubeResourceListResultV1<TResource>).

KubeResourceResultV1<TResource> can be implicitly cast to a TResource or a StatusV1, so consuming code can continue to use the client as if it expects an operation to return only a resource or expects it to return only a StatusV1:

PodV1 existingPod = await client.PodsV1().Delete("mypod", propagationPolicy: DeletePropagationPolicy.Foreground);
// OR:
StatusV1 deleteStatus = await client.PodsV1().Delete("mypod", propagationPolicy: DeletePropagationPolicy.Background);

If an attempt is made to cast a KubeResourceResultV1<TResource> that contains a non-success StatusV1 to a TResource, a KubeApiException is thrown, based on the information in the StatusV1:

PodV1 existingPod;

try
{
    existingPod = await client.PodsV1().Delete("mypod", propagationPolicy: DeletePropagationPolicy.Foreground);
}
catch (KubeApiException kubeApiError)
{
    Log.Error(kubeApiError, "Failed to delete Pod: {ErrorMessage}", kubeApiError.Status.Message);
}

For more information about the behaviour of KubeResultV1 and its derived implementations, see KubeResultTests.cs.

Extensibility

KubeClient is designed to be easily extensible. The KubeApiClient provides the top-level entry point for the Kubernetes API and extension methods are used to expose more specific resource clients.

Simplified version of PodClientV1.cs:

public class PodClientV1 : KubeResourceClient
{
    public PodClientV1(KubeApiClient client) : base(client)
    {
    }

    public async Task<List<PodV1>> List(string labelSelector = null, string kubeNamespace = null, CancellationToken cancellationToken = default)
    {
        PodListV1 matchingPods =
            await Http.GetAsync(
                Requests.Collection.WithTemplateParameters(new
                {
                    Namespace = kubeNamespace ?? KubeClient.DefaultNamespace,
                    LabelSelector = labelSelector
                }),
                cancellationToken: cancellationToken
            )
            .ReadContentAsObjectV1Async<PodListV1>();

        return matchingPods.Items;
    }

    public static class Requests
    {
        public static readonly HttpRequest Collection = KubeRequest.Create("api/v1/namespaces/{Namespace}/pods?labelSelector={LabelSelector?}&watch={Watch?}");
    }
}

Simplified version of ClientFactoryExtensions.cs:

public static PodClientV1 PodsV1(this KubeApiClient kubeClient)
{
    return kubeClient.ResourceClient(
        client => new PodClientV1(client)
    );
}

This enables the following usage of KubeApiClient:

KubeApiClient client;
PodListV1 pods = await client.PodsV1().List(kubeNamespace: "kube-system");

Through the use of extension methods, resource clients (or additional operations) can be declared in any assembly and used as if they are part of the KubeApiClient. For example, the KubeClient.Extensions.WebSockets package adds an ExecAndConnect method to PodClientV1.

Simplified version of ResourceClientWebSocketExtensions.cs:

public static async Task<K8sMultiplexer> ExecAndConnect(this IPodClientV1 podClient, string podName, string command, bool stdin = false, bool stdout = true, bool stderr = false, bool tty = false, string container = null, string kubeNamespace = null, CancellationToken cancellation = default)
{
    byte[] outputStreamIndexes = stdin ? new byte[1] { 0 } : new byte[0];
    byte[] inputStreamIndexes;
    if (stdout && stderr)
        inputStreamIndexes = new byte[2] { 1, 2 };
    else if (stdout)
        inputStreamIndexes = new byte[1] { 1 };
    else if (stderr)
        inputStreamIndexes = new byte[1] { 2 };
    else if (!stdin)
        throw new InvalidOperationException("Must specify at least one of STDIN, STDOUT, or STDERR.");
    else
        inputStreamIndexes = new byte[0];
    
    return await podClient.KubeClient
        .ConnectWebSocket("api/v1/namespaces/{KubeNamespace}/pods/{PodName}/exec?stdin={StdIn?}&stdout={StdOut?}&stderr={StdErr?}&tty={TTY?}&command={Command}&container={Container?}", new
        {
            PodName = podName,
            Command = command,
            StdIn = stdin,
            StdOut = stdout,
            StdErr = stderr,
            TTY = tty,
            Container = container,
            KubeNamespace = kubeNamespace ?? podClient.KubeClient.DefaultNamespace
        }, cancellation)
        .Multiplexed(inputStreamIndexes, outputStreamIndexes,
            loggerFactory: podClient.KubeClient.LoggerFactory()
        );
}

Example usage of ExecAndConnect:

KubeApiClient client;
K8sMultiplexer connection = await client.PodsV1().ExecAndConnect(
    podName: "my-pod",
    command: "/bin/bash",
    stdin: true,
    stdout: true,
    tty: true
);
using (connection)
using (StreamWriter stdin = new StreamWriter(connection.GetOutputStream(0), Encoding.UTF8))
using (StreamReader stdout = new StreamReader(connection.GetInputStream(1), Encoding.UTF8))
{
    await stdin.WriteLineAsync("ls -l /");
    await stdin.WriteLineAsync("exit");

    // Read from STDOUT until process terminates.
    string line;
    while ((line = await stdout.ReadLineAsync()) != null)
    {
        Console.WriteLine(line);
    }
}

For information about HttpRequest, UriTemplate, and other features used to implement the client take a look at the HTTPlease documentation.

Working out what APIs to call

If you want to replicate the behaviour of a kubectl command you can pass the flag --v=10 to kubectl and it will dump out (for each request that it makes) the request URI, request body, and response body.

Building

You will need to use v2.1.300 (or newer) of the .NET Core SDK to build KubeClient.

Questions / feedback

Feel free to get in touch if you have questions, feedback, or would like to contribute.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (3)

Showing the top 3 NuGet packages that depend on KubeClient.Extensions.DependencyInjection:

Package Downloads
Ocelot.Provider.Kubernetes

Provides Ocelot extensions to use kubernetes

Contrib.KubeClient.CustomResources

KubeClient contribution to simplify work with CustomResources

CustomOcelot.Provider.Kubernetes

Provides Ocelot extensions to use kubernetes

GitHub repositories (1)

Showing the top 1 popular GitHub repositories that depend on KubeClient.Extensions.DependencyInjection:

Repository Stars
ThreeMammals/Ocelot
.NET API Gateway
Version Downloads Last updated
2.5.12 1,907 10/16/2024
2.5.10 3,023 8/11/2024
2.5.9 128 8/11/2024
2.5.8 1,344 5/19/2024
2.4.10 98,843 12/10/2022
2.4.9 3,133 10/15/2022
2.4.6 150,623 9/17/2021
2.4.4 488 9/17/2021
2.3.16 3,964 4/3/2021
2.3.15 64,552 9/17/2020
2.3.14 721 9/15/2020
2.3.13 2,307 6/4/2020
2.3.11 93,035 2/12/2020
2.3.9 730 2/5/2020
2.3.8 658 2/5/2020
2.3.7 2,595 1/15/2020
2.3.6 3,115 11/9/2019
2.3.5 950 10/6/2019
2.3.4 38,525 10/5/2019
2.3.3 618 10/4/2019
2.3.2 2,621 9/21/2019
2.3.1 602 9/20/2019
2.3.0 668 8/10/2019
2.2.16 608 8/10/2019
2.2.15 858 8/7/2019
2.2.14 1,714 6/12/2019
2.2.13 748 5/25/2019
2.2.12 20,714 5/20/2019
2.2.11 9,614 4/16/2019
2.2.10 679 3/23/2019
2.2.9 636 3/23/2019
2.2.8 1,442 3/18/2019
2.2.7 693 3/17/2019
2.2.6 733 3/1/2019
2.2.4 1,242 1/17/2019
2.2.3 799 1/14/2019
2.2.2 793 1/12/2019
2.2.1 781 1/11/2019
2.2.0 775 1/11/2019
2.1.14 836 12/12/2018
2.1.13 743 12/12/2018
2.1.12 2,907 11/21/2018
2.1.11 1,280 11/15/2018
2.1.10 1,178 11/15/2018
2.1.9 750 11/15/2018
2.1.8 806 11/15/2018
2.1.7 2,987 10/16/2018
2.1.6 1,005 8/17/2018
2.1.5 1,167 7/12/2018
2.1.4 934 6/27/2018
2.1.2 1,041 6/6/2018
2.0.4 1,159 3/30/2018
2.0.3 1,263 3/30/2018
2.0.2 1,236 3/30/2018
2.0.0 1,061 3/30/2018
1.0.4 1,049 3/1/2018
0.6.8 1,091 2/28/2018
0.6.7 1,117 2/28/2018
0.6.6 970 2/28/2018
0.6.5 1,156 2/28/2018
0.6.4 1,096 2/28/2018
0.6.3 1,043 2/28/2018
0.6.2 1,053 2/28/2018
0.6.1 970 2/27/2018
0.6.0 1,085 2/26/2018
0.5.5 1,078 2/26/2018
0.5.4 1,086 2/26/2018
0.5.3 1,009 2/26/2018
0.5.2 1,048 2/26/2018
0.5.1 1,008 2/26/2018
0.5.0 942 2/25/2018
0.4.6 1,055 2/25/2018
0.4.5 893 2/25/2018
0.4.4 1,038 2/23/2018
0.4.3 987 2/23/2018
0.4.2 1,032 2/23/2018
0.4.1 1,103 2/22/2018
0.4.0 1,145 2/22/2018
0.3.1 977 2/22/2018
0.3.0 1,014 2/22/2018
0.2.13 689 5/3/2019
0.2.12 732 5/2/2019
0.2.2 986 2/21/2018
0.2.1 1,055 2/21/2018