Skip to content

Commit

Permalink
cura: add cura support
Browse files Browse the repository at this point in the history
  • Loading branch information
nadiamoe committed Feb 14, 2024
1 parent 7529a3e commit 29ee1d8
Show file tree
Hide file tree
Showing 10 changed files with 364 additions and 5 deletions.
3 changes: 3 additions & 0 deletions Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,6 @@ dependencies:
- name: ustreamer
version: 0.1.0
condition: ustreamer.enabled
- name: cura
version: 0.1.0
condition: cura.enabled
30 changes: 26 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ It includes:
- [Mainsail](https://github.com/mainsail-crew/mainsail), a slick web UI for Klipper/Moonraker
- And/or [Fluidd](https://github.com/fluidd-core/fluidd), anoter slick web UI for Klipper/Moonraker
- [µStreamer](https://github.com/pikvm/ustreamer), a lightweight and fast MJPEG-HTTP streamer for your webcam

Mostly autoconfigured to run out of the box*.
- [Cura](https://ultimaker.com/software/ultimaker-cura/), an advanced slicer software.

## Using this chart

Expand All @@ -28,18 +27,41 @@ You can also install the chart directly:
helm install kubeklipper oci://ghcr.io/roobre/charts/kubeklipper --version 0.1.0
```

Things you will be able to do _the Kubernetes way_:

- Run a standard linux distro and kubelet on whatever compute you have connected to your 3D printer.
- Store your klipper, moonraker, and mainsail configs as-code, in your `values.yaml` file.
- Distribute other components (web UI, slicer) across different nodes.
- Leverage Kubernetes Ingress objects for local/remote access and TLS termination.
- Upgrade all* your 3D printing software at once, using gitops (if you want to).

Things you will need to do _the old way_:

- Flashing klipper on your 3D printer has to be done manually, as a prerequisite (*).
- The `mkuf/klipper:latest-tools` image from the prind project contains the toolchain needed for this.
- As klipper firmware does not change often, you won't need to do this more than once a year.
- Have any ideas on better ways to do this? Let me know on an issue!
- Configure Cura using its GUI. Cura config is extensive and the software relies on having write access to it.

Things the chart doesn't currently do but might in the future:

- Better volume management. Currently users are allowed to template a `volume` spec, but not to create PVs or PVCs.
- You can still create those outside of the chart and reference the volumes to them.

## Architecture

Klipper and Moonraker run together, as different containers, in the same pod. This allows them to communicate over a unix socket. You should place node selector, affinities, or resources accordingly so the node running this pod can communicate with your 3D printer via USB.

Mainsail and/or Fluidd run each one on its own pod. All of them communicate with the Klipper/Moonraker pod over HTTP, so they do not necessarily need to run on a node connected to the printer.

Finally, uStreamer also runs as an independent pod, but like Klipper/Moonraker, you should specify selectors, affinities, or resources to pin it to the node with the required webcam.
uStreamer also runs as an independent pod, but like Klipper/Moonraker, you should specify selectors, affinities, or resources to pin it to the node with the required webcam.

Cura also runs as an independent pod.

### Note on `smarter-device-manager`

I recommend [smarter-device-manager](https://gitlab.com/arm-research/smarter/smarter-device-manager) to allow pods to access device nodes (`/dev/*`), as it provides a secure way to map only certain devices to the pods, while also removing the need to set nodeSelectors or affinities.

## Images

This chart uses some of the awesome images built for the [prind](https://github.com/mkuf/prind) project.
This chart uses some of the awesome images built for the [prind](https://github.com/mkuf/prind) project, as well as the [docker-cura](https://github.com/linuxserver/docker-cura) image maintained by the excellent linuxserver folks.
23 changes: 23 additions & 0 deletions charts/cura/.helmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/
24 changes: 24 additions & 0 deletions charts/cura/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
apiVersion: v2
name: cura
description: A Helm chart for Kubernetes

# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
type: application

# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.0

# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "1.16.0"
51 changes: 51 additions & 0 deletions charts/cura/templates/_helpers.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "cura.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "cura.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}

{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "cura.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Common labels
*/}}
{{- define "cura.labels" -}}
helm.sh/chart: {{ include "cura.chart" . }}
{{ include "cura.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{/*
Selector labels
*/}}
{{- define "cura.selectorLabels" -}}
app.kubernetes.io/name: {{ include "cura.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
73 changes: 73 additions & 0 deletions charts/cura/templates/deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "cura.fullname" . }}
labels:
{{- include "cura.labels" . | nindent 4 }}
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
{{- include "cura.selectorLabels" . | nindent 6 }}
template:
metadata:
{{- with .Values.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "cura.labels" . | nindent 8 }}
{{- with .Values.podLabels }}
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
containers:
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
env:
- name: TITLE
value: Cura
{{- with .Values.extraEnv }}
{{- . | toYaml | nindent 12 }}
{{- end }}
ports:
- name: http
containerPort: {{ .Values.service.port }}
protocol: TCP
livenessProbe:
{{- toYaml .Values.livenessProbe | nindent 12 }}
readinessProbe:
{{- toYaml .Values.readinessProbe | nindent 12 }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
{{- with .Values.volumeMounts }}
volumeMounts:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.volumes }}
volumes:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
61 changes: 61 additions & 0 deletions charts/cura/templates/ingress.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "cura.fullname" . -}}
{{- $svcPort := .Values.service.port -}}
{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }}
{{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }}
{{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}}
{{- end }}
{{- end }}
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1beta1
{{- else -}}
apiVersion: extensions/v1beta1
{{- end }}
kind: Ingress
metadata:
name: {{ $fullName }}
labels:
{{- include "cura.labels" . | nindent 4 }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}
ingressClassName: {{ .Values.ingress.className }}
{{- end }}
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ .path }}
{{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }}
pathType: {{ .pathType }}
{{- end }}
backend:
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
service:
name: {{ $fullName }}
port:
number: {{ $svcPort }}
{{- else }}
serviceName: {{ $fullName }}
servicePort: {{ $svcPort }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}
15 changes: 15 additions & 0 deletions charts/cura/templates/service.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "cura.fullname" . }}
labels:
{{- include "cura.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
{{- include "cura.selectorLabels" . | nindent 4 }}
83 changes: 83 additions & 0 deletions charts/cura/values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Default values for cura.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.

image:
repository: ghcr.io/linuxserver/cura
pullPolicy: IfNotPresent
tag: 5.6.0-ls11@sha256:a1edb8f70f80ab5627af8448a50a8a522a53850d506e716aa6fac57732dc6258

imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""

podAnnotations: {}
podLabels: {}

podSecurityContext: {}

securityContext: {}

extraEnv: []
# - name: FOO
# value: bar

service:
type: ClusterIP
port: 3000

ingress:
enabled: false
className: ""
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
# hosts: []
# - host: chart-example.local
# paths:
# - path: /
# pathType: ImplementationSpecific
# tls: []
# - secretName: chart-example-tls
# hosts:
# - chart-example.local

resources: {}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi

livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http

# You probably want change this to something that is not an emptyDir.
# As of 5.6.0-ls11, the container does not appropriately set permissions for cura to be able to this directory. You will
# need to manually chown the directories cura writes to:
# chown -R 911 /config/.local/share/cura
# chown -R 911 /config/.config/cura
volumes:
- name: config
emptyDir: {}

volumeMounts:
- name: config
mountPath: /config

nodeSelector: {}

tolerations: []

affinity: {}
Loading

0 comments on commit 29ee1d8

Please sign in to comment.