|
| 1 | +# Defining CRDs |
| 2 | + |
| 3 | +The ease of using basic Kubernetes resources can be extended into creating CRDs for your custom use case. This needs a lot of context about what you can apply to the resources, based on your needs. |
| 4 | + |
| 5 | +In these examples, we will be looking at the [Traefik CRDs](https://doc.traefik.io/traefik/routing/providers/kubernetes-crd) and [Agones CRDs](https://github.com/googleforgames/agones/tree/main/install/helm/agones/templates/crds). The versions might differ from the actual live Traefik docs, it's just for the example purposes. |
| 6 | + |
| 7 | +# Getting started |
| 8 | + |
| 9 | +Each CRD must extend the `K8sResource` class. This will provide the base PHP API functionalities that you can work with your resource. |
| 10 | + |
| 11 | +Additionally, to be able to interact with the cluster and actually perform operations on it, you should implement the `InteractsWithK8sCluster` interface. |
| 12 | + |
| 13 | + |
| 14 | +The following example will create an `IngressRoute` CRD-ready class for `traefik.containo.us/v1alpha1`: |
| 15 | + |
| 16 | +```php |
| 17 | +use RenokiCo\PhpK8s\Contracts\InteractsWithK8sCluster; |
| 18 | +use RenokiCo\PhpK8s\Kinds\K8sResource; |
| 19 | + |
| 20 | +class IngressRoute extends K8sResource implements InteractsWithK8sCluster |
| 21 | +{ |
| 22 | + /** |
| 23 | + * The resource Kind parameter. |
| 24 | + * |
| 25 | + * @var null|string |
| 26 | + */ |
| 27 | + protected static $kind = 'IngressRoute'; |
| 28 | + |
| 29 | + /** |
| 30 | + * The default version for the resource. |
| 31 | + * |
| 32 | + * @var string |
| 33 | + */ |
| 34 | + protected static $defaultVersion = 'traefik.containo.us/v1alpha1'; |
| 35 | + |
| 36 | + /** |
| 37 | + * Wether the resource has a namespace. |
| 38 | + * |
| 39 | + * @var bool |
| 40 | + */ |
| 41 | + protected static $namespaceable = true; |
| 42 | +} |
| 43 | + |
| 44 | +$ir = new IngressRoute([ |
| 45 | + 'spec' => [ |
| 46 | + 'entryPoints' => ... |
| 47 | + ], |
| 48 | +]); |
| 49 | + |
| 50 | +$ir->create(); |
| 51 | +``` |
| 52 | + |
| 53 | +**For non-namespaceable resources, you shall set the `$namespaceable` variable to `false`.** |
| 54 | + |
| 55 | +## Watchable Resources |
| 56 | + |
| 57 | +Watchable Resources are resources that can access the `/watch` endpoint in order to poll the changes over one or more resources. Typically, this can happen on any resource on which you can run `kubectl get some-crd --watch` upon. |
| 58 | + |
| 59 | +For example, on basic CRDs (the default K8s ones), many resources like Service or Secret come with a watchable implementation. |
| 60 | + |
| 61 | +You can read more about [how to watch a resource](Usage.md#watch-resource). |
| 62 | + |
| 63 | +```php |
| 64 | +use RenokiCo\PhpK8s\Contracts\InteractsWithK8sCluster; |
| 65 | +use RenokiCo\PhpK8s\Contracts\Watchable; |
| 66 | +use RenokiCo\PhpK8s\Kinds\K8sResource; |
| 67 | + |
| 68 | +class IngressRoute extends K8sResource implements InteractsWithK8sCluster, Watchable |
| 69 | +{ |
| 70 | + // |
| 71 | +} |
| 72 | + |
| 73 | +(new IngressRoute)->whereName('foo')->watch(function ($type, $ir) { |
| 74 | + // |
| 75 | +}); |
| 76 | +``` |
| 77 | + |
| 78 | +## Scalable Resources |
| 79 | + |
| 80 | +Scalable resources need a custom API on which you can call scale operations on them. Usually, this is done for resources that open a `/scale` endpoint to the API. |
| 81 | + |
| 82 | +On the default CRDs, this is applied to StatefulSets and Deployments. |
| 83 | + |
| 84 | +You can look on [how StatefulSets are scaled](kinds/StatefulSet.md#scaling) |
| 85 | + |
| 86 | +```php |
| 87 | +use RenokiCo\PhpK8s\Contracts\InteractsWithK8sCluster; |
| 88 | +use RenokiCo\PhpK8s\Contracts\Scalable; |
| 89 | +use RenokiCo\PhpK8s\Kinds\K8sResource; |
| 90 | +use RenokiCo\PhpK8s\Traits\CanScale; |
| 91 | + |
| 92 | +class GameServerSet extends K8sResource implements InteractsWithK8sCluster, Scalable |
| 93 | +{ |
| 94 | + use CanScale; |
| 95 | +} |
| 96 | + |
| 97 | +$scaler = $gameServerSet->scale(3); |
| 98 | +``` |
| 99 | + |
| 100 | +## Podable Resources |
| 101 | + |
| 102 | +Podable resources are resources that manage pods. You can easily get the pods that are ran under the resource. |
| 103 | + |
| 104 | +For example, Jobs and DaemonSets are one of the kinds that have this behaviour. |
| 105 | + |
| 106 | +In PHP, this implementation is a bit tricky and need some configuration on your side: |
| 107 | + |
| 108 | +```php |
| 109 | +use RenokiCo\PhpK8s\Contracts\InteractsWithK8sCluster; |
| 110 | +use RenokiCo\PhpK8s\Contracts\Podable; |
| 111 | +use RenokiCo\PhpK8s\Kinds\K8sResource; |
| 112 | +use RenokiCo\PhpK8s\Traits\HasPods; |
| 113 | + |
| 114 | +class GameServerSet extends K8sResource implements InteractsWithK8sCluster, Podable |
| 115 | +{ |
| 116 | + use HasPods; |
| 117 | + |
| 118 | + /** |
| 119 | + * Get the selector for the pods that are owned by this resource. |
| 120 | + * |
| 121 | + * @return array |
| 122 | + */ |
| 123 | + public function podsSelector(): array |
| 124 | + { |
| 125 | + return [ |
| 126 | + 'game-server-name' => $this->getName(), |
| 127 | + ]; |
| 128 | + } |
| 129 | +} |
| 130 | + |
| 131 | +$gameServerSet = new GameServerSet([ |
| 132 | + 'metadata' => [ |
| 133 | + 'name' => 'some-name', |
| 134 | + ], |
| 135 | + 'spec' => [ |
| 136 | + 'template' => [ |
| 137 | + 'metadata' => [ |
| 138 | + 'labels' => [ |
| 139 | + 'game-server-name' => 'some-name', // this must match |
| 140 | + ], |
| 141 | + ], |
| 142 | + ... |
| 143 | + ], |
| 144 | + ... |
| 145 | + ], |
| 146 | + ... |
| 147 | +]); |
| 148 | + |
| 149 | +foreach ($gameServerSet->getPods() as $pod) { |
| 150 | + // |
| 151 | +} |
| 152 | +``` |
| 153 | + |
| 154 | +As you can see, there is a `podsSelector()` array where you can define a set of labels that a `Pod` managed by this resource needs to have in order to `->getPods()` to work on it. |
| 155 | + |
| 156 | +The labels for the Pod can be defined in the template spec of the resource. [Read more about the pod template definition in StatefulSets](kinds/StatefulSet.md#example) and [how to retrieve pods in StatefulSets](kinds/StatefulSet.md#getting-pods) |
| 157 | + |
| 158 | + |
| 159 | +## Loggable Resources |
| 160 | + |
| 161 | +Loggable resources are resources that expose the `/log` endpoint and can easily get logs, both statically and in a polling request manner. |
| 162 | + |
| 163 | +Check the [documentation on how to watch or get logs](kinds/Pod.md#pod-logs) using Pods. |
| 164 | + |
| 165 | +```php |
| 166 | +use RenokiCo\PhpK8s\Contracts\Loggable; |
| 167 | +use RenokiCo\PhpK8s\Kinds\K8sResource; |
| 168 | + |
| 169 | +class GameServerSet extends K8sResource implements InteractsWithK8sCluster, Loggable |
| 170 | +{ |
| 171 | + // |
| 172 | +} |
| 173 | +``` |
| 174 | + |
| 175 | +# Helper Traits |
| 176 | + |
| 177 | +"Helper Traits" are just traits that make the boring nested variables be easier set with a more friendly way. |
| 178 | + |
| 179 | +You can find some in the [Traits folder](../../tree/master/src/Traits). By default, the `K8sResource` already uses the `HasAttributes` trait. |
| 180 | + |
| 181 | +```php |
| 182 | +use RenokiCo\PhpK8s\Kinds\K8sResource; |
| 183 | +use RenokiCo\PhpK8s\Traits\HasStatus; |
| 184 | + |
| 185 | +class GameServerSet extends K8sResource implements InteractsWithK8sCluster |
| 186 | +{ |
| 187 | + use HasStatus; |
| 188 | +} |
| 189 | + |
| 190 | +$gameServerSet->getStatus('some.path'); |
| 191 | +``` |
0 commit comments