- Project: PHP client for Kubernetes clusters with HTTP/WebSocket support, CRD ergonomics, exec/logs/watch, and JSON Patch/Merge Patch.
- Audience: Human contributors and code agents working on features, fixes, or docs.
src/KubernetesCluster.php: Core client; builds URLs, performs operations (get/create/replace/delete, exec, attach, watch, logs, patch).src/Kinds/*: First‑class resource wrappers (Pod, Deployment, Service, …) extendingK8sResourcewith convenience traits.src/Traits/Cluster/*: HTTP/WebSocket, auth, kubeconfig loaders, version checks.src/Auth/*: Token providers (ExecCredential, EKS, OpenShift OAuth, ServiceAccount TokenRequest) with automatic refresh.src/Traits/Resource/*: Reusable capabilities (spec/status/labels/annotations/templates/scale/etc.).src/K8s.php: Facade/helper for resource construction, YAML parsing, and CRD registration via macros.src/Patches/*:JsonPatch(RFC 6902) andJsonMergePatch(RFC 7396).tests/*: PHPUnit tests (unit + integration) including testing‑only CRDs undertests/Kinds.
This project uses Laravel Pint with the Laravel preset to enforce PSR-12 coding standards.
CRITICAL: Always run Pint before committing PHP code changes:
./vendor/bin/pintPint auto-fixes:
- String concatenation spacing (no spaces around
.) - Negation operator spacing (space after
!) - Trailing commas in multiline arrays
- Doc block formatting
- Use statement ordering
- Class definition formatting
- PSR-12 compliance
Manual checks after running Pint:
- Doc comments must end with periods:
/** Comment. */ - No blank lines before
finallyblocks
If StyleCI reports issues on PR:
- Run
./vendor/bin/pint - Fix any remaining manual issues
- Commit and push fixes
- PHP:
^8.3(CI also exercises 8.5). - Composer deps: Guzzle 7, Symfony Process 7.3, Illuminate components, Ratchet Pawl, ext‑json; optional
ext-yamlfor YAML helpers, optionalaws/aws-sdk-phpfor native EKS authentication. - Static analysis: Psalm (see
psalm.xml). - License: Apache‑2.0.
- Authentication: Supports tokens, certificates, kubeconfig, in-cluster config, exec credential plugins, AWS EKS native, OpenShift OAuth, and ServiceAccount TokenRequest API.
- Install deps:
composer install. - Update deps:
composer update. - Run all tests:
vendor/bin/phpunit. - Run tests (unit only):
vendor/bin/phpunit --filter Test$(or target specific files) to avoid cluster requirements. - Run specific test file:
vendor/bin/phpunit tests/PriorityClassTest.php. - Run specific test method:
vendor/bin/phpunit tests/PriorityClassTest.php --filter test_priority_class_build. - Run with CI environment:
CI=true vendor/bin/phpunit(requires running Kubernetes cluster). - Static analysis:
vendor/bin/psalm. - Coding style: Run
./vendor/bin/pintbefore all commits (see "Code Style Requirements" above).
These hit a live Kubernetes cluster and mirror CI.
- Start cluster: Minikube is the reference. Example:
minikube start --kubernetes-version=v1.34.6. - Enable addons:
minikube addons enable volumesnapshots && minikube addons enable csi-hostpath-driver && minikube addons enable metrics-server. - Install VPA: Clone
kubernetes/autoscalerand run./vertical-pod-autoscaler/hack/vpa-up.sh. Alternatively:git clone https://github.com/kubernetes/autoscaler.git /tmp/autoscaler kubectl apply -f /tmp/autoscaler/vertical-pod-autoscaler/deploy/vpa-v1-crd-gen.yaml kubectl apply -f /tmp/autoscaler/vertical-pod-autoscaler/deploy/recommender-deployment.yaml kubectl apply -f /tmp/autoscaler/vertical-pod-autoscaler/deploy/updater-deployment.yaml kubectl apply -f /tmp/autoscaler/vertical-pod-autoscaler/deploy/admission-controller-deployment.yaml
- Install CRDs:
- Sealed Secrets CRD:
kubectl apply -f https://raw.githubusercontent.com/bitnami-labs/sealed-secrets/main/helm/sealed-secrets/crds/bitnami.com_sealedsecrets.yaml - Gateway API:
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.3.0/standard-install.yaml
- Sealed Secrets CRD:
- Expose API:
kubectl proxy --port=8080 --reject-paths="^/non-existent-path" &(tests usehttp://127.0.0.1:8080). - Verify connectivity:
curl -s http://127.0.0.1:8080/version. - Run tests:
CI=true vendor/bin/phpunit. - Important: Tests expect the Kubernetes API accessible at
http://127.0.0.1:8080(seetests/TestCase.php).
- Resources: Each kind extends
Kinds\K8sResourceand composes traits fromTraits\Resourcefor spec/status/metadata helpers.- Resource pattern:
K8sResource(base) → Uses Traits (HasSpec, HasStatus, etc.) → Implements Contracts (InteractsWithK8sCluster, Watchable, etc.) → Extended by specific classes (K8sPod, K8sDeployment, etc.) - Namespaced resources: Set
protected static $namespaceable = true(most resources) - Cluster-scoped resources: Set
protected static $namespaceable = false(nodes, PriorityClass, ClusterRole, etc.)
- Resource pattern:
- Traits: Provide composable functionality (
src/Traits/Resource/)HasSpec- Manage spec section (most resources)HasStatus- Read-only status informationHasSelector- Label/field selectorsHasMetadata- Labels, annotations, name, namespaceHasReplicas- Replica management (Deployments, StatefulSets, ReplicaSets)HasPodTemplate- Pod template spec (workload resources)HasStorage- Storage configuration (PVCs, PVs)
- Contracts (Interfaces): Define capabilities (
src/Contracts/)InteractsWithK8sCluster- Basic CRUD operations (get, create, update, delete)Watchable- Watch operations (event streaming)Scalable- Scale subresource supportLoggable- Log retrieval (pods, jobs)Executable- Exec operations (pods)
- Cluster Ops:
KubernetesClusterprovides typed creators/getters (e.g.,pod(),getPodByName(),getAllPods()), plusexec,attach,watch,logs, and patch operations. - YAML helpers:
K8s::fromYaml($cluster, $yaml)andK8s::fromYamlFile($cluster, $path)create object(s) from YAML. Templating is supported viafromTemplatedYamlFile. - CRDs: Register custom kinds at runtime with
K8s::registerCrd(YourClass::class, 'alias')or rely on the unique CRD macro computed from kind + apiVersion. - Patching: Use
$resource->jsonPatch($patch)or$resource->jsonMergePatch($patch)withPatches\JsonPatch/JsonMergePatchor raw arrays. - State tracking:
isSynced()- resource has been synced with cluster;exists()- resource currently exists in cluster.
-
Add a new built-in kind:
- Create
src/Kinds/K8sYourKind.phpextendingK8sResource:<?php namespace RenokiCo\PhpK8s\Kinds; use RenokiCo\PhpK8s\Contracts\InteractsWithK8sCluster; class K8sYourKind extends K8sResource implements InteractsWithK8sCluster { protected static $kind = 'YourKind'; protected static $defaultVersion = 'v1'; // or appropriate apiVersion protected static $namespaceable = true; // or false for cluster-scoped // Add resource-specific methods }
- Add factory method in
src/Traits/InitializesResources.php:public static function yourKind($cluster = null, array $attributes = []) { return new K8sYourKind($cluster, $attributes); }
- Create test file
tests/YourKindTest.phpwith:- Unit tests:
test_your_kind_build(),test_your_kind_from_yaml() - Integration test:
test_your_kind_api_interaction() - Run methods:
runCreationTests(),runGetAllTests(),runGetTests(),runUpdateTests(),runWatchAllTests(),runWatchTests(),runDeletionTests() - Note: Cluster-scoped resources typically omit watch tests
- Unit tests:
- Create YAML fixture in
tests/yaml/yourkind.yamlfor YAML parsing tests - Document the resource (REQUIRED):
# Generate documentation stub (determines category from class name or specify manually) php scripts/generate-resource-doc.php K8sYourKind category # Edit generated file: docs/resources/category/yourkind.yaml.md # Add to sidebar in docs/.vitepress/config.mjs # Verify: npm run docs:build
- Create
-
Test structure: (
tests/TestCase.phpsets up cluster athttp://127.0.0.1:8080)- Build test: Verify resource construction with fluent API
- YAML test: Load and validate from YAML file
- API interaction test: Orchestrate full CRUD lifecycle
- Creation tests: Create resource, verify
isSynced()andexists() - Deletion tests: Delete resource, wait for deletion, expect
KubernetesAPIExceptionon get
-
Add support for a CRD (without bundling it):
- Create a kind class under
tests/Kinds(for testing) or a separate package. - Register with
K8s::registerCrd(...)in tests or userland. - Provide YAML examples for
K8s::fromYaml*()parsing.
- Create a kind class under
-
Extend cluster operations: Add behavior in
Traits/Cluster/*orTraits/RunsClusterOperations.phpwith matching tests.
- VitePress setup: Documentation is in
docs/with config atdocs/.vitepress/config.mjs. Deployed tohttps://php-k8s.cuppett.devvia GitHub Actions. - Local preview:
npm install(once), thennpm run docs:dev(opens http://localhost:5173). - Build check:
npm run docs:buildto verify docs compile (required before commits touching docs). - Adding new resource docs:
- Generate stub:
php scripts/generate-resource-doc.php K8sYourKind category - Edit generated
docs/resources/category/yourkind.mdusing the template as a guide - Add to sidebar in
docs/.vitepress/config.mjsunder the appropriate section - Build and verify:
npm run docs:buildandnpm run docs:dev
- Generate stub:
- Documentation coverage check: Run
php scripts/check-documentation.phpbefore PRs to ensure all resources are documented. - Templates: Use
docs/_templates/resource-template.mdordocs/_templates/example-template.mdfor new pages. - Attribution: Adapted upstream pages include footer:
*Originally from renoki-co/php-k8s documentation, adapted for cuppett/php-k8s fork*. New fork-only pages use:*Documentation for cuppett/php-k8s fork*. - Deployment: Documentation auto-deploys when changes to
docs/**are merged tomain. See.github/workflows/docs-deploy.yml. - See also:
DOCS_README.mdfor full documentation system overview,docs/development/documentation.mdfor maintenance guide.
- Tests first: Add/adjust tests for all behavior changes. Use PHPUnit; integration tests may require a live cluster.
- API stability: Follow SemVer; avoid breaking public APIs. Prefer additive changes.
- Consistency: Mirror naming and patterns used by existing kinds and traits. Keep methods fluent and chainable where appropriate.
- Docs: Update
README.mdand/or add focused docs indocs/for new features. Keep examples runnable. - Static analysis: Keep Psalm clean (config at
psalm.xml).
- Code style: Run
./vendor/bin/pintand fix any manual style issues before committing. composer installcompletes andvendor/bin/psalmpasses.vendor/bin/phpunitpasses for unit tests; integration suite passes if you ran a local cluster.- Documentation complete:
- New resources have documentation:
php scripts/check-documentation.php - Documentation builds successfully:
npm run docs:build - Sidebar updated in
docs/.vitepress/config.mjsif new pages added - Code examples in docs are tested and work
- Attribution footer present on all pages
- New resources have documentation:
- Public APIs documented; new options/settings covered with tests and examples.
- Changes are scoped; one concern per PR.
- Cluster URL: Tests default to
http://127.0.0.1:8080viakubectl proxyand disable SSL verification for local runs. - Namespace handling: Cluster-scoped resources (
$namespaceable = false) should not include namespace in specs or API calls. - YAML extension:
ext-yamlis optional but required for YAML helpers (parsing/serialization). Guard features accordingly. Tests usingfromYamlFile()will fail without the yaml PHP extension installed. - kubectl Proxy: Integration tests expect proxy on
http://127.0.0.1:8080- verify withcurl http://127.0.0.1:8080/version. - Watch tests: Cluster-scoped resources typically don't implement watch tests (pattern varies).
- Status vs Spec: Status is read-only from API; modifications go in spec section.
- WebSockets: Exec/attach/watch rely on Ratchet Pawl; ensure TLS headers/certs are passed through from
KubernetesClusterwhen touching WS paths. - Patches: Use proper content types (
application/json-patch+jsonvsapplication/merge-patch+json). The client handles this if you use the provided patch helpers.
- Workload: Pod, Deployment, StatefulSet, DaemonSet, Job, CronJob, ReplicaSet
- Networking: Service, Ingress, NetworkPolicy, EndpointSlice
- Storage: PersistentVolume, PersistentVolumeClaim, StorageClass
- Configuration: ConfigMap, Secret
- Autoscaling: HorizontalPodAutoscaler, VerticalPodAutoscaler
- Policy: ResourceQuota, LimitRange, PodDisruptionBudget, NetworkPolicy, PriorityClass
- RBAC: ServiceAccount, Role, ClusterRole, RoleBinding, ClusterRoleBinding
- Webhooks: ValidatingWebhookConfiguration, MutatingWebhookConfiguration
- Cluster: Namespace, Node, Event
- Core resources (Pod, Service, etc.):
v1 - Apps resources (Deployment, StatefulSet, etc.):
apps/v1 - Networking:
networking.k8s.io/v1 - Autoscaling:
autoscaling/v2(HPA),autoscaling.k8s.io/v1(VPA) - Scheduling:
scheduling.k8s.io/v1 - Policy:
policy/v1 - RBAC:
rbac.authorization.k8s.io/v1
- Main branch:
master(upstream: renoki-co/php-k8s) - Fork:
cuppett/php-k8swith branchmain - Feature branches: Use descriptive names (e.g.,
feat/add-core-policy-resources) - Pull request process:
- Create feature branch from current working branch
- Implement changes following existing patterns
- Run full test suite locally:
vendor/bin/phpunit - Run integration tests with minikube:
CI=true vendor/bin/phpunit - Commit changes with descriptive message
- Push to fork:
git push -u origin {branch-name} - Create PR against
cuppett/php-k8smain branch:gh pr create --repo cuppett/php-k8s --base main --title "..." --body "..."
- CI matrix runs PHP 8.3-8.5 across Kubernetes v1.33.10, v1.34.6, v1.35.3 and Laravel 12/13 with both
prefer-lowestandprefer-stable. - Minikube v1.37.0 is provisioned in CI with VolumeSnapshots, CSI hostpath, metrics‑server, VPA, Sealed Secrets CRD, and Gateway API CRDs before running tests.
- Timeout: 25 minutes per job.
- Fork Documentation: https://php-k8s.cuppett.dev
- Upstream Documentation: https://php-k8s.renoki.org
- Fork Repository: https://github.com/cuppett/php-k8s
- Upstream Repository: https://github.com/renoki-co/php-k8s
- Kubernetes API Reference: https://kubernetes.io/docs/reference/kubernetes-api/
If anything is unclear or you need deeper context for a change, open a draft PR with your approach and questions. Keeping changes small and well‑tested speeds up reviews.