---
title: "Building resources with value objects — Kubernetes API | Roundly"
description: "Compose pods and services from typed Container, Port, Probe, Volume, VolumeMount and claim-template objects instead of raw arrays."
url: https://roundly-consulting.com/open-source/docs/kubernetes-api-for-laravel/value-objects
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)

# Building resources with value objects

Resources compose from typed value objects in RoundlyConsulting\\KubernetesApi\\Resources\\Types, each serialising to the exact shape the apiserver expects. A pod with probes, resources, environment and volumes:

```php
use RoundlyConsulting\KubernetesApi\Resources\ConfigMap;
use RoundlyConsulting\KubernetesApi\Resources\Secret;
use RoundlyConsulting\KubernetesApi\Resources\Types\Container;
use RoundlyConsulting\KubernetesApi\Resources\Types\Probe;
use RoundlyConsulting\KubernetesApi\Resources\Types\Volume;

$configVolume = Volume::make()->fromConfigMap(ConfigMap::make()->setName('checkout-config'));
$tlsVolume = Volume::make()->fromSecret(Secret::make()->setName('checkout-tls'));
$cacheVolume = Volume::make()->emptyDirectory('cache', ['sizeLimit' => '500Mi']);

$app = Container::make()
    ->setName('app')
    ->setImage('registry.example.com/checkout', 'v1.4.0')
    ->addPort(8080, 'TCP', 'http')
    ->setEnvironment(['APP_ENV' => 'production', 'LOG_CHANNEL' => 'stderr'])
    ->addToEnvironmentFromSecret('DB_PASSWORD', 'checkout-db', 'password')
    ->addToEnvironmentFromConfigMap('FEATURE_FLAGS', 'checkout-config', 'flags')
    ->addToEnvironmentFromFieldReference('POD_NAME', 'metadata.name')
    ->setMinimumCpu('250m')
    ->setMaximumCpu('1')
    ->setMinimumMemory(256, 'Mi')
    ->setMaximumMemory(512, 'Mi')
    ->setReadinessProbe(Probe::http('/healthz', 8080))
    ->setLivenessProbe(Probe::tcp(8080))
    ->addVolumeMount($configVolume->mountTo('/etc/checkout'))
    ->addVolumeMount($tlsVolume->mountTo('/etc/tls'))
    ->addVolumeMount($cacheVolume->mountTo('/var/cache/checkout'));

$pod = $cluster->pods()
    ->setNamespace('shop')
    ->setName('checkout-debug')
    ->setLabels(['app' => 'checkout', 'purpose' => 'debug'])
    ->setContainers([$app])
    ->addVolumes([$configVolume, $tlsVolume, $cacheVolume])
    ->addImagePullSecret('registry-credentials')
    ->create();
```

## Container

| Method | Writes |
| --- | --- |
| `setImage($image, ?string $tag = 'latest')` | image as image:tag. A reference that already carries a tag (nginx:1.27) or a digest (nginx@sha256:…) is kept as given, and a null tag leaves the image untagged. A registry port is not a tag: registry.local:5000/app becomes …/app:latest. |
| `addPort($containerPort, $protocol = 'TCP', $name = null)` | ports\[\]. |
| `setEnvironment([...]) · addToEnvironment($name, $value) · addMultipleToEnvironment([...])` | env\[\] — setEnvironment() replaces the list. |
| `addToEnvironmentFromSecret($name, $secretName, $key = null)` | env\[\].valueFrom.secretKeyRef — the key defaults to the secret name. |
| `addToEnvironmentFromConfigMap($name, $configMapName, $key)` | env\[\].valueFrom.configMapKeyRef. |
| `addToEnvironmentFromFieldReference($name, $fieldPath)` | env\[\].valueFrom.fieldRef. |
| `setMinimumCpu($size) / setMaximumCpu($size)` | resources.requests.cpu / resources.limits.cpu. |
| `setMinimumMemory($size, $measure = 'Gi') / setMaximumMemory(…)` | resources.requests.memory / resources.limits.memory. |
| `setReadinessProbe() · setLivenessProbe() · setStartupProbe()` | The three probes, from a Probe. |
| `addVolumeMount() · addVolumeMounts() · setVolumeMounts()` | volumeMounts\[\], from VolumeMount objects. |

The plural forms take maps: addToEnvironmentFromSecrets(\['DB\_PASSWORD' => \['checkout-db', 'password'\]\]), addToEnvironmentFromConfigMaps(\['FLAGS' => \['checkout-config', 'flags'\]\]) and addToEnvironmentFromFieldReferences(\['POD\_NAME' => 'metadata.name'\]). Anything else — command, args, imagePullPolicy — goes through the magic setters.

## Probes

Probe::http(), Probe::tcp() and command() build the three probe kinds. Tune thresholds and timings, or any other probe field, with the magic setters:

```php
use RoundlyConsulting\KubernetesApi\Resources\Types\Probe;

Probe::http('/healthz', 8080);                                  // httpGet, scheme HTTP
Probe::http('/ready', 8443, ['X-Probe' => 'kubelet'], 'HTTPS'); // headers + scheme
Probe::tcp(5432);                                               // tcpSocket
Probe::make()->command(['pg_isready', '-U', 'shop']);           // exec

// Every probe starts with failureThreshold: 1 and successThreshold: 1
Probe::http('/healthz', 8080)
    ->setFailureThreshold(3)
    ->setPeriodSeconds(10)
    ->setInitialDelaySeconds(5);
```

## Volumes, mounts and ports

- Volume::fromConfigMap() and fromSecret() name the volume after its source — checkout-config-config-volume, checkout-tls-secret-volume — made a valid DNS-1123 label (dots become hyphens, cut to 63 characters), or take the volume name as a second argument: fromSecret($secret, 'tls'). Pass one when two long names share their start. An unnamed source throws InvalidResourceException.
- emptyDirectory($name, $options) adds an emptyDir volume; pass its options, such as sizeLimit — without any it sends emptyDir: {}.
- mountTo($mountPath, $subPath = null) turns any volume into a VolumeMount with the matching name.
- Pod takes them through setContainers(), setInitContainers(), addVolume(s)(), setVolumes() and addImagePullSecret(s)(), and reads them back as objects with getContainers(), getInitContainers() and getVolumes().
- Port::http($containerPort = 80) builds a TCP service port 80 targeting the container port; build other ports with Port::make() and the magic setters.
- PersistentVolumeClaimTemplate describes a stateful set’s per-replica claim — see Workloads.

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