From 97d697274e9f202743a9f773644cb113b935f566 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Socho=C5=84?= Date: Thu, 11 Jul 2024 22:31:27 +0200 Subject: [PATCH] Add example kubernetes deployment --- docs/service.kubernetes.md | 47 ++++++++++++++++++ k8s/README.md | 4 ++ k8s/configs/cam-1.env | 7 +++ k8s/configs/cam-2.env | 5 ++ k8s/deployment-1.yaml | 96 +++++++++++++++++++++++++++++++++++++ k8s/deployment-2.yaml | 90 ++++++++++++++++++++++++++++++++++ k8s/kustomization.yaml | 29 +++++++++++ k8s/namespace.yaml | 7 +++ k8s/prusa-connect-camera.sh | 1 + mkdocs.yml | 1 + 10 files changed, 287 insertions(+) create mode 100644 docs/service.kubernetes.md create mode 100644 k8s/README.md create mode 100644 k8s/configs/cam-1.env create mode 100644 k8s/configs/cam-2.env create mode 100644 k8s/deployment-1.yaml create mode 100644 k8s/deployment-2.yaml create mode 100644 k8s/kustomization.yaml create mode 100644 k8s/namespace.yaml create mode 120000 k8s/prusa-connect-camera.sh diff --git a/docs/service.kubernetes.md b/docs/service.kubernetes.md new file mode 100644 index 0000000..a430ea0 --- /dev/null +++ b/docs/service.kubernetes.md @@ -0,0 +1,47 @@ +# Running in kubernetes + +Yes, because why not, especially if you run k3s :D + +This is just an example but you should be able to adjust it to your needs. + +## Overview + +- each camera should be a separate kubernetes deployment, easier to manage. + +- in `configs` there is a one file with env vars loaded per deployment, + those env vars **MUST BE** changed as in env vars + Also do not use double quotes the values. + +- deployment possible using for example kustomize + +## Examples + +- [deployment-1.yaml](https://github.com/nvtkaszpir/prusa-connect-camera-script/k8s/deployment-1.yaml) + is an example to fetch image from a stream using ffmpeg and with custom + prusa-connect-camera.sh for easier development/iteration + +- [deployment-2.yaml](https://github.com/nvtkaszpir/prusa-connect-camera-script/k8s/deployment-2.yaml) + is an example how to run it on Raspberry Pi with USB camera using default parameters. + You want to change `.spec.nodeName` and volumes to point to desired camera. + +## More copies + +If you want to add more cameras then you should: + +- copy example config file from `config/` and adjust it +- copy desired deployment.yaml and adjust it +- update any `cam-x` references in the deployment.yaml +- update `.spec.nodeName` in the deployment.yaml +- if using direct camera update volumes - `dev-video` hostpath to point to the desired + camera device + +- fine tune requests/limits to use less resources if needed + +## Troubleshooting + +- just look into the logs of the failing pods +- some hosts do not have predictable camera names, will have to think about udev + rules how to handle it... + +- not tested with any device operators +- not tested with istio/traefik whatever. diff --git a/k8s/README.md b/k8s/README.md new file mode 100644 index 0000000..0b7a037 --- /dev/null +++ b/k8s/README.md @@ -0,0 +1,4 @@ +# prusa-connect-camera-script in kubernetes + +See [docs](https://nvtkaszpir.github.io/prusa-connect-camera-script/service.kubernetes/) +for more details. diff --git a/k8s/configs/cam-1.env b/k8s/configs/cam-1.env new file mode 100644 index 0000000..52bba6f --- /dev/null +++ b/k8s/configs/cam-1.env @@ -0,0 +1,7 @@ +PRINTER_ADDRESS= +PRUSA_CONNECT_CAMERA_TOKEN=change-me +PRUSA_CONNECT_CAMERA_FINGERPRINT=change-me +CAMERA_SETUP_COMMAND= +CAMERA_DEVICE=/dev/null +CAMERA_COMMAND=ffmpeg +CAMERA_COMMAND_EXTRA_PARAMS=-y -i 'http://esp32-wrover-0461c8.intra.hlds.pl:8080/' -vframes 1 -q:v 1 -f image2 -update 1 diff --git a/k8s/configs/cam-2.env b/k8s/configs/cam-2.env new file mode 100644 index 0000000..caef572 --- /dev/null +++ b/k8s/configs/cam-2.env @@ -0,0 +1,5 @@ +PRUSA_CONNECT_CAMERA_TOKEN=change-me +PRUSA_CONNECT_CAMERA_FINGERPRINT=change-me +CAMERA_DEVICE=/dev/video999 +CAMERA_COMMAND=fswebcam +CAMERA_COMMAND_EXTRA_PARAMS=-S 10 --resolution 1280x720 --no-banner -s auto_exposure=1,brightness=128,contrast=5 diff --git a/k8s/deployment-1.yaml b/k8s/deployment-1.yaml new file mode 100644 index 0000000..195105c --- /dev/null +++ b/k8s/deployment-1.yaml @@ -0,0 +1,96 @@ +--- +apiVersion: apps/v1 +kind: Deployment + +metadata: + name: cam-1 + labels: + app.kubernetes.io/name: cam-1 +spec: + replicas: 1 + revisionHistoryLimit: 3 + + strategy: + type: Recreate + + selector: + matchLabels: + app.kubernetes.io/name: cam-1 + + template: + metadata: + labels: + app.kubernetes.io/name: cam-1 + + spec: + automountServiceAccountToken: false + enableServiceLinks: false + containers: + - name: script + tty: true # get that logs flowing to stdout/stderr + command: + - /script/prusa-connect-camera.sh + envFrom: + - secretRef: + name: cam-1 + image: quay.io/kaszpir/prusa-connect-script:latest + imagePullPolicy: IfNotPresent + securityContext: + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 1000 + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + # add: + # - NET_RAW + ports: + - name: status + containerPort: 8080 + protocol: TCP + + resources: + requests: + cpu: "0.1" + memory: "32Mi" + limits: + cpu: "1.0" + memory: "128Mi" + + lifecycle: + preStop: + exec: + command: ["/bin/sh","-c","echo graceful-shutdown-start;sleep 2;echo graceful-shutdown-end"] # wait for inflight requests to finish + + livenessProbe: + exec: + command: + - bash + - -c + - test $(find /dev/shm/ -mmin -1 | wc -l) -gt "0" + initialDelaySeconds: 5 + periodSeconds: 15 + + # readinessProbe: + # httpGet: + # path: /health + # port: status + + volumeMounts: + - mountPath: /script/ + name: script + - mountPath: /dev/shm + name: dev-shm + + terminationGracePeriodSeconds: 10 + volumes: + + - name: dev-shm + emptyDir: + medium: Memory + + - name: script + configMap: + name: script + defaultMode: 0755 diff --git a/k8s/deployment-2.yaml b/k8s/deployment-2.yaml new file mode 100644 index 0000000..f281842 --- /dev/null +++ b/k8s/deployment-2.yaml @@ -0,0 +1,90 @@ +--- +apiVersion: apps/v1 +kind: Deployment + +metadata: + name: cam-2 + labels: + app.kubernetes.io/name: cam-2 +spec: + replicas: 1 + revisionHistoryLimit: 3 + + strategy: + type: Recreate + + selector: + matchLabels: + app.kubernetes.io/name: cam-2 + + template: + metadata: + labels: + app.kubernetes.io/name: cam-2 + + spec: + nodeName: hormex # change this to the desired host with given hardware + automountServiceAccountToken: false + enableServiceLinks: false + containers: + - name: script + tty: true # get that logs flowing to stdout/stderr + envFrom: + - secretRef: + name: cam-2 + image: quay.io/kaszpir/prusa-connect-script:latest + imagePullPolicy: IfNotPresent + lifecycle: + preStop: + exec: + command: ["/bin/sh","-c","echo graceful-shutdown-start;sleep 2;echo graceful-shutdown-end"] # wait for inflight requests to finish + livenessProbe: + exec: + command: + - bash + - -c + - test $(find /dev/shm/ -mmin -1 | wc -l) -gt "0" + initialDelaySeconds: 5 + periodSeconds: 15 + + securityContext: + # allowPrivilegeEscalation: false + privileged: true + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 1000 + capabilities: + drop: + - ALL + # add: + # - NET_RAW # needed for ping if not using + + resources: + requests: + cpu: "0.1" + memory: "32Mi" + limits: + cpu: "1.0" + memory: "128Mi" + + volumeMounts: + - mountPath: /dev/shm + name: dev-shm + - mountPath: /dev/video999 # must be the same as in `volumes` section and in cam.env + name: dev-video + # securityContext: + # runAsUser: 1000 + # # runAsGroup: video + # # fsGroup: 2000 + # tolerations: + # - key: "rpi" + # operator: "Exists" + # effect: "NoSchedule" + terminationGracePeriodSeconds: 10 # let it finish the sending the picture + volumes: + - name: dev-shm + emptyDir: + medium: Memory + - name: dev-video + hostPath: + path: /dev/video1 # change this to the device on the host diff --git a/k8s/kustomization.yaml b/k8s/kustomization.yaml new file mode 100644 index 0000000..6f9f91e --- /dev/null +++ b/k8s/kustomization.yaml @@ -0,0 +1,29 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +namespace: prusa-connect-camera + +resources: + - namespace.yaml + + - deployment-1.yaml + # - deployment-2.yaml + +secretGenerator: + - name: cam-1 + envs: + - configs/cam-1.env + - name: cam-2 + envs: + - configs/cam-2.env + + +configMapGenerator: + - name: script + files: + - prusa-connect-camera.sh + +images: + - name: quay.io/kaszpir/prusa-connect-script + newName: bagno.hlds.pl:16000/quay.io/kaszpir/prusa-connect-script + newTag: "5a471cf" diff --git a/k8s/namespace.yaml b/k8s/namespace.yaml new file mode 100644 index 0000000..f163f73 --- /dev/null +++ b/k8s/namespace.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: v1 +kind: Namespace +metadata: + labels: + kubernetes.io/metadata.name: prusa-connect-camera + name: prusa-connect-camera diff --git a/k8s/prusa-connect-camera.sh b/k8s/prusa-connect-camera.sh new file mode 120000 index 0000000..faffe52 --- /dev/null +++ b/k8s/prusa-connect-camera.sh @@ -0,0 +1 @@ +../prusa-connect-camera.sh \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 790e8f3..a54fa58 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -73,6 +73,7 @@ nav: - Overview: service.md - Systemd: service.systemd.md - Docker: service.docker.md + - Kubernetes: service.kubernetes.md - Configuration Tuning: configuration.tuning.md - Configuration all env vars: configuration.env.full.md