NewWe open-sourced 50+ Laravel packages
Custom AI apps, agents and automation — Roundly ConsultingRoundly
All packages
Kubernetes API for Laravel

Connecting to a cluster

Every request goes through a Cluster — an immutable client that knows the apiserver URL and how to authenticate. Kubernetes::url() starts a blank ad-hoc one; build it fluently with tokens, client certificates and a CA bundle:

use RoundlyConsulting\KubernetesApi\Facades\Kubernetes;

$cluster = Kubernetes::url('https://api.prod.example.com:6443')
    ->withToken(config('services.kubernetes.token'))
    ->withCertificate('/path/to/client.crt')
    ->withPrivateKey('/path/to/client.key')
    ->withCaCertificate('/path/to/ca.crt')
    ->withSslVerification()
    ->withManagerName('my-app'); // the field manager on resources this app writes

$cluster->withToken('other');   // returns a copy — $cluster still uses the original token

Kubernetes::url() inherits nothing — no token, no certificate — from the default cluster. For local development you can skip the certificates and disable verification; never do this in production:

$cluster = Kubernetes::url('https://127.0.0.1:6443')
    ->withToken('local-dev-token')
    ->withoutSslVerification();

url(), every with…() / without…(), withManagerName(), withDefaultNamespace() and namespace() return a new cluster and leave the one you called untouched — a client handed out by the facade can never be re-pointed or re-credentialed by another caller.

Authentication API

Method (each returns a copy)Effect
url($url)Apiserver base URL, e.g. https://api.prod.example.com:6443.
withToken($token)Bearer token sent with every request (a #[SensitiveParameter], so it never shows in stack traces).
withCertificate($path) / withPrivateKey($path)Client certificate and key for mutual TLS.
withCaCertificate($path)CA bundle the apiserver certificate is verified against.
withSslVerification() / withoutSslVerification()Toggle TLS verification — on by default.
withManagerName($name)Sent as fieldManager on every create, update, patch, scale and rollout restart, and as the User-Agent of every request.
withDefaultNamespace($namespace)Soft default namespace for namespaced resources — unlike namespace(), it refuses nothing.
getUrl() · getToken() · hasToken() · shouldVerify() · getManagerName() · defaultNamespace()Readers for the settings above.
getPathToCertificate() · getPathToPrivateKey() · getPathToCaCertificate()Readers for the certificate paths.

Tokens become an Authorization: Bearer header, the certificate and key are handed to the HTTP client for mutual TLS, and the CA path replaces the system trust store for verification. The manager name is sent as the fieldManager query parameter on every create, update, patch, scale and rollout restart, so managedFields records your app as the owner of what it wrote; it is also sent as the User-Agent. A server-side apply needs a field manager, so without a manager name it falls back to kubernetes-api-for-laravel.

From a kubeconfig or in-cluster

Point the client at a cluster in one line instead of hand-wiring the URL and credentials. fromKubeConfig() parses the kubeconfig, resolves the named context’s cluster and user, and materialises any inline certificate data to private temp files — one per distinct PEM, removed when the PHP process exits. inCluster() reads the service-account token and CA mounted into a pod:

use RoundlyConsulting\KubernetesApi\Facades\Kubernetes;

// Current context from the default kubeconfig (or the KUBECONFIG env path):
$cluster = Kubernetes::fromKubeConfig();

// A specific context, optionally from an explicit kubeconfig path:
$cluster = Kubernetes::fromKubeConfig(context: 'local-dev');
$cluster = Kubernetes::fromKubeConfig(path: '/path/to/kubeconfig', context: 'staging');

// From in-cluster service-account mounts (when running inside a pod):
$cluster = Kubernetes::inCluster()->withManagerName('my-app');
  • Without a path, the first entry of the KUBECONFIG environment variable is read, falling back to ~/.kube/config. Without a context, current-context is used.
  • From the user entry the loader reads a static token and/or client-certificate and client-key; from the cluster entry the server, certificate-authority and insecure-skip-tls-verify. Each certificate can be a file path or an inline *-data block; relative paths (certificate-authority: certs/ca.crt) resolve against the kubeconfig’s own directory, as kubectl does.
  • A cluster’s insecure-skip-tls-verify must be a boolean — true/false, also yes/no, on/off or 1/0, quoted or not. Anything else throws KubeConfigException instead of guessing, so a quoted “false” keeps TLS verification on.
  • inCluster() builds https://KUBERNETES_SERVICE_HOST:KUBERNETES_SERVICE_PORT (IPv6 hosts included) and reads the token from /var/run/secrets/kubernetes.io/serviceaccount/token. TLS verification stays on against the mounted ca.crt — if that file is missing it throws KubeConfigException rather than send the token to an unverified apiserver.
  • A missing file, context, cluster or user, a cluster without a server URL, an invalid insecure-skip-tls-verify, invalid base64, missing in-cluster env vars, an empty token or a missing in-cluster CA all throw KubeConfigException.
  • The same sources work from config — 'source' => 'kubeconfig' or 'source' => 'in-cluster' on a clusters entry (see Named clusters).

Connecting from a KubeConfig

Both loaders produce a KubeConfig value object. Kubernetes::connect() turns one into a new ad-hoc cluster, so you can build it from your own secrets store the same way; Cluster::applyConfig() applies one to a copy of an existing cluster:

use RoundlyConsulting\KubernetesApi\DataTransferObjects\KubeConfig;
use RoundlyConsulting\KubernetesApi\Facades\Kubernetes;

$cluster = Kubernetes::connect(new KubeConfig(
    server: 'https://api.staging.example.com:6443',
    token: config('services.kubernetes.staging_token'),
    clientCertificatePath: null,
    clientKeyPath: null,
    certificateAuthorityPath: storage_path('kubernetes/staging-ca.crt'),
    verify: true,
));

Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

More ways to support, including crypto

By donating, you agree to our donation terms.

Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.