---
title: "Workloads — Kubernetes API for Laravel | Roundly"
description: "Deployments, stateful sets, daemon sets, replica sets, jobs, cron jobs and autoscalers — typed setters and readable status helpers."
url: https://roundly-consulting.com/open-source/docs/kubernetes-api-for-laravel/workloads
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)

# Workloads

Workload resources add typed setters for their spec and readable getters for their status. A deployment’s health at a glance:

```php
$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:

```php
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

```php
$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:

```php
$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

```php
$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();             // true
```

setJobTemplate() also accepts a Job, and getJobTemplate() returns one. The history limits read back as 3 and 1 when unset.

## Horizontal pod autoscalers

```php
$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 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)
