Workload resources add typed setters for their spec and readable getters for their status. A deployment’s health at a glance:
$checkout = $cluster->deployments()->setNamespace('shop')->withName('checkout')->find();
$checkout->getReplicas(); // spec.replicas
$checkout->getReadyReplicasCount(); // status.readyReplicas
$checkout->getAvailableReplicasCount(); // status.availableReplicas
$checkout->getUnavailableReplicasCount(); // status.unavailableReplicas
$checkout->getDesiredReplicasCount(); // status.replicas
$checkout->getConditions(); // status.conditions
$checkout->getPodsSelectors(); // spec.selector.matchLabels
$checkout->getTemplate(); // the pod template as a Pod
$checkout->getUpdateStrategy(); // spec.strategy
// Tweak and write back
$checkout->setMinReadySeconds(10)->setReplicas(6)->update();
// spec.strategy — RollingUpdate (with its surge limits) or Recreate
$checkout->setUpdateStrategy('RollingUpdate', maxUnavailable: '0', maxSurge: '1')->update();setPodsSelectors() writes spec.selector.matchLabels on deployments, daemon sets and replica sets, and the flat selector map on replication controllers. The apiserver refuses an empty selector on apps/v1 workloads, so always give them at least one label. setTemplate() takes a Pod and sends only its metadata and spec; or set spec.template directly with setSpec() as in the examples below.
StatefulSets
Stable network identity comes from setServiceName(); per-replica storage from PersistentVolumeClaimTemplate objects:
use RoundlyConsulting\KubernetesApi\Resources\Types\PersistentVolumeClaimTemplate;
$cluster->statefulSets()
->setNamespace('shop')
->setName('search')
->setServiceName('search')
->setReplicas(3)
->setSpec('selector.matchLabels', ['app' => 'search'])
->setSpec('template', [
'metadata' => ['labels' => ['app' => 'search']],
'spec' => ['containers' => [['name' => 'search', 'image' => 'registry.example.com/search:v2.1.0']]],
])
->setVolumeClaimTemplates([
PersistentVolumeClaimTemplate::make()
->setName('data')
->setAccessModes(['ReadWriteOnce'])
->setStorageClassName('fast-ssd')
->setStorageRequest('20Gi'),
])
->create();
$search = $cluster->statefulSets()->setNamespace('shop')->withName('search')->find();
$search->getReadyReplicasCount();
$search->getCurrentReplicasCount();
$search->getUpdatedReplicasCount();DaemonSets
$cluster->daemonSets()
->setNamespace('monitoring')
->setName('node-agent')
->setPodsSelectors(['app' => 'node-agent'])
->setUpdateStrategy('RollingUpdate', maxUnavailable: '2') // or 'OnDelete'
->setSpec('template', [
'metadata' => ['labels' => ['app' => 'node-agent']],
'spec' => ['containers' => [['name' => 'agent', 'image' => 'registry.example.com/node-agent:v3.0.2']]],
])
->create();
$agent = $cluster->daemonSets()->setNamespace('monitoring')->withName('node-agent')->find();
$agent->getDesiredNumberScheduled();
$agent->getCurrentNumberScheduled();
$agent->getNumberReady();
$agent->getNumberAvailable();ReplicaSets offer setPodsSelectors(), getReadyReplicasCount(), getAvailableReplicasCount() and getFullyLabeledReplicasCount(); replication controllers the first three.
Jobs
Launch one-off work — data migrations, backups, reports — and check back when it finishes:
$cluster->jobs()
->setNamespace('shop')
->setName('reindex-catalogue')
->setTtl(3600) // ttlSecondsAfterFinished
->setSpec('template', [
'spec' => [
'restartPolicy' => 'Never',
'containers' => [[
'name' => 'reindex',
'image' => 'registry.example.com/shop-cli:v1.4.0',
'command' => ['php', 'artisan', 'catalogue:reindex'],
]],
],
])
->create();
// Later — for example from a queued job
$job = $cluster->jobs()->setNamespace('shop')->withName('reindex-catalogue')->find();
$job->hasCompleted(); // status.completionTime is set
$job->getActivePodsCount();
$job->getSucceededPodsCount();
$job->getFailedPodsCount();
$job->getStartTime(); // ?Carbon
$job->getDurationInSeconds();
$job->getStatusMessage();
// The job's pods carry the job-name label
$cluster->pods()->setNamespace('shop')->whereLabel('job-name', $job->getName())->get();
$job->podsSelectors(); // ['job-name' => 'reindex-catalogue']CronJobs
$cluster->cronJobs()
->setNamespace('shop')
->setName('nightly-report')
->setSchedule('0 3 * * *')
->setConcurrencyPolicy('Forbid') // default 'Allow'
->setSuccessfulJobsHistoryLimit(3)
->setFailedJobsHistoryLimit(1)
->setSpec('jobTemplate', [
'spec' => [
'template' => [
'spec' => [
'restartPolicy' => 'Never',
'containers' => [[
'name' => 'report',
'image' => 'registry.example.com/shop-cli:v1.4.0',
'command' => ['php', 'artisan', 'reports:nightly'],
]],
],
],
],
])
->create();
$report = $cluster->cronJobs()->setNamespace('shop')->withName('nightly-report')->find();
$report->getSchedule(); // '0 3 * * *'
$report->getLastScheduleTime(); // ?Carbon
$report->getLastSuccessfulTime(); // ?Carbon
// Pause it
$report->suspend()->update();
$report->isSuspended(); // truesetJobTemplate() also accepts a Job, and getJobTemplate() returns one. The history limits read back as 3 and 1 when unset.
Horizontal pod autoscalers
$cluster->horizontalPodAutoscalers()
->setNamespace('shop')
->setName('checkout')
->setScaleTargetRef('Deployment', 'checkout') // apiVersion defaults to apps/v1
->setMinReplicas(2)
->setMaxReplicas(10)
->setSpec('metrics', [[
'type' => 'Resource',
'resource' => ['name' => 'cpu', 'target' => ['type' => 'Utilization', 'averageUtilization' => 70]],
]])
->create();
$hpa = $cluster->horizontalPodAutoscalers()->setNamespace('shop')->withName('checkout')->find();
$hpa->getCurrentReplicas();
$hpa->getDesiredReplicas();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.