Skip to content

Commit d847101

Browse files
committed
docs draft from AI rerendered shell-operator docs
Signed-off-by: Pavel Okhlopkov <[email protected]>
1 parent 48be155 commit d847101

File tree

6 files changed

+1266
-0
lines changed

6 files changed

+1266
-0
lines changed

docs/book.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[book]
2+
authors = ["The Shell-Operator Maintainers"]
3+
language = "en"
4+
multilingual = false
5+
src = "src"
6+
title = "Shell-operator"
7+
8+
[output.html]
9+
curly-quotes = true
10+
git-repository-url = "https://github.com/flant/shell-operator"

docs/src/HOOKS.md

Lines changed: 838 additions & 0 deletions
Large diffs are not rendered by default.

docs/src/KUBERNETES.md

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
# Modifying Kubernetes objects
2+
3+
You can delegate Kubernetes object manipulation to the module-sdk.
4+
5+
To do this, you have to write one or more JSON or YAML documents describing operation type and its parameters to a file.
6+
List of possible operations and corresponding JSON specifications can be found below.
7+
8+
The path to the file is found in the `$KUBERNETES_PATCH_PATH` environment variable.
9+
10+
## Operations
11+
12+
### Create
13+
14+
* `operation` — specifies an operation's type.
15+
* `CreateOrUpdate` — accept a Kubernetes object.
16+
It retrieves an object, and if it already exists, computes a JSON Merge Patch and applies it (will not update .status field).
17+
If it does not exist, we create the object.
18+
* `Create` — will fail if an object already exists
19+
* `CreateIfNotExists` — create an object if such an object does not already
20+
exist by namespace/name.
21+
* `object` — full object specification including "apiVersion", "kind" and all necessary metadata. Can be a normal JSON or YAML object or a stringified JSON or YAML object.
22+
23+
#### Example
24+
25+
```json
26+
{
27+
"operation": "CreateOrUpdate",
28+
"object": {
29+
"apiVersion": "apps/v1",
30+
"kind": "DaemonSet",
31+
"metadata": {
32+
"name": "flannel",
33+
"namespace": "d8-flannel"
34+
},
35+
"spec": {
36+
"selector": {
37+
"matchLabels": {
38+
"app": "flannel"
39+
}
40+
},
41+
"template": {
42+
"metadata": {
43+
"labels": {
44+
"app": "flannel",
45+
"tier": "node"
46+
}
47+
},
48+
"spec": {
49+
"containers": [
50+
{
51+
"args": [
52+
"--ip-masq",
53+
"--kube-subnet-mgr"
54+
],
55+
"image": "flannel:v0.11",
56+
"name": "kube-flannel",
57+
"securityContext": {
58+
"privileged": true
59+
}
60+
}
61+
],
62+
"hostNetwork": true,
63+
"imagePullSecrets": [
64+
{
65+
"name": "registry"
66+
}
67+
],
68+
"terminationGracePeriodSeconds": 5
69+
}
70+
},
71+
"updateStrategy": {
72+
"type": "RollingUpdate"
73+
}
74+
}
75+
}
76+
}
77+
```
78+
79+
```yaml
80+
operation: Create
81+
object:
82+
apiVersion: v1
83+
kind: ConfigMap
84+
metadata:
85+
namespace: default
86+
name: testcm
87+
data: ...
88+
```
89+
90+
```yaml
91+
operation: Create
92+
object: |
93+
{"apiVersion":"v1", "kind":"ConfigMap",
94+
"metadata":{"namespace":"default","name":"testcm"},
95+
"data":{"foo": "bar"}}
96+
```
97+
98+
### Delete
99+
100+
* `operation` — specifies an operation's type. Deletion types map directly to Kubernetes
101+
DELETE's [`propagationPolicy`][controller-gc].
102+
* `Delete` — foreground deletion. Module-sdk will block the queue until the referenced object and all its descendants are deleted.
103+
* `DeleteInBackground` — will delete the referenced object immediately. All its descendants will be removed by Kubernetes'
104+
garbage collector.
105+
* `DeleteNonCascading` — will delete the referenced object immediately, and orphan all its descendants.
106+
* `apiVersion` — optional field that specifies object's apiVersion. If not present, we'll use preferred apiVersion
107+
for the given kind.
108+
* `kind` — object's Kind.
109+
* `namespace` — object's namespace. If empty, implies operation on a cluster-level resource.
110+
* `name` — object's name.
111+
* `subresource` — a subresource name if subresource is to be transformed. For example, `status`.
112+
113+
#### Example
114+
115+
```json
116+
{
117+
"operation": "Delete",
118+
"kind": "Pod",
119+
"namespace": "default",
120+
"name": "nginx"
121+
}
122+
```
123+
124+
### Patch
125+
126+
Use `JQPatch` for almost everything. Consider using `MergePatch` or `JSONPatch` if you are attempting to modify
127+
rapidly changing object, for example `status` field with many concurrent changes (and incrementing `resourceVersion`).
128+
129+
Be careful, when updating a `.status` field. If a `/status` subresource is enabled on a resource,
130+
it'll ignore updates to the `.status` field if you haven't specified `subresource: status` in the operation spec.
131+
More info [here][spec-and-status].
132+
133+
#### JQPatch
134+
135+
* `operation` — specifies an operation's type.
136+
* `apiVersion` — optional field that specifies object's apiVersion. If not present, we'll use preferred apiVersion
137+
for the given kind.
138+
* `kind` — object's Kind.
139+
* `namespace` — object's Namespace. If empty, implies operation on a Cluster-level resource.
140+
* `name` — object's name.
141+
* `jqFilter` — describes transformations to perform on an object.
142+
* `subresource` — a subresource name if subresource is to be transformed. For example, `status`.
143+
##### Example
144+
145+
```json
146+
{
147+
"operation": "JQPatch",
148+
"kind": "Deployment",
149+
"namespace": "default",
150+
"name": "nginx",
151+
"jqFilter": ".spec.replicas = 1"
152+
}
153+
```
154+
155+
#### MergePatch
156+
157+
* `operation` — specifies an operation's type.
158+
* `apiVersion` — optional field that specifies object's apiVersion. If not present, we'll use preferred apiVersion
159+
for the given kind.
160+
* `kind` — object's Kind.
161+
* `namespace` — object's Namespace. If empty, implies operation on a Cluster-level resource.
162+
* `name` — object's name.
163+
* `mergePatch` — describes transformations to perform on an object. Can be a normal JSON or YAML object or a stringified JSON or YAML object.
164+
* `subresource` — e.g., `status`.
165+
* `ignoreMissingObject` — set to true to ignore error when patching non existent object.
166+
167+
##### Example
168+
169+
```json
170+
{
171+
"operation": "MergePatch",
172+
"kind": "Deployment",
173+
"namespace": "default",
174+
"name": "nginx",
175+
"mergePatch": {
176+
"spec": {
177+
"replicas": 1
178+
}
179+
}
180+
}
181+
```
182+
183+
```yaml
184+
operation: MergePatch
185+
kind: Deployment
186+
namespace: default
187+
name: nginx
188+
ignoreMissingObject: true
189+
mergePatch: |
190+
spec:
191+
replicas: 1
192+
```
193+
194+
#### JSONPatch
195+
196+
* `operation` — specifies an operation's type.
197+
* `apiVersion` — optional field that specifies object's apiVersion. If not present, we'll use preferred apiVersion
198+
for the given kind.
199+
* `kind` — object's Kind.
200+
* `namespace` — object's Namespace. If empty, implies operation on a Cluster-level resource.
201+
* `name` — object's name.
202+
* `jsonPatch` — describes transformations to perform on an object. Can be a normal JSON or YAML array or a stringified JSON or YAML array.
203+
* `subresource` — a subresource name if subresource is to be transformed. For example, `status`.
204+
* `ignoreMissingObject` — set to true to ignore error when patching non existent object.
205+
206+
##### Example
207+
208+
```json
209+
{
210+
"operation": "JSONPatch",
211+
"kind": "Deployment",
212+
"namespace": "default",
213+
"name": "nginx",
214+
"jsonPatch": [
215+
{"op": "replace", "path": "/spec/replicas", "value": 1}
216+
]
217+
}
218+
```
219+
220+
```json
221+
{
222+
"operation": "JSONPatch",
223+
"kind": "Deployment",
224+
"namespace": "default",
225+
"name": "nginx",
226+
"jsonPatch": "[
227+
{\"op\": \"replace\", \"path\": \"/spec/replicas\", \"value\": 1}
228+
]"
229+
}
230+
```
231+
232+
[controller-gc]: https://kubernetes.io/docs/concepts/workloads/controllers/garbage-collection/
233+
[spec-and-status]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#spec-and-status

