Configuration
The published config/kubernetes.php in full:
use RoundlyConsulting\KubernetesApi\Resources;
return [
'default' => env('KUBERNETES_CLUSTER', 'default'),
'clusters' => [
'default' => [
'source' => env('KUBERNETES_SOURCE', 'url'), // url | kubeconfig | in-cluster
'url' => env('KUBERNETES_URL'),
'token' => env('KUBERNETES_TOKEN'),
'certificate' => env('KUBERNETES_CLIENT_CERTIFICATE'),
'private_key' => env('KUBERNETES_CLIENT_KEY'),
'ca_certificate' => env('KUBERNETES_CA_CERTIFICATE'),
'verify' => env('KUBERNETES_VERIFY_SSL', true),
'kubeconfig' => env('KUBERNETES_KUBECONFIG'), // null = KUBECONFIG or ~/.kube/config
'context' => env('KUBERNETES_CONTEXT'), // null = current-context
'namespace' => env('KUBERNETES_NAMESPACE', 'default'),
'manager' => env('KUBERNETES_MANAGER'),
],
],
'client' => [
'options' => [
'timeout' => 5,
],
'stream_timeout' => env('KUBERNETES_STREAM_TIMEOUT', 0),
],
'rate_limits' => [
'enabled' => env('KUBERNETES_RATELIMIT_ENABLED', true),
'owner' => env('KUBERNETES_RATELIMIT_OWNER', 'app'),
'max_attempts' => env('KUBERNETES_RATELIMIT', 400),
'timespan' => env('KUBERNETES_RATELIMIT_TIMESPAN', 'minute'), // second|minute|hour|day
'adaptive' => env('KUBERNETES_RATELIMIT_ADAPTIVE', true), // honour 429 Retry-After
'max_wait' => env('KUBERNETES_RATELIMIT_MAX_WAIT'), // ms; null = pace, set = fail fast
'jitter' => env('KUBERNETES_RATELIMIT_JITTER'), // ms; null = none
],
'traefik' => [
'group' => 'traefik.io/v1alpha1',
],
'resources' => [
'clusterRoles' => Resources\ClusterRole::class,
'clusterRoleBindings' => Resources\ClusterRoleBinding::class,
'configMaps' => Resources\ConfigMap::class,
'cronJobs' => Resources\CronJob::class,
'daemonSets' => Resources\DaemonSet::class,
'deployments' => Resources\Deployment::class,
'endpoints' => Resources\Endpoints::class,
'events' => Resources\Event::class,
'horizontalPodAutoscalers' => Resources\HorizontalPodAutoscaler::class,
'ingresses' => Resources\Ingress::class,
'jobs' => Resources\Job::class,
'limitRanges' => Resources\LimitRange::class,
'namespaces' => Resources\KubernetesNamespace::class,
'networkPolicies' => Resources\NetworkPolicy::class,
'nodes' => Resources\Node::class,
'persistentVolumes' => Resources\PersistentVolume::class,
'persistentVolumeClaims' => Resources\PersistentVolumeClaim::class,
'pods' => Resources\Pod::class,
'replicaSets' => Resources\ReplicaSet::class,
'replicationControllers' => Resources\ReplicationController::class,
'resourceQuotas' => Resources\ResourceQuota::class,
'roles' => Resources\Role::class,
'roleBindings' => Resources\RoleBinding::class,
'secrets' => Resources\Secret::class,
'serviceAccounts' => Resources\ServiceAccount::class,
'services' => Resources\Service::class,
'statefulSets' => Resources\StatefulSet::class,
'storageClasses' => Resources\StorageClass::class,
'traefikIngressRoutes' => Resources\TraefikIngressRoute::class,
'traefikMiddlewares' => Resources\TraefikMiddleware::class,
'traefikServersTransports' => Resources\TraefikServersTransport::class,
'traefikTlsOptions' => Resources\TraefikTlsOption::class,
'traefikTlsStores' => Resources\TraefikTlsStore::class,
],
];Every key
| Key | Env | Default | Purpose |
|---|---|---|---|
default | KUBERNETES_CLUSTER | default | The cluster Kubernetes::pods(), Kubernetes::ping() and every other default-cluster shortcut use — and what kubernetes:ping checks without an argument. |
clusters.<name>.source | KUBERNETES_SOURCE | url | Where the connection comes from: url (the keys below), kubeconfig (a file and context) or in-cluster (the pod’s service account). |
clusters.<name>.url | KUBERNETES_URL | null | The apiserver URL for the url source. |
clusters.<name>.token | KUBERNETES_TOKEN | null | Bearer token. |
clusters.<name>.certificate / private_key / ca_certificate | KUBERNETES_CLIENT_CERTIFICATE · …_CLIENT_KEY · …_CA_CERTIFICATE | null | Paths to the client certificate, its key and the CA bundle. |
clusters.<name>.verify | KUBERNETES_VERIFY_SSL | true | TLS verification. Only turn it off for local development. A blank KUBERNETES_VERIFY_SSL= is not set and keeps verification on. |
clusters.<name>.kubeconfig / context | KUBERNETES_KUBECONFIG · KUBERNETES_CONTEXT | null | For the kubeconfig source: the file (null = KUBECONFIG or ~/.kube/config) and the context (null = current-context). |
clusters.<name>.namespace | KUBERNETES_NAMESPACE | default | The default namespace for namespaced resources on this cluster. |
clusters.<name>.manager | KUBERNETES_MANAGER | null | Your app’s field manager, sent as fieldManager on every write and as the user agent. A server-side apply without one uses kubernetes-api-for-laravel. It doesn’t key the rate-limit budget (that is per apiserver). |
client.options | — | ['timeout' => 5] | Laravel HTTP client options merged into every request the package sends (timeout, proxy, headers…). The timeout — seconds as an int, a float or a numeric string, 0 = none — bounds ordinary requests; for watches and streamLogs() it bounds only connecting and the response headers, and exec() ignores it. |
client.stream_timeout | KUBERNETES_STREAM_TIMEOUT | 0 | Idle timeout for streams in seconds (an integer from 0 to 86400): after this much silence a watch or log follow ends cleanly, and an unfinished exec() reports no exit code. 0 waits indefinitely, like kubectl. |
rate_limits.enabled | KUBERNETES_RATELIMIT_ENABLED | true | Toggle client-side rate limiting; false sends raw, unthrottled requests. |
rate_limits.owner | KUBERNETES_RATELIMIT_OWNER | app | Namespaces the budget key, so several apps or workers can share — or isolate — a cluster budget. |
rate_limits.max_attempts | KUBERNETES_RATELIMIT | 400 | Requests allowed per cluster per window before pacing kicks in — an integer of at least 1. |
rate_limits.timespan | KUBERNETES_RATELIMIT_TIMESPAN | minute | Window length: exactly second, minute, hour or day. A typo such as minutes throws instead of becoming a minute. |
rate_limits.adaptive | KUBERNETES_RATELIMIT_ADAPTIVE | true | Honour the apiserver’s Retry-After header on a 429, self-tuning the limiter. |
rate_limits.max_wait | KUBERNETES_RATELIMIT_MAX_WAIT | null | null paces (waits). A ceiling in ms (0 or more) fails fast with RateLimitExceededException instead. |
rate_limits.jitter | KUBERNETES_RATELIMIT_JITTER | null | Random spread in ms (0 or more) added to each defer, smoothing thundering-herd bursts. |
traefik.group | — | traefik.io/v1alpha1 | API group/version of the bundled Traefik resources; traefik.containo.us/v1alpha1 for Traefik older than v3. |
resources | — | 33 built-in entries | Accessor name → resource class, read at call time. Point a built-in name at your subclass to swap it, or add your own CRDs. Every entry must name a Resource subclass. |
Environment
The default cluster and the rate-limit knobs are env-driven, so you often don’t need to publish the config at all:
KUBERNETES_CLUSTER=default # the default cluster's name
KUBERNETES_SOURCE=url # url | kubeconfig | in-cluster
KUBERNETES_URL=https://api.my-cluster.example:6443
KUBERNETES_TOKEN=service-account-token
KUBERNETES_NAMESPACE=shop # default namespace for namespaced resources
KUBERNETES_MANAGER=shop-app # field manager (fieldManager on writes) and user agent
KUBERNETES_STREAM_TIMEOUT=0 # idle seconds before a watch or log follow ends (0 = never)KUBERNETES_RATELIMIT=400 # attempts per window, per cluster
KUBERNETES_RATELIMIT_TIMESPAN=minute
KUBERNETES_RATELIMIT_ADAPTIVE=true # honour 429 Retry-After
# KUBERNETES_RATELIMIT_MAX_WAIT=2000 # ms — fail fast instead of waiting
# KUBERNETES_RATELIMIT_JITTER=250 # ms of random spread per defer
# KUBERNETES_RATELIMIT_OWNER=app
# KUBERNETES_RATELIMIT_ENABLED=false # the raw, unthrottled clientWhat strict config refuses
Every key is read strictly: nothing falls back to a default except a key that is not set, and a set but invalid value throws an exception naming the key. Blank means not set: an absent key, null and a blank value (a host’s KEY=, empty or whitespace only) all take the default — on the switches too, where a blank is never false.
- Switches — clusters.<name>.verify, rate_limits.enabled and rate_limits.adaptive — accept true/false, 1/0, on/off and yes/no. Anything else throws, so a typo in KUBERNETES_VERIFY_SSL can never switch TLS verification off — and a blank KUBERNETES_VERIFY_SSL= is not set, so verification stays on.
- Numbers take an int or an integer string ('400'): rate_limits.max_attempts (at least 1), rate_limits.max_wait and jitter (0 or more) and client.stream_timeout (0–86400). client.options.timeout also takes a float or a decimal string ('2.5'), 0 or more. 'five', '5.5' for an integer, '5s' or a negative number throws. A blank KUBERNETES_STREAM_TIMEOUT= is the default 0, and a blank max_wait or jitter is unset — never a 0 ms fail-fast ceiling.
- rate_limits.timespan must be exactly second, minute, hour or day — minutes throws instead of becoming a minute.
- Strings — default, a cluster’s url, credential paths, kubeconfig, context, namespace and manager, plus rate_limits.owner and traefik.group — must be strings. A blank env such as KUBERNETES_TOKEN= is not set: no token is sent, exactly as if the line were missing. Likewise KUBERNETES_NAMESPACE= is default and KUBERNETES_CLUSTER= the default cluster. An unknown or non-string source throws; a blank one is url.
- Maps — clusters, each clusters.<name> entry, client.options and resources — must be arrays, and every resources entry must name a Resource subclass.
Cluster and client settings throw ClusterConfigurationException, resources throws InvalidResourceException, and the rate limits and traefik.group throw the toolkit’s InvalidConfigurationException.
The resource map
The typed accessors read the resources map at call time and fall back to the packaged class when their name is missing, so a published resources array only needs the entries you add or swap — the published file lists all 33 for reference. Custom names resolve only while they are in the map. An entry that isn’t a Resource subclass, or a resources value that isn’t an array, throws InvalidResourceException.
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 cryptoBy 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.