keboola / k8s-client
Keboola K8S client library
Requires
- php: ^8.2
- keboola/retry: ^0.5.1
- kubernetes/php-client: 1.26.10-patch.1
- kubernetes/php-runtime: ^1.0.13
Requires (Dev)
- keboola/coding-standard: ^15.0
- monolog/monolog: ^3.9
- phpstan/phpstan: ^1.9
- phpstan/phpstan-phpunit: ^1.1
- phpunit/phpunit: ^9.5
- sempro/phpunit-pretty-print: ^1.4
- symfony/dotenv: ^6.2
- symfony/filesystem: ^6.1
This package is auto-updated.
Last update: 2026-07-31 14:29:54 UTC
README
High-level K8S client library. It is based on kubernetes/php-client library, but enhances
it in many ways:
- support connection to multiple clusters
- automatic handling of result type (you don't need to check if the result is what you expect,
Statusor something else) - integrated retries in case of networking problems
- high-level operations like
createmultiple resources at once,waitWhileExiststo wait while given resource exists etc.
Usage
To create a client, first pick a Keboola\K8sClient\ClientFactory\KubernetesApiClientFactory implementation that
matches how you obtain credentials, then use it together with the universal KubernetesApiClientFacadeFactory to
build the high-level facade:
StaticKubernetesApiClientFactoryif you have explicit cluster credentialsInClusterKubernetesApiClientFactoryif you run inside a Pod which has access to K8S APIEnvVariablesKubernetesApiClientFactoryif credentials are provided viaK8S_HOST/K8S_TOKEN/K8S_CA_CERT_PATH/K8S_NAMESPACEenv variablesAutoDetectKubernetesApiClientFactoryto try env variables first, falling back to in-cluster credentials
<?php use Keboola\K8sClient\ClientFactory\StaticKubernetesApiClientFactory; use Keboola\K8sClient\KubernetesApiClientFacade; use Kubernetes\Model\Io\K8s\Api\Core\V1\Container; use Kubernetes\Model\Io\K8s\Api\Core\V1\Pod; $clientFactory = new StaticKubernetesApiClientFactory( $retryProxy, 'https://api.k8s-cluster.example.com', 'secret-token', 'var/k8s/caCert.pem', 'default', ); $apiClient = $clientFactory->createApiClient(); $client = KubernetesApiClientFacade::create($apiClient, $logger); $pod = new Pod([ 'metadata' => [ 'name' => 'my-pod', ], 'spec' => [ 'restartPolicy' => 'Never', 'containers' => [ new Container([ 'name' => 'app', 'image' => 'alpine', 'command' => ['sh', '-c', 'echo hello; sleep 3; echo bye'], ]), ], ], ]); // create the pod $client->createModels([ $pod, ]); // wait for pod to finish do { $pod = $client->pods()->getStatus($pod->metadata->name); if (in_array($pod->status->phase, ['Succeeded', 'Failed'], true)) { break; } sleep(1); } while (true); // check pod logs $client->pods()->readLog($pod->metadata->name); // delete the pod $client->deleteModels([ $pod, ]);
Custom resources (CRDs)
The facade also serves resources it doesn't ship. Implement an API client for your CRD by extending
Keboola\K8sClient\ApiClient\BaseNamespaceApiClient (or BaseClusterApiClient), then register it via the
$extraClients map — keyed by the CRD model class — when building the facade:
$facade = KubernetesApiClientFacade::create($apiClient, $logger, [ My\Crd\Model::class => new My\Crd\ApiClient($apiClient), ]); $facade->client(My\Crd\Model::class)->get('my-resource'); // typed access $facade->mergePatch($myCrdModel); // generic methods route via the map too
Symfony integration
The library ships no bundle, so wire the pieces as services. Minimal setup with auto-detected credentials
(env vars in dev, in-cluster ServiceAccount token in prod) using the shared-client + create() split:
services: # credential strategy — AutoDetect needs its two sub-factories defined (RetryProxy is not autowirable) Keboola\K8sClient\ClientFactory\EnvVariablesKubernetesApiClientFactory: arguments: $retryProxy: !service { class: Retry\RetryProxy } Keboola\K8sClient\ClientFactory\InClusterKubernetesApiClientFactory: arguments: $retryProxy: !service { class: Retry\RetryProxy } Keboola\K8sClient\ClientFactory\AutoDetectKubernetesApiClientFactory: ~ # the shared low-level client app.k8s.api_client: class: Keboola\K8sClient\KubernetesApiClient factory: ['@Keboola\K8sClient\ClientFactory\AutoDetectKubernetesApiClientFactory', 'createApiClient'] arguments: $namespace: '%env(K8S_NAMESPACE)%' # the high-level facade (static factory called as a class-string); register CRD clients via $extraClients Keboola\K8sClient\KubernetesApiClientFacade: factory: ['Keboola\K8sClient\KubernetesApiClientFacade', 'create'] arguments: $apiClient: '@app.k8s.api_client' $logger: '@logger' $extraClients: {} # e.g. 'App\Crd\Model': '@App\Crd\ApiClient'
For a single credential source you can skip AutoDetect and point the client at
StaticKubernetesApiClientFactory (explicit values) or InClusterKubernetesApiClientFactory directly.
Development
Prerequisites:
- configured
azandawsCLI tools (runaz loginandaws configure --profile keboola-dev-platform-services) - installed
terraform(https://www.terraform.io) andjq(https://stedolan.github.io/jq) to setup local env - installed
dockerto run & develop the library
TL;DR:
export NAME_PREFIX= # your name/nickname to make your resource unique & recognizable cat <<EOF > ./provisioning/local/terraform.tfvars name_prefix = "${NAME_PREFIX}" EOF terraform -chdir=./provisioning/local init -backend-config="key=k8s-client/${NAME_PREFIX}.tfstate" terraform -chdir=./provisioning/local apply ./provisioning/local/update-env.sh azure # or aws docker compose run --rm dev composer install docker compose run --rm dev composer ci
Implementing new API
Only few K8S APIs we needed are implement so far. To implement new API, do following:
- create API client wrapper in
Keboola\K8sClient\ApiClient- this is a wrapper around
kubernetes/php-clientAPI class, takes care of handling results
- this is a wrapper around
- add the wrapper to
KubernetesApiClientFacade- inject the
kubernetes/php-clientclient through constructor - add support for the new resource to methods signatures
- inject the
- update
KubernetesApiClientFacade::create()to provide the new API class to the facade
License
MIT licensed, see LICENSE file.