docs/src/QUICK_START.md

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# Quickstart
2+
3+
> You need to have a Kubernetes cluster, and the `kubectl` must be configured to communicate with your cluster.
4+
5+
The simplest setup of module-sdk in your cluster consists of these steps:
6+
7+
- build an image with your module
8+
- create necessary RBAC objects (for Kubernetes access)
9+
- deploy your module to the cluster
10+
11+
For more configuration options see [RUNNING](RUNNING.md).
12+
13+
## Build an image with your module
14+
15+
A module is a component that implements specific functionality using the module-sdk framework. [Learn more](MODULE_DEVELOPMENT.md) about module development.
16+
17+
Let's create a small module that will watch for all Pods in all Namespaces and simply log the name of a new Pod.
18+
19+
Create a basic module structure with a handler that responds to Pod creation events. Create the `pod-watcher.go` file with the following content:
20+
21+
```go
22+
package main
23+
24+
import (
25+
"fmt"
26+
"github.com/your-org/module-sdk/pkg/module"
27+
corev1 "k8s.io/api/core/v1"
28+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
29+
"k8s.io/client-go/kubernetes/scheme"
30+
)
31+
32+
func main() {
33+
mod := module.New("pod-watcher")
34+
35+
mod.RegisterEventHandler("v1", "Pod", module.EventHandlerConfig{
36+
EventTypes: []string{"Added"},
37+
Handler: func(obj *unstructured.Unstructured) error {
38+
// Convert unstructured to Pod
39+
pod := &corev1.Pod{}
40+
err := scheme.Scheme.Convert(obj, pod, nil)
41+
if err != nil {
42+
return err
43+
}
44+
45+
fmt.Printf("Pod '%s' added\n", pod.Name)
46+
return nil
47+
},
48+
})
49+
50+
mod.Run()
51+
}
52+
```
53+
54+
Create the following `Dockerfile` in the directory where you created the `pod-watcher.go` file:
55+
56+
```dockerfile
57+
FROM golang:1.19 as builder
58+
WORKDIR /app
59+
COPY . .
60+
RUN go mod init pod-watcher && \
61+
go mod tidy && \
62+
CGO_ENABLED=0 go build -o /pod-watcher
63+
64+
FROM alpine:3.16
65+
COPY --from=builder /pod-watcher /pod-watcher
66+
ENTRYPOINT ["/pod-watcher"]
67+
```
68+
69+
Build an image (change image tag according to your Docker registry):
70+
71+
```sh
72+
docker build -t "registry.mycompany.com/module-sdk:pod-watcher" .
73+
```
74+
75+
Push image to the Docker registry accessible by the Kubernetes cluster:
76+
77+
```sh
78+
docker push registry.mycompany.com/module-sdk:pod-watcher
79+
```
80+
81+
## Create RBAC objects
82+
83+
We need to watch for Pods in all Namespaces. That means that we need specific RBAC definitions for our module:
84+
85+
```sh
86+
kubectl create namespace example-pod-watcher
87+
kubectl create serviceaccount pod-watcher-acc --namespace example-pod-watcher
88+
kubectl create clusterrole pod-watcher --verb=get,watch,list --resource=pods
89+
kubectl create clusterrolebinding pod-watcher --clusterrole=pod-watcher --serviceaccount=example-pod-watcher:pod-watcher-acc
90+
```
91+
92+
## Deploy your module to the cluster
93+
94+
Module-sdk modules can be deployed as a Pod or Deployment. Put this manifest into the `pod-watcher.yaml` file:
95+
96+
```yaml
97+
apiVersion: v1
98+
kind: Pod
99+
metadata:
100+
name: pod-watcher
101+
spec:
102+
containers:
103+
- name: pod-watcher
104+
image: registry.mycompany.com/module-sdk:pod-watcher
105+
imagePullPolicy: Always
106+
serviceAccountName: pod-watcher-acc
107+
```
108+
109+
Deploy your module by applying the `pod-watcher.yaml` file:
110+
111+
```sh
112+
kubectl -n example-pod-watcher apply -f pod-watcher.yaml
113+
```
114+
115+
## It all comes together
116+
117+
Let's deploy a [kubernetes-dashboard][kubernetes-dashboard] to trigger the registered event handler in our module:
118+
119+
```sh
120+
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/master/aio/deploy/recommended.yaml
121+
```
122+
123+
Now run `kubectl -n example-pod-watcher logs po/pod-watcher` and observe that the module will print dashboard pod name:
124+
125+
```plain
126+
...
127+
2023/06/22 12:30:45 Registered event handler for v1/Pod
128+
2023/06/22 12:30:45 Starting informers...
129+
2023/06/22 12:30:50 Pod 'kubernetes-dashboard-775dd7f59c-hr7kj' added
130+
...
131+
```
132+
133+
To clean up a cluster, delete namespace and RBAC objects:
134+
135+
```sh
136+
kubectl delete ns example-pod-watcher
137+
kubectl delete clusterrole pod-watcher
138+
kubectl delete clusterrolebinding pod-watcher
139+
```
140+
141+
This example is also available in /examples: [pod-watcher-example][pod-watcher-example].
142+
143+
[kubernetes-dashboard]: https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/
144+
[pod-watcher-example]: https://github.com/your-org/module-sdk/tree/main/examples/pod-watcher

0 commit comments

Comments
 (0)