---
title: "The Kubernetes facade — Kubernetes API for Laravel | Roundly"
description: "The Kubernetes facade in full: default-cluster shortcuts, named and ad-hoc clusters, the Cluster handle, raw requests and the 33 resource accessors."
url: https://roundly-consulting.com/open-source/docs/kubernetes-api-for-laravel/facade
language: en
---

[All packages](https://roundly-consulting.com/open-source.md)

[Kubernetes API for Laravel](https://roundly-consulting.com/open-source/docs/kubernetes-api-for-laravel.md)

# The Kubernetes facade

Everything starts at the Kubernetes facade (RoundlyConsulting\\KubernetesApi\\Facades\\Kubernetes). It hands out clusters — immutable clients — and, through them, resource objects (Pod, Deployment, …) that read and write the apiserver. Calls without a cluster name go to the default cluster from config/kubernetes.php:

```php
use RoundlyConsulting\KubernetesApi\Facades\Kubernetes;

Kubernetes::pods()->get();                                   // default cluster, default namespace
Kubernetes::namespace('shop')->deployments()->get();         // default cluster, scoped to shop
Kubernetes::cluster('production')->services()->get();        // a named cluster

Kubernetes::ping();                                          // bool — does the apiserver answer?
Kubernetes::version()->gitVersion;                           // "v1.34.0" (a VersionInfo DTO)

Kubernetes::hasCluster('production');                        // bool
Kubernetes::clusters();                                      // ['default', 'production']

Kubernetes::url('https://127.0.0.1:6443')->withToken($token); // a new, blank ad-hoc cluster
Kubernetes::fromKubeConfig(context: 'staging');              // a new cluster from a kubeconfig context
```

## Method reference

| Method | Returns | What it does |
| --- | --- | --- |
| `cluster(?string $name = null)` | `Cluster` | A configured or registered cluster — the default one when null. Resolved once and reused. |
| `hasCluster(string $name) · clusters()` | `bool · list<string>` | Whether a cluster exists; every configured and registered name. |
| `registerCluster(string $name, Closure $definition)` | `void` | Define a cluster in code; overrides a configured one of the same name. |
| `registerResource(string $name, string $class)` | `void` | Register a resource class under an accessor name for every cluster. |
| `namespace(string $namespace)` | `Cluster` | The default cluster, scoped to one namespace. |
| `ping() · version()` | `bool · VersionInfo` | Health and build information of the default cluster. |
| `url(string $url)` | `Cluster` | A new, blank ad-hoc cluster. |
| `connect(KubeConfig $config)` | `Cluster` | A new ad-hoc cluster from a resolved connection; its namespace, if any, is the default namespace. |
| `fromKubeConfig(?string $path, ?string $context) · inCluster()` | `Cluster` | A new ad-hoc cluster from a kubeconfig context (its namespace is the default namespace) or the pod’s service account (its token file is re-read for every request). |
| `resource(string $class)` | `Resource` | Any resource class, bound to the default cluster. |
| `pods(), deployments(), services(), … (33 accessors)` | the resource | Every packaged resource, bound to the default cluster. |
| `apps(), tenantNamespace(), …` | resource / macro result | A custom resource registered under that name, or a Cluster macro — on the default cluster. |
| `fake()` | `KubernetesFake` | Swap in the in-memory apiserver for tests — see Testing. Under the fake, the facade also forwards the fake’s assertions, assertTokenRequested() included. |

## The Cluster handle

cluster(), namespace(), url(), connect(), fromKubeConfig() and inCluster() all return a RoundlyConsulting\\KubernetesApi\\Cluster. Every Cluster has the same 33 accessors as the facade, plus its own identity, health checks and a raw request() escape hatch that is authenticated, rate limited and faked like everything else:

```php
$cluster = Kubernetes::cluster('production');

$cluster->name();                   // 'production' (null for ad-hoc clusters)
$cluster->defaultNamespace();       // from clusters.production.namespace
$cluster->hasResource('apps');      // is an accessor registered under that name?
$cluster->getUrl();                 // plus getToken(), getTokenFile(), getManagerName(), shouldVerify()…
$cluster->followsRedirects();       // false unless the cluster opted in
$cluster->redactsErrors();          // whether exception messages carry status + reason only

// Raw escape hatch — authenticated, rate limited and faked like the typed resources
$response = $cluster->request('GET', '/apis/apps/v1/namespaces/shop/deployments', ['limit' => 10]);
$response->json('items');
```

| Cluster method | Returns | Notes |
| --- | --- | --- |
| `name()` | `?string` | The registration name; null for ad-hoc clusters (url(), connect(), fromKubeConfig(), inCluster()). |
| `url() · with…() · without…() · withManagerName() · withDefaultNamespace()` | a copy | Connection and credentials — see Connecting to a cluster. |
| `namespace(string) · namespaceScope()` | `Cluster · ?string` | A copy scoped to one namespace; the scope, if any. |
| `defaultNamespace()` | `string` | The soft default for namespaced resources. |
| `withRedirects() · withoutRedirects() · followsRedirects()` | a copy · a copy · bool | Opt in to following HTTP redirects — off by default; see Connecting to a cluster. |
| `withRedactedErrors() · redactsErrors()` | a copy · bool | Exception messages with status and reason only; see Error handling. |
| `applyConfig(KubeConfig)` | a copy | Replaces URL, token, token file, certificate, key, CA and verification; a namespace becomes the default namespace (never over a namespace scope). The redirect opt-in and error redaction are kept. |
| `resource(class-string) · hasResource(string)` | `Resource · bool` | Any resource class bound to this cluster; whether an accessor name is registered. |
| `ping() · version()` | `bool · VersionInfo` | ping() is false on an apiserver error (an unfollowed redirect included), a connection failure or a missing URL; a rate-limit exhaustion still throws. |
| `request($method, $path, $query = [], $body = '', $contentType = null, $stream = false)` | `Response` | Raw escape hatch through the cluster’s transport; a failed response throws KubernetesException, and so does a redirect that wasn’t followed. |
| `getUrl() · getToken() · getTokenFile() · getManagerName() · shouldVerify() · getPathTo…()` | readers | The credentials the cluster carries. |

- Clusters are immutable: every with…() / without…() call, url(), withManagerName(), withDefaultNamespace() and namespace() return a new cluster, so a client handed out by the facade can never be re-pointed or re-credentialed by another caller.
- Named clusters are resolved once and reused; url(), connect(), fromKubeConfig() and inCluster() build a new ad-hoc cluster on every call.
- Cluster::execute() is @internal — it opens the exec WebSocket for Pod::exec(); call exec() on a pod instead.

## 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](https://roundly-consulting.com/support-us.md)

By donating, you agree to our [donation terms](https://roundly-consulting.com/donation-terms.md).

[Support our open source work (opens in a new tab)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Join us on Patreon (opens in a new tab)](https://www.patreon.com/cw/roundly)

## 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.

[Get a quote in 48 hours](https://roundly-consulting.com/contact.md) [Browse all packages](https://roundly-consulting.com/open-source/docs/kubernetes-api-for-laravel.md)
