Storage, RBAC & cluster objects
Namespaces
// Provision an isolated namespace per tenant
$cluster->namespaces()
->setName('tenant-acme')
->setLabels(['example.com/tenant' => 'acme'])
->create();
$tenant = $cluster->namespaces()->withName('tenant-acme')->find();
$tenant->isActive(); // status.phase === 'Active'
$tenant->isTerminating(); // status.phase === 'Terminating'Nodes, events and endpoints
Read-mostly objects come with getters for the fields you actually look at. Events also offer getType(), isNormal() and getFirstTimestamp(); endpoints getSubsets() and getSubset($index):
use RoundlyConsulting\KubernetesApi\Resources\Event;
foreach ($cluster->nodes()->get() as $node) {
$node->getName();
$node->getInfo(); // status.nodeInfo
$node->getCapacity(); // status.capacity
$node->getAllocatableInfo(); // status.allocatable
$node->getImages(); // status.images
}
// Warnings about one object, straight from the event log
$warnings = $cluster->events()
->setNamespace('shop')
->whereField('involvedObject.name', 'checkout-5f7c9d8b6-x2kqj')
->get()
->filter(fn (Event $event): bool => $event->isWarning());
foreach ($warnings as $event) {
$event->getReason(); // e.g. 'BackOff'
$event->getMessage();
$event->getCount();
$event->getLastTimestamp(); // ?Carbon
$event->getInvolvedObject(); // kind, name, namespace…
}
// Ready addresses behind a service
$endpoints = $cluster->endpoints()->setNamespace('shop')->withName('checkout')->find();
$endpoints->getReadyAddresses(); // pod IPs
$endpoints->getPorts(); // [8080]Storage
Volumes and claims share setAccessModes(), setStorageClassName() and setCapacity($size, $measure = 'Gi'), plus isBound() and isAvailable() from status.phase:
// A claim for 10 GiB on a storage class
$cluster->persistentVolumeClaims()
->setNamespace('shop')
->setName('uploads')
->setAccessModes(['ReadWriteOnce'])
->setStorageClassName('fast-ssd')
->setCapacity(10, 'Gi') // spec.resources.requests.storage = 10Gi
->create();
$cluster->persistentVolumeClaims()->setNamespace('shop')->withName('uploads')->find()->isBound();
// A storage class
$cluster->storageClasses()
->setName('fast-ssd')
->setProvisioner('csi.example.com') // magic setter -> provisioner
->setParameters(['type' => 'ssd'])
->setMountOptions(['noatime'])
->create();
// A pre-provisioned NFS volume
$cluster->persistentVolumes()
->setName('shared-media')
->setCapacity(100, 'Gi') // spec.capacity.storage = 100Gi
->setAccessModes(['ReadWriteMany'])
->setStorageClassName('nfs')
->setMountOptions(['nfsvers=4.1'])
->setSpec('nfs', ['server' => 'nfs.example.com', 'path' => '/exports/media'])
->create();RBAC and service accounts
// A service account for your deploy tooling
$cluster->serviceAccounts()
->setNamespace('shop')
->setName('deployer')
->addImagePullSecret('registry-credentials')
->setAutomountServiceAccountToken(false)
->create();
// What it may do in the namespace
$cluster->roles()
->setNamespace('shop')
->setName('deployer')
->addRule(['apps'], ['deployments', 'deployments/scale'], ['get', 'list', 'patch'])
->addRule([''], ['pods', 'pods/log'], ['get', 'list'])
->create();
$cluster->roleBindings()
->setNamespace('shop')
->setName('deployer')
->setRoleRef('deployer') // kind defaults to Role
->addSubject('ServiceAccount', 'deployer', 'shop')
->addSubject('User', '[email protected]')
->create();
// Cluster-wide
$cluster->clusterRoles()
->setName('node-reader')
->addRule([''], ['nodes'], ['get', 'list', 'watch'])
->create();
$cluster->clusterRoleBindings()
->setName('deployer-node-reader')
->setRoleRef('node-reader') // always a ClusterRole
->addSubject('ServiceAccount', 'deployer', 'shop')
->create();addRule($apiGroups, $resources, $verbs) appends a rule. addSubject($kind, $name, $namespace = null) adds the namespace for a ServiceAccount subject and the rbac.authorization.k8s.io API group for users and groups. RoleBinding::setRoleRef() takes an optional kind, so a role binding can reference a ClusterRole.
Quotas and limit ranges
$cluster->resourceQuotas()
->setNamespace('tenant-acme')
->setName('compute')
->setHard(['pods' => '20', 'requests.cpu' => '4', 'requests.memory' => '8Gi'])
->create();
$quota = $cluster->resourceQuotas()->setNamespace('tenant-acme')->withName('compute')->find();
$quota->getHard(); // the limits you set
$quota->getUsed(); // current usage from status.used
$cluster->limitRanges()
->setNamespace('tenant-acme')
->setName('defaults')
->addLimit([
'type' => 'Container',
'default' => ['cpu' => '500m', 'memory' => '512Mi'],
'defaultRequest' => ['cpu' => '100m', 'memory' => '128Mi'],
])
->create();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.