Merge upstream/master-vnext into feature/add-inotify-workaround-docs
Resolve conflicts by combining inotify troubleshooting documentation with all features from master-vnext integration branch: - inotify troubleshooting docs (this branch) - HTTPRoute support - envFrom support - Startup probe - Cache persistence - IPv6 dual-stack - revisionHistoryLimit - initContainers deprecation Updated version to 3.0.0 and merged all changelog entries. Regenerated README.md from template. Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la>
This commit is contained in:
14 files changed
+1352
-18
No files matched your search
@@ -8,11 +8,29 @@ keywords:
|
||||
- jellyfin
|
||||
- media
|
||||
- self-hosted
|
||||
version: 2.5.1
|
||||
version: 3.0.0
|
||||
appVersion: 10.11.2
|
||||
annotations:
|
||||
artifacthub.io/changes: |
|
||||
- kind: deprecated
|
||||
description: Deprecate initContainers parameter in favor of extraInitContainers for consistency (will be removed after 2030)
|
||||
- kind: fixed
|
||||
description: Fix extraInitContainers not working (was using wrong parameter name in template)
|
||||
- kind: added
|
||||
description: Add troubleshooting documentation for inotify instance limits with workaround example
|
||||
- kind: added
|
||||
description: Add support for Gateway API HTTPRoute resource
|
||||
- kind: added
|
||||
description: Add envFrom support to load environment variables from ConfigMap or Secret
|
||||
- kind: added
|
||||
description: Add NOTES.txt with helpful post-installation information and deprecation warnings
|
||||
- kind: added
|
||||
description: Add startup probe to prevent pod restarts during slow initial startup with large media libraries
|
||||
- kind: added
|
||||
description: Add persistence.cache configuration for dedicated cache volume support
|
||||
- kind: added
|
||||
description: Add comprehensive IPv6 and dual-stack networking documentation
|
||||
- kind: added
|
||||
description: Add revisionHistoryLimit parameter to control rollback history retention (defaults to 3 instead of Kubernetes default 10)
|
||||
- kind: changed
|
||||
description: Improve health probe configuration examples for IPv6 compatibility
|
||||
@@ -1,6 +1,6 @@
|
||||
# jellyfin
|
||||
|
||||
  
|
||||
  
|
||||
|
||||
A Helm chart for Jellyfin Media Server
|
||||
|
||||
@@ -58,18 +58,24 @@ helm install my-jellyfin jellyfin/jellyfin -f values.yaml
|
||||
| dnsConfig | object | `{}` | Define a dnsConfig. See https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-dns-config Use this to provide a custom DNS resolver configuration |
|
||||
| dnsPolicy | string | `""` | Define a dnsPolicy. See https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-s-dns-policy |
|
||||
| extraContainers | list | `[]` | additional sidecar containers to run inside the pod. |
|
||||
| extraInitContainers | list | `[]` | additional init containers to run inside the pod. |
|
||||
| extraInitContainers | list | `[]` | Additional init containers to run inside the pod. Init containers run before the main application container starts. See: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ Example: extraInitContainers: - name: init-config image: busybox:1.35 command: ['sh', '-c', 'echo "Initializing..." && sleep 5'] volumeMounts: - name: config mountPath: /config |
|
||||
| fullnameOverride | string | `""` | Override the default full name of the chart. |
|
||||
| httpRoute | object | `{"annotations":{},"enabled":false,"hostnames":[],"parentRefs":[],"rules":[{"matches":[{"path":{"type":"PathPrefix","value":"/"}}]}]}` | HTTPRoute configuration for Gateway API. See: https://gateway-api.sigs.k8s.io/ |
|
||||
| httpRoute.hostnames | list | `[]` | Hostnames to match for this HTTPRoute |
|
||||
| httpRoute.parentRefs | list | `[]` | Gateway references to attach this HTTPRoute to |
|
||||
| httpRoute.rules | list | `[{"matches":[{"path":{"type":"PathPrefix","value":"/"}}]}]` | Rules for routing traffic |
|
||||
| image.pullPolicy | string | `"IfNotPresent"` | Image pull policy (Always, IfNotPresent, or Never). |
|
||||
| image.repository | string | `"docker.io/jellyfin/jellyfin"` | Container image repository for Jellyfin. |
|
||||
| image.tag | string | `""` | Jellyfin container image tag. Leave empty to automatically use the Chart's app version. |
|
||||
| imagePullSecrets | list | `[]` | Image pull secrets to authenticate with private repositories. See: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ |
|
||||
| ingress | object | `{"annotations":{},"className":"","enabled":false,"hosts":[{"host":"chart-example.local","paths":[{"path":"/","pathType":"ImplementationSpecific"}]}],"tls":[]}` | Ingress configuration. See: https://kubernetes.io/docs/concepts/services-networking/ingress/ |
|
||||
| initContainers | list | `[]` | DEPRECATED: Use extraInitContainers instead. Will be removed after 2030. @deprecated - This parameter is deprecated, use extraInitContainers instead |
|
||||
| jellyfin.args | list | `[]` | Additional arguments for the entrypoint command. |
|
||||
| jellyfin.command | list | `[]` | Custom command to use as container entrypoint. |
|
||||
| jellyfin.enableDLNA | bool | `false` | Enable DLNA. Requires host network. See: https://jellyfin.org/docs/general/networking/dlna.html |
|
||||
| jellyfin.env | list | `[]` | Additional environment variables for the container. Example: Workaround for inotify limits (see Troubleshooting section in README) |
|
||||
| livenessProbe | object | `{"initialDelaySeconds":10,"tcpSocket":{"port":"http"}}` | Configure liveness probe for Jellyfin. |
|
||||
| jellyfin.env | list | `[]` | Additional environment variables for the container. Example: Workaround for inotify limits (see Troubleshooting section in README) Example: env: - name: JELLYFIN_CACHE_DIR value: /cache |
|
||||
| jellyfin.envFrom | list | `[]` | Load environment variables from ConfigMap or Secret. See: https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#configure-all-key-value-pairs-in-a-configmap-as-container-environment-variables Example: envFrom: - configMapRef: name: jellyfin-config - secretRef: name: jellyfin-secrets |
|
||||
| livenessProbe | object | `{"httpGet":{"path":"/health","port":"http"},"initialDelaySeconds":10}` | Configure liveness probe for Jellyfin. This probe is disabled during startup (startup probe handles initial checks). Uses httpGet for compatibility with both IPv4 and IPv6. |
|
||||
| metrics | object | `{"enabled":false,"serviceMonitor":{"enabled":false,"interval":"30s","labels":{},"metricRelabelings":[],"namespace":"","path":"/metrics","port":8096,"relabelings":[],"scheme":"http","scrapeTimeout":"30s","targetLabels":[],"tlsConfig":{}}}` | Configuration for metrics collection and monitoring |
|
||||
| metrics.enabled | bool | `false` | Enable or disable metrics collection |
|
||||
| metrics.serviceMonitor | object | `{"enabled":false,"interval":"30s","labels":{},"metricRelabelings":[],"namespace":"","path":"/metrics","port":8096,"relabelings":[],"scheme":"http","scrapeTimeout":"30s","targetLabels":[],"tlsConfig":{}}` | Configuration for the Prometheus ServiceMonitor |
|
||||
@@ -87,6 +93,13 @@ helm install my-jellyfin jellyfin/jellyfin -f values.yaml
|
||||
| metrics.serviceMonitor.tlsConfig | object | `{}` | TLS configuration for scraping metrics |
|
||||
| nameOverride | string | `""` | Override the default name of the chart. |
|
||||
| nodeSelector | object | `{}` | Node selector for pod scheduling. |
|
||||
| persistence.cache.accessMode | string | `"ReadWriteOnce"` | PVC specific settings, only used if type is 'pvc'. |
|
||||
| persistence.cache.annotations | object | `{}` | Custom annotations to be added to the PVC |
|
||||
| persistence.cache.enabled | bool | `false` | set to false to use emptyDir |
|
||||
| persistence.cache.hostPath | string | `""` | Path on the host node for cache storage, only used if type is 'hostPath'. |
|
||||
| persistence.cache.size | string | `"10Gi"` | |
|
||||
| persistence.cache.storageClass | string | `""` | If undefined (the default) or set to null, no storageClassName spec is set, choosing the default provisioner. |
|
||||
| persistence.cache.type | string | `"pvc"` | Type of volume for cache storage (pvc, hostPath, emptyDir). If 'enabled' is false, 'emptyDir' is used regardless of this setting. |
|
||||
| persistence.config.accessMode | string | `"ReadWriteOnce"` | |
|
||||
| persistence.config.annotations | object | `{}` | Custom annotations to be added to the PVC |
|
||||
| persistence.config.enabled | bool | `true` | set to false to use emptyDir |
|
||||
@@ -107,14 +120,15 @@ helm install my-jellyfin jellyfin/jellyfin -f values.yaml
|
||||
| podPrivileges.hostPID | bool | `false` | Enable hostPID namespace. Allows pod to see processes on the host. |
|
||||
| podSecurityContext | object | `{}` | Security context for the pod. |
|
||||
| priorityClassName | string | `""` | Define a priorityClassName for the pod. |
|
||||
| readinessProbe | object | `{"initialDelaySeconds":10,"tcpSocket":{"port":"http"}}` | Configure readiness probe for Jellyfin. |
|
||||
| readinessProbe | object | `{"httpGet":{"path":"/health","port":"http"},"initialDelaySeconds":10}` | Configure readiness probe for Jellyfin. This probe is disabled during startup (startup probe handles initial checks). Uses httpGet for compatibility with both IPv4 and IPv6. |
|
||||
| replicaCount | int | `1` | Number of Jellyfin replicas to start. Should be left at 1. |
|
||||
| resources | object | `{}` | Resource requests and limits for the Jellyfin container. |
|
||||
| revisionHistoryLimit | int | `3` | Number of old ReplicaSets to retain for rollback history. Set to 0 to disable revision history (not recommended). If not specified, Kubernetes defaults to 10. See: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#revision-history-limit |
|
||||
| runtimeClassName | string | `""` | Define a custom runtimeClassName for the pod. |
|
||||
| securityContext | object | `{}` | Security context for the container. |
|
||||
| service.annotations | object | `{}` | Annotations for the service. |
|
||||
| service.ipFamilies | list | `[]` | Supported IP families (IPv4, IPv6). |
|
||||
| service.ipFamilyPolicy | string | `""` | Configure dual-stack IP family policy. See: https://kubernetes.io/docs/concepts/services-networking/dual-stack/ |
|
||||
| service.ipFamilies | list | `[]` | Supported IP families (IPv4, IPv6). Examples: IPv4 only: ["IPv4"] IPv6 only: ["IPv6"] Dual-stack (IPv4 primary): ["IPv4", "IPv6"] Dual-stack (IPv6 primary): ["IPv6", "IPv4"] Note: When using IPv6, ensure your health checks are compatible (consider using httpGet instead of tcpSocket) |
|
||||
| service.ipFamilyPolicy | string | `""` | Configure dual-stack IP family policy. See: https://kubernetes.io/docs/concepts/services-networking/dual-stack/ Options: SingleStack, PreferDualStack, RequireDualStack For IPv6-only clusters, use "SingleStack" with ipFamilies: ["IPv6"] For dual-stack, use "PreferDualStack" or "RequireDualStack" with ipFamilies: ["IPv4", "IPv6"] or ["IPv6", "IPv4"] |
|
||||
| service.labels | object | `{}` | Labels for the service. |
|
||||
| service.loadBalancerClass | string | `""` | Class of the LoadBalancer. |
|
||||
| service.loadBalancerIP | string | `""` | Specific IP address for the LoadBalancer. |
|
||||
@@ -127,6 +141,7 @@ helm install my-jellyfin jellyfin/jellyfin -f values.yaml
|
||||
| serviceAccount.automount | bool | `true` | Automatically mount API credentials for the service account. |
|
||||
| serviceAccount.create | bool | `true` | Specifies whether to create a service account. |
|
||||
| serviceAccount.name | string | `""` | Custom name for the service account. If left empty, the name will be autogenerated. |
|
||||
| startupProbe | object | `{"failureThreshold":30,"initialDelaySeconds":0,"periodSeconds":10,"tcpSocket":{"port":"http"}}` | Configure startup probe for Jellyfin. This probe gives Jellyfin enough time to start, especially with large media libraries. After the startup probe succeeds once, liveness and readiness probes take over. |
|
||||
| tolerations | list | `[]` | Tolerations for pod scheduling. |
|
||||
| volumeMounts | list | `[]` | Additional volume mounts for the Jellyfin container. |
|
||||
| volumes | list | `[]` | Additional volumes to mount in the Jellyfin pod. |
|
||||
@@ -134,6 +149,33 @@ helm install my-jellyfin jellyfin/jellyfin -f values.yaml
|
||||
----------------------------------------------
|
||||
Autogenerated from chart metadata using [helm-docs v1.14.2](https://github.com/norwoodj/helm-docs/releases/v1.14.2)
|
||||
|
||||
## Gateway API HTTPRoute
|
||||
|
||||
This chart supports the Kubernetes Gateway API HTTPRoute resource as a modern alternative to Ingress.
|
||||
|
||||
To use HTTPRoute, you need to have Gateway API CRDs installed in your cluster and a Gateway resource configured.
|
||||
|
||||
Example configuration:
|
||||
|
||||
```yaml
|
||||
httpRoute:
|
||||
enabled: true
|
||||
annotations: {}
|
||||
parentRefs:
|
||||
- name: my-gateway
|
||||
namespace: gateway-system
|
||||
sectionName: https
|
||||
hostnames:
|
||||
- jellyfin.example.com
|
||||
rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /
|
||||
```
|
||||
|
||||
For more information about Gateway API, see: <https://gateway-api.sigs.k8s.io/>
|
||||
|
||||
## Hardware acceleration
|
||||
|
||||
Out of the box the pod does not have the necessary permissions to enable hardware acceleration (HWA) in Jellyfin.
|
||||
@@ -201,3 +243,32 @@ jellyfin:
|
||||
```
|
||||
|
||||
This workaround disables inotify file watching in favor of periodic polling, which doesn't require inotify instances but is less efficient.
|
||||
|
||||
## IPv6 Configuration
|
||||
|
||||
This chart supports IPv6 and dual-stack networking configurations out of the box. Health probes use httpGet by default for compatibility with both IPv4 and IPv6.
|
||||
|
||||
### IPv6-only Configuration
|
||||
|
||||
For IPv6-only clusters:
|
||||
|
||||
```yaml
|
||||
service:
|
||||
ipFamilyPolicy: SingleStack
|
||||
ipFamilies:
|
||||
- IPv6
|
||||
```
|
||||
|
||||
### Dual-stack Configuration
|
||||
|
||||
For dual-stack clusters (both IPv4 and IPv6):
|
||||
|
||||
```yaml
|
||||
service:
|
||||
ipFamilyPolicy: PreferDualStack # or RequireDualStack
|
||||
ipFamilies:
|
||||
- IPv4
|
||||
- IPv6 # First family in the list is the primary
|
||||
```
|
||||
|
||||
For more information about Kubernetes dual-stack networking, see: <https://kubernetes.io/docs/concepts/services-networking/dual-stack/>
|
||||
@@ -59,6 +59,33 @@ helm install my-jellyfin jellyfin/jellyfin -f values.yaml
|
||||
|
||||
{{ template "helm-docs.versionFooter" . }}
|
||||
|
||||
## Gateway API HTTPRoute
|
||||
|
||||
This chart supports the Kubernetes Gateway API HTTPRoute resource as a modern alternative to Ingress.
|
||||
|
||||
To use HTTPRoute, you need to have Gateway API CRDs installed in your cluster and a Gateway resource configured.
|
||||
|
||||
Example configuration:
|
||||
|
||||
```yaml
|
||||
httpRoute:
|
||||
enabled: true
|
||||
annotations: {}
|
||||
parentRefs:
|
||||
- name: my-gateway
|
||||
namespace: gateway-system
|
||||
sectionName: https
|
||||
hostnames:
|
||||
- jellyfin.example.com
|
||||
rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /
|
||||
```
|
||||
|
||||
For more information about Gateway API, see: <https://gateway-api.sigs.k8s.io/>
|
||||
|
||||
## Hardware acceleration
|
||||
|
||||
Out of the box the pod does not have the necessary permissions to enable hardware acceleration (HWA) in Jellyfin.
|
||||
@@ -126,3 +153,32 @@ jellyfin:
|
||||
```
|
||||
|
||||
This workaround disables inotify file watching in favor of periodic polling, which doesn't require inotify instances but is less efficient.
|
||||
|
||||
## IPv6 Configuration
|
||||
|
||||
This chart supports IPv6 and dual-stack networking configurations out of the box. Health probes use httpGet by default for compatibility with both IPv4 and IPv6.
|
||||
|
||||
### IPv6-only Configuration
|
||||
|
||||
For IPv6-only clusters:
|
||||
|
||||
```yaml
|
||||
service:
|
||||
ipFamilyPolicy: SingleStack
|
||||
ipFamilies:
|
||||
- IPv6
|
||||
```
|
||||
|
||||
### Dual-stack Configuration
|
||||
|
||||
For dual-stack clusters (both IPv4 and IPv6):
|
||||
|
||||
```yaml
|
||||
service:
|
||||
ipFamilyPolicy: PreferDualStack # or RequireDualStack
|
||||
ipFamilies:
|
||||
- IPv4
|
||||
- IPv6 # First family in the list is the primary
|
||||
```
|
||||
|
||||
For more information about Kubernetes dual-stack networking, see: <https://kubernetes.io/docs/concepts/services-networking/dual-stack/>
|
||||
@@ -1,12 +1,137 @@
|
||||
Thank you for installing {{ .Chart.Name }}.
|
||||
{{- if .Values.initContainers }}
|
||||
#############################################################################
|
||||
## ⚠️ WARNING ⚠️ ##
|
||||
## ##
|
||||
## The 'initContainers' parameter is DEPRECATED! ##
|
||||
## Please migrate to 'extraInitContainers' instead. ##
|
||||
## ##
|
||||
## Support for 'initContainers' will be removed after 2030. ##
|
||||
## ##
|
||||
## Migration guide: ##
|
||||
## Old: initContainers: [...] ##
|
||||
## New: extraInitContainers: [...] ##
|
||||
## ##
|
||||
#############################################################################
|
||||
|
||||
{{- end }}
|
||||
Thank you for installing {{ .Chart.Name }}!
|
||||
|
||||
Your release is named {{ .Release.Name }}.
|
||||
|
||||
To learn more about the release, try:
|
||||
|
||||
$ helm status {{ .Release.Name }} --namespace {{ .Release.Namespace }}
|
||||
$ helm get all {{ .Release.Name }} --namespace {{ .Release.Namespace }}
|
||||
|
||||
{{- if .Values.ingress.enabled }}
|
||||
{{- range $host := .Values.ingress.hosts }}
|
||||
{{- range .paths }}
|
||||
|
||||
Jellyfin is available at:
|
||||
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- else if contains "NodePort" .Values.service.type }}
|
||||
|
||||
Get the Jellyfin URL by running:
|
||||
|
||||
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "jellyfin.fullname" . }})
|
||||
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
||||
echo "Jellyfin URL: http://$NODE_IP:$NODE_PORT"
|
||||
|
||||
{{- else if contains "LoadBalancer" .Values.service.type }}
|
||||
|
||||
Get the Jellyfin URL by running:
|
||||
|
||||
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
||||
You can watch the status by running:
|
||||
kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "jellyfin.fullname" . }}
|
||||
|
||||
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "jellyfin.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
|
||||
echo "Jellyfin URL: http://$SERVICE_IP:{{ .Values.service.port }}"
|
||||
|
||||
{{- else if contains "ClusterIP" .Values.service.type }}
|
||||
|
||||
Get the Jellyfin URL by running:
|
||||
|
||||
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "jellyfin.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
|
||||
export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
|
||||
echo "Jellyfin URL: http://127.0.0.1:8080"
|
||||
kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT
|
||||
|
||||
{{- end }}
|
||||
|
||||
{{- if .Values.persistence.config.enabled }}
|
||||
|
||||
Configuration is persisted to:
|
||||
{{- if .Values.persistence.config.existingClaim }}
|
||||
Existing PVC: {{ .Values.persistence.config.existingClaim }}
|
||||
{{- else }}
|
||||
PVC: {{ include "jellyfin.fullname" . }}-config
|
||||
{{- end }}
|
||||
{{- else }}
|
||||
|
||||
WARNING: Configuration persistence is disabled!
|
||||
Data will be lost when the pod is restarted.
|
||||
Enable persistence.config.enabled to persist your configuration.
|
||||
{{- end }}
|
||||
|
||||
{{- if .Values.persistence.media.enabled }}
|
||||
|
||||
Media is {{ if eq .Values.persistence.media.type "hostPath" }}mounted from host path{{ else if eq .Values.persistence.media.type "pvc" }}persisted to PVC{{ else }}stored in emptyDir{{ end }}:
|
||||
{{- if eq .Values.persistence.media.type "hostPath" }}
|
||||
Host path: {{ .Values.persistence.media.hostPath }}
|
||||
{{- else if eq .Values.persistence.media.type "pvc" }}
|
||||
{{- if .Values.persistence.media.existingClaim }}
|
||||
Existing PVC: {{ .Values.persistence.media.existingClaim }}
|
||||
{{- else }}
|
||||
PVC: {{ include "jellyfin.fullname" . }}-media
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- else }}
|
||||
|
||||
WARNING: Media persistence is disabled!
|
||||
Your media files will be lost when the pod is restarted.
|
||||
Enable persistence.media.enabled to persist your media.
|
||||
{{- end }}
|
||||
|
||||
For more information and documentation:
|
||||
Repository: https://github.com/jellyfin/jellyfin-helm
|
||||
Jellyfin Docs: https://jellyfin.org/docs/
|
||||
$ helm status {{ .Release.Name }}
|
||||
$ helm get all {{ .Release.Name }}
|
||||
|
||||
{{- if .Values.httpRoute.enabled }}
|
||||
|
||||
HTTPRoute (Gateway API) is ENABLED:
|
||||
{{- if .Values.httpRoute.parentRefs }}
|
||||
Gateway References:
|
||||
{{- range .Values.httpRoute.parentRefs }}
|
||||
- {{ .name }}{{ if .namespace }} (namespace: {{ .namespace }}){{ end }}{{ if .sectionName }} [{{ .sectionName }}]{{ end }}
|
||||
{{- end }}
|
||||
{{- else }}
|
||||
⚠ WARNING: No parentRefs defined - HTTPRoute will not attach to any Gateway!
|
||||
{{- end }}
|
||||
{{- if .Values.httpRoute.hostnames }}
|
||||
Hostnames:
|
||||
{{- range .Values.httpRoute.hostnames }}
|
||||
- {{ . }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
Rules: {{ len .Values.httpRoute.rules }} route(s) configured
|
||||
Backend: {{ include "jellyfin.fullname" . }}:{{ .Values.service.port }}
|
||||
|
||||
Access Jellyfin via Gateway API at:
|
||||
{{- if .Values.httpRoute.hostnames }}
|
||||
{{- range .Values.httpRoute.hostnames }}
|
||||
https://{{ . }}{{ (index $.Values.httpRoute.rules 0).matches 0 .path.value }}
|
||||
{{- end }}
|
||||
{{- else }}
|
||||
(Configure httpRoute.hostnames for external access)
|
||||
{{- end }}
|
||||
|
||||
Note: Ensure your Gateway API CRDs are installed and Gateway is configured.
|
||||
{{- else if .Values.ingress.enabled }}
|
||||
{{- if .Values.ingress.enabled }}
|
||||
|
||||
Jellyfin is available via Ingress at:
|
||||
@@ -30,6 +155,79 @@ For troubleshooting common issues, see the README:
|
||||
Useful resources:
|
||||
Documentation: https://jellyfin.org/docs/
|
||||
Troubleshooting: See README.md in the chart repository
|
||||
|
||||
{{- if .Values.jellyfin.envFrom }}
|
||||
|
||||
Environment Configuration:
|
||||
Loading environment variables from {{ len .Values.jellyfin.envFrom }} source(s):
|
||||
{{- range .Values.jellyfin.envFrom }}
|
||||
{{- if .configMapRef }}
|
||||
- ConfigMap: {{ .configMapRef.name }}{{ if .configMapRef.optional }} (optional){{ end }}{{ if .prefix }} with prefix: {{ .prefix }}{{ end }}
|
||||
{{- else if .secretRef }}
|
||||
- Secret: {{ .secretRef.name }}{{ if .secretRef.optional }} (optional){{ end }}{{ if .prefix }} with prefix: {{ .prefix }}{{ end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- if .Values.startupProbe }}
|
||||
{{- $startupTimeout := mul (default 10 .Values.startupProbe.periodSeconds) (default 30 .Values.startupProbe.failureThreshold) }}
|
||||
|
||||
Startup Configuration:
|
||||
Startup Probe: Enabled
|
||||
Max Startup Time: {{ $startupTimeout }}s ({{ div $startupTimeout 60 }} minutes)
|
||||
|
||||
The startup probe gives Jellyfin enough time to initialize, especially
|
||||
with large media libraries. After startup succeeds, liveness and
|
||||
readiness probes take over for health monitoring.
|
||||
|
||||
{{- if gt $startupTimeout 600 }}
|
||||
⚠ NOTE: Startup timeout is very long ({{ div $startupTimeout 60 }}+ minutes).
|
||||
Consider optimizing your media library or reducing failureThreshold.
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
Persistence Configuration:
|
||||
Config: {{ if .Values.persistence.config.enabled }}{{ .Values.persistence.config.type | default "pvc" }}{{ if .Values.persistence.config.existingClaim }} (existing: {{ .Values.persistence.config.existingClaim }}){{ end }}{{ else }}emptyDir{{ end }}
|
||||
Media: {{ if .Values.persistence.media.enabled }}{{ .Values.persistence.media.type | default "pvc" }}{{ if .Values.persistence.media.existingClaim }} (existing: {{ .Values.persistence.media.existingClaim }}){{ end }}{{ else }}emptyDir{{ end }}
|
||||
Cache: {{ if .Values.persistence.cache.enabled }}{{ .Values.persistence.cache.type | default "pvc" }}{{ if .Values.persistence.cache.existingClaim }} (existing: {{ .Values.persistence.cache.existingClaim }}){{ end }}{{ else }}emptyDir{{ end }}
|
||||
|
||||
{{- if and .Values.persistence.cache.enabled (eq .Values.persistence.cache.type "pvc") }}
|
||||
Cache Volume:
|
||||
Dedicated cache volume is enabled for improved performance.
|
||||
Size: {{ .Values.persistence.cache.size }}
|
||||
Access Mode: {{ .Values.persistence.cache.accessMode }}
|
||||
{{- if .Values.persistence.cache.storageClass }}
|
||||
Storage Class: {{ .Values.persistence.cache.storageClass }}
|
||||
{{- end }}
|
||||
|
||||
Benefits:
|
||||
- Faster transcoding and metadata operations
|
||||
- Separate cache lifecycle from config/media
|
||||
- Can use faster storage class (SSD) for cache
|
||||
{{- end }}
|
||||
|
||||
{{- if and .Values.persistence.cache.enabled (eq .Values.persistence.cache.type "hostPath") }}
|
||||
⚠ WARNING: Using hostPath for cache - ensure {{ .Values.persistence.cache.hostPath }} exists on the node
|
||||
{{- end }}
|
||||
|
||||
{{- if or .Values.service.ipFamilyPolicy .Values.service.ipFamilies }}
|
||||
|
||||
Service IP Configuration:
|
||||
{{- if .Values.service.ipFamilyPolicy }}
|
||||
IP Family Policy: {{ .Values.service.ipFamilyPolicy }}
|
||||
{{- end }}
|
||||
{{- if .Values.service.ipFamilies }}
|
||||
IP Families: {{ .Values.service.ipFamilies | join ", " }}
|
||||
{{- if eq (index .Values.service.ipFamilies 0) "IPv6" }}
|
||||
⚠ NOTE: IPv6 primary - ensure your probes use httpGet instead of tcpSocket for compatibility
|
||||
{{- end }}
|
||||
{{- if has "IPv6" .Values.service.ipFamilies }}
|
||||
{{- if not .Values.service.ipFamilyPolicy }}
|
||||
⚠ WARNING: ipFamilies includes IPv6 but ipFamilyPolicy is not set
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
Deployment Configuration:
|
||||
Revision History Limit: {{ .Values.revisionHistoryLimit }}
|
||||
{{- $limit := int .Values.revisionHistoryLimit }}
|
||||
|
||||
@@ -62,6 +62,10 @@ spec:
|
||||
args:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.jellyfin.envFrom }}
|
||||
envFrom:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.jellyfin.env }}
|
||||
env:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
@@ -111,6 +115,10 @@ spec:
|
||||
hostPort: 1900
|
||||
protocol: UDP
|
||||
{{- end }}
|
||||
{{- with .Values.startupProbe }}
|
||||
startupProbe:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
livenessProbe:
|
||||
{{- toYaml .Values.livenessProbe | nindent 12 }}
|
||||
readinessProbe:
|
||||
@@ -122,15 +130,24 @@ spec:
|
||||
name: config
|
||||
- mountPath: /media
|
||||
name: media
|
||||
- mountPath: /cache
|
||||
name: cache
|
||||
{{- with .Values.volumeMounts }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.extraContainers }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.initContainers }}
|
||||
{{- if or .Values.initContainers .Values.extraInitContainers }}
|
||||
# Support both initContainers (deprecated) and extraInitContainers for backward compatibility.
|
||||
# TODO: Remove initContainers support after 2030
|
||||
initContainers:
|
||||
{{- toYaml . | nindent 6 }}
|
||||
{{- if .Values.initContainers }}
|
||||
{{- toYaml .Values.initContainers | nindent 6 }}
|
||||
{{- end }}
|
||||
{{- if .Values.extraInitContainers }}
|
||||
{{- toYaml .Values.extraInitContainers | nindent 6 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
volumes:
|
||||
- name: config
|
||||
@@ -155,6 +172,21 @@ spec:
|
||||
{{- else }}
|
||||
emptyDir: {}
|
||||
{{- end }}
|
||||
- name: cache
|
||||
{{- if .Values.persistence.cache.enabled }}
|
||||
{{- if eq .Values.persistence.cache.type "pvc" }}
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ if .Values.persistence.cache.existingClaim }}{{ .Values.persistence.cache.existingClaim }}{{- else }}{{ template "jellyfin.fullname" . }}-cache{{- end }}
|
||||
{{- else if eq .Values.persistence.cache.type "hostPath" }}
|
||||
hostPath:
|
||||
path: {{ .Values.persistence.cache.hostPath }}
|
||||
type: Directory
|
||||
{{- else }}
|
||||
emptyDir: {}
|
||||
{{- end }}
|
||||
{{- else }}
|
||||
emptyDir: {}
|
||||
{{- end }}
|
||||
{{- with .Values.volumes }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
{{- if .Values.httpRoute.enabled }}
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
kind: HTTPRoute
|
||||
metadata:
|
||||
name: {{ include "jellyfin.fullname" . }}
|
||||
labels:
|
||||
{{- include "jellyfin.labels" . | nindent 4 }}
|
||||
{{- with .Values.httpRoute.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- with .Values.httpRoute.parentRefs }}
|
||||
parentRefs:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- with .Values.httpRoute.hostnames }}
|
||||
hostnames:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range .Values.httpRoute.rules }}
|
||||
- matches:
|
||||
{{- range .matches }}
|
||||
- path:
|
||||
type: {{ .path.type }}
|
||||
value: {{ .path.value }}
|
||||
{{- end }}
|
||||
backendRefs:
|
||||
- name: {{ include "jellyfin.fullname" $ }}
|
||||
port: {{ $.Values.service.port }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -43,3 +43,26 @@ spec:
|
||||
storageClassName: {{ . | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- if and .Values.persistence.cache.enabled (eq .Values.persistence.cache.type "pvc") (not .Values.persistence.cache.existingClaim) }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: {{ include "jellyfin.fullname" . }}-cache
|
||||
labels:
|
||||
{{- include "jellyfin.labels" . | nindent 4 }}
|
||||
{{- with .Values.persistence.cache.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
accessModes:
|
||||
- {{ .Values.persistence.cache.accessMode | quote }}
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.persistence.cache.size | quote }}
|
||||
{{- with .Values.persistence.cache.storageClass }}
|
||||
storageClassName: {{ . | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,160 @@
|
||||
suite: test cache persistence
|
||||
templates:
|
||||
- deployment.yaml
|
||||
- persistentVolumeClaim.yaml
|
||||
tests:
|
||||
# Deployment volume mount tests
|
||||
- it: should mount cache as emptyDir by default
|
||||
template: deployment.yaml
|
||||
asserts:
|
||||
- contains:
|
||||
path: spec.template.spec.volumes
|
||||
content:
|
||||
name: cache
|
||||
emptyDir: {}
|
||||
|
||||
- it: should mount cache PVC when enabled
|
||||
template: deployment.yaml
|
||||
set:
|
||||
persistence.cache.enabled: true
|
||||
persistence.cache.type: pvc
|
||||
asserts:
|
||||
- contains:
|
||||
path: spec.template.spec.volumes
|
||||
content:
|
||||
name: cache
|
||||
persistentVolumeClaim:
|
||||
claimName: RELEASE-NAME-jellyfin-cache
|
||||
|
||||
- it: should mount cache from hostPath when configured
|
||||
template: deployment.yaml
|
||||
set:
|
||||
persistence.cache.enabled: true
|
||||
persistence.cache.type: hostPath
|
||||
persistence.cache.hostPath: /mnt/jellyfin-cache
|
||||
asserts:
|
||||
- contains:
|
||||
path: spec.template.spec.volumes
|
||||
content:
|
||||
name: cache
|
||||
hostPath:
|
||||
path: /mnt/jellyfin-cache
|
||||
|
||||
- it: should mount cache at correct path
|
||||
template: deployment.yaml
|
||||
asserts:
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].volumeMounts
|
||||
content:
|
||||
name: cache
|
||||
mountPath: /cache
|
||||
|
||||
# PVC tests
|
||||
- it: should not create cache PVC by default
|
||||
template: persistentVolumeClaim.yaml
|
||||
asserts:
|
||||
- hasDocuments:
|
||||
count: 2 # config and media only
|
||||
|
||||
- it: should create cache PVC when enabled
|
||||
template: persistentVolumeClaim.yaml
|
||||
set:
|
||||
persistence.cache.enabled: true
|
||||
persistence.cache.type: pvc
|
||||
asserts:
|
||||
- hasDocuments:
|
||||
count: 3 # config, media, and cache
|
||||
- contains:
|
||||
path: metadata.name
|
||||
content: RELEASE-NAME-jellyfin-cache
|
||||
|
||||
- it: should not create cache PVC when type is hostPath
|
||||
template: persistentVolumeClaim.yaml
|
||||
set:
|
||||
persistence.cache.enabled: true
|
||||
persistence.cache.type: hostPath
|
||||
asserts:
|
||||
- hasDocuments:
|
||||
count: 2 # config and media only
|
||||
|
||||
- it: should not create cache PVC when type is emptyDir
|
||||
template: persistentVolumeClaim.yaml
|
||||
set:
|
||||
persistence.cache.enabled: true
|
||||
persistence.cache.type: emptyDir
|
||||
asserts:
|
||||
- hasDocuments:
|
||||
count: 2
|
||||
|
||||
- it: should set cache PVC size correctly
|
||||
template: persistentVolumeClaim.yaml
|
||||
documentIndex: 2
|
||||
set:
|
||||
persistence.cache.enabled: true
|
||||
persistence.cache.type: pvc
|
||||
persistence.cache.size: 20Gi
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.resources.requests.storage
|
||||
value: 20Gi
|
||||
|
||||
- it: should set cache PVC access mode
|
||||
template: persistentVolumeClaim.yaml
|
||||
documentIndex: 2
|
||||
set:
|
||||
persistence.cache.enabled: true
|
||||
persistence.cache.type: pvc
|
||||
persistence.cache.accessMode: ReadWriteMany
|
||||
asserts:
|
||||
- contains:
|
||||
path: spec.accessModes
|
||||
content: ReadWriteMany
|
||||
|
||||
- it: should set cache PVC storage class
|
||||
template: persistentVolumeClaim.yaml
|
||||
documentIndex: 2
|
||||
set:
|
||||
persistence.cache.enabled: true
|
||||
persistence.cache.type: pvc
|
||||
persistence.cache.storageClass: fast-ssd
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.storageClassName
|
||||
value: fast-ssd
|
||||
|
||||
- it: should add annotations to cache PVC
|
||||
template: persistentVolumeClaim.yaml
|
||||
documentIndex: 2
|
||||
set:
|
||||
persistence.cache.enabled: true
|
||||
persistence.cache.type: pvc
|
||||
persistence.cache.annotations:
|
||||
my-annotation: my-value
|
||||
asserts:
|
||||
- equal:
|
||||
path: metadata.annotations.my-annotation
|
||||
value: my-value
|
||||
|
||||
- it: should use existing claim when specified
|
||||
template: deployment.yaml
|
||||
set:
|
||||
persistence.cache.enabled: true
|
||||
persistence.cache.type: pvc
|
||||
persistence.cache.existingClaim: my-existing-cache-claim
|
||||
asserts:
|
||||
- contains:
|
||||
path: spec.template.spec.volumes
|
||||
content:
|
||||
name: cache
|
||||
persistentVolumeClaim:
|
||||
claimName: my-existing-cache-claim
|
||||
|
||||
- it: should not create PVC when existing claim used
|
||||
template: persistentVolumeClaim.yaml
|
||||
set:
|
||||
persistence.cache.enabled: true
|
||||
persistence.cache.type: pvc
|
||||
persistence.cache.existingClaim: my-existing-cache-claim
|
||||
asserts:
|
||||
- hasDocuments:
|
||||
count: 2 # config and media only, not cache
|
||||
@@ -0,0 +1,122 @@
|
||||
suite: test envFrom
|
||||
templates:
|
||||
- deployment.yaml
|
||||
tests:
|
||||
- it: should not have envFrom by default
|
||||
asserts:
|
||||
- isNull:
|
||||
path: spec.template.spec.containers[0].envFrom
|
||||
|
||||
- it: should add envFrom from ConfigMap
|
||||
set:
|
||||
jellyfin.envFrom:
|
||||
- configMapRef:
|
||||
name: jellyfin-config
|
||||
asserts:
|
||||
- isNotNull:
|
||||
path: spec.template.spec.containers[0].envFrom
|
||||
- lengthEqual:
|
||||
path: spec.template.spec.containers[0].envFrom
|
||||
count: 1
|
||||
- equal:
|
||||
path: spec.template.spec.containers[0].envFrom[0].configMapRef.name
|
||||
value: jellyfin-config
|
||||
|
||||
- it: should add envFrom from Secret
|
||||
set:
|
||||
jellyfin.envFrom:
|
||||
- secretRef:
|
||||
name: jellyfin-secrets
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.template.spec.containers[0].envFrom[0].secretRef.name
|
||||
value: jellyfin-secrets
|
||||
|
||||
- it: should support multiple envFrom sources
|
||||
set:
|
||||
jellyfin.envFrom:
|
||||
- configMapRef:
|
||||
name: jellyfin-config
|
||||
- secretRef:
|
||||
name: jellyfin-secrets
|
||||
- configMapRef:
|
||||
name: jellyfin-extra-config
|
||||
asserts:
|
||||
- lengthEqual:
|
||||
path: spec.template.spec.containers[0].envFrom
|
||||
count: 3
|
||||
- equal:
|
||||
path: spec.template.spec.containers[0].envFrom[0].configMapRef.name
|
||||
value: jellyfin-config
|
||||
- equal:
|
||||
path: spec.template.spec.containers[0].envFrom[1].secretRef.name
|
||||
value: jellyfin-secrets
|
||||
- equal:
|
||||
path: spec.template.spec.containers[0].envFrom[2].configMapRef.name
|
||||
value: jellyfin-extra-config
|
||||
|
||||
- it: should support optional ConfigMap
|
||||
set:
|
||||
jellyfin.envFrom:
|
||||
- configMapRef:
|
||||
name: optional-config
|
||||
optional: true
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.template.spec.containers[0].envFrom[0].configMapRef.optional
|
||||
value: true
|
||||
|
||||
- it: should support optional Secret
|
||||
set:
|
||||
jellyfin.envFrom:
|
||||
- secretRef:
|
||||
name: optional-secret
|
||||
optional: true
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.template.spec.containers[0].envFrom[0].secretRef.optional
|
||||
value: true
|
||||
|
||||
- it: should support prefix for ConfigMap
|
||||
set:
|
||||
jellyfin.envFrom:
|
||||
- configMapRef:
|
||||
name: my-config
|
||||
prefix: CONFIG_
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.template.spec.containers[0].envFrom[0].prefix
|
||||
value: CONFIG_
|
||||
|
||||
- it: should support prefix for Secret
|
||||
set:
|
||||
jellyfin.envFrom:
|
||||
- secretRef:
|
||||
name: my-secret
|
||||
prefix: SECRET_
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.template.spec.containers[0].envFrom[0].prefix
|
||||
value: SECRET_
|
||||
|
||||
- it: should work alongside regular env variables
|
||||
set:
|
||||
jellyfin.env:
|
||||
- name: CUSTOM_VAR
|
||||
value: custom-value
|
||||
jellyfin.envFrom:
|
||||
- configMapRef:
|
||||
name: jellyfin-config
|
||||
asserts:
|
||||
- isNotNull:
|
||||
path: spec.template.spec.containers[0].env
|
||||
- isNotNull:
|
||||
path: spec.template.spec.containers[0].envFrom
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: CUSTOM_VAR
|
||||
value: custom-value
|
||||
- equal:
|
||||
path: spec.template.spec.containers[0].envFrom[0].configMapRef.name
|
||||
value: jellyfin-config
|
||||
@@ -0,0 +1,193 @@
|
||||
suite: test httproute
|
||||
templates:
|
||||
- httproute.yaml
|
||||
tests:
|
||||
- it: should not create HTTPRoute by default
|
||||
asserts:
|
||||
- hasDocuments:
|
||||
count: 0
|
||||
|
||||
- it: should create HTTPRoute when enabled
|
||||
set:
|
||||
httpRoute.enabled: true
|
||||
httpRoute.parentRefs:
|
||||
- name: my-gateway
|
||||
namespace: gateway-system
|
||||
httpRoute.rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /
|
||||
asserts:
|
||||
- hasDocuments:
|
||||
count: 1
|
||||
- isKind:
|
||||
of: HTTPRoute
|
||||
- isAPIVersion:
|
||||
of: gateway.networking.k8s.io/v1
|
||||
- equal:
|
||||
path: metadata.name
|
||||
value: RELEASE-NAME-jellyfin
|
||||
|
||||
- it: should add annotations when specified
|
||||
set:
|
||||
httpRoute.enabled: true
|
||||
httpRoute.annotations:
|
||||
my-annotation: my-value
|
||||
httpRoute.parentRefs:
|
||||
- name: my-gateway
|
||||
httpRoute.rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /
|
||||
asserts:
|
||||
- equal:
|
||||
path: metadata.annotations.my-annotation
|
||||
value: my-value
|
||||
|
||||
- it: should set parentRefs correctly
|
||||
set:
|
||||
httpRoute.enabled: true
|
||||
httpRoute.parentRefs:
|
||||
- name: my-gateway
|
||||
namespace: gateway-system
|
||||
sectionName: https
|
||||
httpRoute.rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.parentRefs[0].name
|
||||
value: my-gateway
|
||||
- equal:
|
||||
path: spec.parentRefs[0].namespace
|
||||
value: gateway-system
|
||||
- equal:
|
||||
path: spec.parentRefs[0].sectionName
|
||||
value: https
|
||||
|
||||
- it: should set hostnames when specified
|
||||
set:
|
||||
httpRoute.enabled: true
|
||||
httpRoute.hostnames:
|
||||
- jellyfin.example.com
|
||||
- media.example.com
|
||||
httpRoute.parentRefs:
|
||||
- name: my-gateway
|
||||
httpRoute.rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.hostnames[0]
|
||||
value: jellyfin.example.com
|
||||
- equal:
|
||||
path: spec.hostnames[1]
|
||||
value: media.example.com
|
||||
|
||||
- it: should create rules with path matches
|
||||
set:
|
||||
httpRoute.enabled: true
|
||||
httpRoute.parentRefs:
|
||||
- name: my-gateway
|
||||
httpRoute.rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /jellyfin
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.rules[0].matches[0].path.type
|
||||
value: PathPrefix
|
||||
- equal:
|
||||
path: spec.rules[0].matches[0].path.value
|
||||
value: /jellyfin
|
||||
|
||||
- it: should set backendRefs to jellyfin service
|
||||
set:
|
||||
httpRoute.enabled: true
|
||||
service.port: 8096
|
||||
httpRoute.parentRefs:
|
||||
- name: my-gateway
|
||||
httpRoute.rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.rules[0].backendRefs[0].name
|
||||
value: RELEASE-NAME-jellyfin
|
||||
- equal:
|
||||
path: spec.rules[0].backendRefs[0].port
|
||||
value: 8096
|
||||
|
||||
- it: should support multiple rules
|
||||
set:
|
||||
httpRoute.enabled: true
|
||||
httpRoute.parentRefs:
|
||||
- name: my-gateway
|
||||
httpRoute.rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /
|
||||
- matches:
|
||||
- path:
|
||||
type: Exact
|
||||
value: /api
|
||||
asserts:
|
||||
- lengthEqual:
|
||||
path: spec.rules
|
||||
count: 2
|
||||
- equal:
|
||||
path: spec.rules[0].matches[0].path.value
|
||||
value: /
|
||||
- equal:
|
||||
path: spec.rules[1].matches[0].path.value
|
||||
value: /api
|
||||
|
||||
- it: should support multiple matches in single rule
|
||||
set:
|
||||
httpRoute.enabled: true
|
||||
httpRoute.parentRefs:
|
||||
- name: my-gateway
|
||||
httpRoute.rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /api
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /web
|
||||
asserts:
|
||||
- lengthEqual:
|
||||
path: spec.rules[0].matches
|
||||
count: 2
|
||||
- equal:
|
||||
path: spec.rules[0].matches[0].path.value
|
||||
value: /api
|
||||
- equal:
|
||||
path: spec.rules[0].matches[1].path.value
|
||||
value: /web
|
||||
|
||||
- it: should use custom service port
|
||||
set:
|
||||
httpRoute.enabled: true
|
||||
service.port: 9000
|
||||
httpRoute.parentRefs:
|
||||
- name: my-gateway
|
||||
httpRoute.rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.rules[0].backendRefs[0].port
|
||||
value: 9000
|
||||
@@ -0,0 +1,119 @@
|
||||
suite: test init containers
|
||||
templates:
|
||||
- deployment.yaml
|
||||
tests:
|
||||
- it: should not have init containers by default
|
||||
asserts:
|
||||
- isNull:
|
||||
path: spec.template.spec.initContainers
|
||||
|
||||
- it: should add extraInitContainers when specified
|
||||
set:
|
||||
extraInitContainers:
|
||||
- name: init-config
|
||||
image: busybox:1.35
|
||||
command: ['sh', '-c', 'echo Initializing']
|
||||
asserts:
|
||||
- isNotNull:
|
||||
path: spec.template.spec.initContainers
|
||||
- lengthEqual:
|
||||
path: spec.template.spec.initContainers
|
||||
count: 1
|
||||
- equal:
|
||||
path: spec.template.spec.initContainers[0].name
|
||||
value: init-config
|
||||
- equal:
|
||||
path: spec.template.spec.initContainers[0].image
|
||||
value: busybox:1.35
|
||||
|
||||
- it: should support multiple extraInitContainers
|
||||
set:
|
||||
extraInitContainers:
|
||||
- name: init-1
|
||||
image: busybox:1.35
|
||||
- name: init-2
|
||||
image: alpine:3.18
|
||||
asserts:
|
||||
- lengthEqual:
|
||||
path: spec.template.spec.initContainers
|
||||
count: 2
|
||||
- equal:
|
||||
path: spec.template.spec.initContainers[0].name
|
||||
value: init-1
|
||||
- equal:
|
||||
path: spec.template.spec.initContainers[1].name
|
||||
value: init-2
|
||||
|
||||
- it: should preserve full container spec in extraInitContainers
|
||||
set:
|
||||
extraInitContainers:
|
||||
- name: init-permissions
|
||||
image: busybox:1.35
|
||||
command: ['sh', '-c']
|
||||
args: ['chown -R 1000:1000 /config']
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /config
|
||||
securityContext:
|
||||
runAsUser: 0
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.template.spec.initContainers[0].command[0]
|
||||
value: sh
|
||||
- equal:
|
||||
path: spec.template.spec.initContainers[0].args[0]
|
||||
value: 'chown -R 1000:1000 /config'
|
||||
- equal:
|
||||
path: spec.template.spec.initContainers[0].volumeMounts[0].name
|
||||
value: config
|
||||
- equal:
|
||||
path: spec.template.spec.initContainers[0].securityContext.runAsUser
|
||||
value: 0
|
||||
|
||||
# Deprecated initContainers (backward compatibility)
|
||||
- it: should still support deprecated initContainers parameter
|
||||
set:
|
||||
initContainers:
|
||||
- name: legacy-init
|
||||
image: busybox:1.35
|
||||
asserts:
|
||||
- lengthEqual:
|
||||
path: spec.template.spec.initContainers
|
||||
count: 1
|
||||
- equal:
|
||||
path: spec.template.spec.initContainers[0].name
|
||||
value: legacy-init
|
||||
|
||||
- it: should merge initContainers and extraInitContainers
|
||||
set:
|
||||
initContainers:
|
||||
- name: legacy-init
|
||||
image: busybox:1.35
|
||||
extraInitContainers:
|
||||
- name: new-init
|
||||
image: alpine:3.18
|
||||
asserts:
|
||||
- lengthEqual:
|
||||
path: spec.template.spec.initContainers
|
||||
count: 2
|
||||
- equal:
|
||||
path: spec.template.spec.initContainers[0].name
|
||||
value: legacy-init
|
||||
- equal:
|
||||
path: spec.template.spec.initContainers[1].name
|
||||
value: new-init
|
||||
|
||||
- it: should prioritize extraInitContainers over initContainers
|
||||
set:
|
||||
initContainers:
|
||||
- name: old-way
|
||||
image: busybox:1.35
|
||||
extraInitContainers:
|
||||
- name: new-way
|
||||
image: alpine:3.18
|
||||
asserts:
|
||||
- contains:
|
||||
path: spec.template.spec.initContainers
|
||||
content:
|
||||
name: new-way
|
||||
image: alpine:3.18
|
||||
@@ -0,0 +1,128 @@
|
||||
suite: test service ipv6 and dual-stack
|
||||
templates:
|
||||
- service.yaml
|
||||
tests:
|
||||
- it: should not set ipFamilyPolicy by default
|
||||
asserts:
|
||||
- isNull:
|
||||
path: spec.ipFamilyPolicy
|
||||
|
||||
- it: should not set ipFamilies by default
|
||||
asserts:
|
||||
- isNull:
|
||||
path: spec.ipFamilies
|
||||
|
||||
- it: should set ipFamilyPolicy when specified
|
||||
set:
|
||||
service.ipFamilyPolicy: PreferDualStack
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.ipFamilyPolicy
|
||||
value: PreferDualStack
|
||||
|
||||
- it: should support SingleStack policy
|
||||
set:
|
||||
service.ipFamilyPolicy: SingleStack
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.ipFamilyPolicy
|
||||
value: SingleStack
|
||||
|
||||
- it: should support RequireDualStack policy
|
||||
set:
|
||||
service.ipFamilyPolicy: RequireDualStack
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.ipFamilyPolicy
|
||||
value: RequireDualStack
|
||||
|
||||
- it: should set ipFamilies for IPv4 only
|
||||
set:
|
||||
service.ipFamilies:
|
||||
- IPv4
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.ipFamilies[0]
|
||||
value: IPv4
|
||||
|
||||
- it: should set ipFamilies for IPv6 only
|
||||
set:
|
||||
service.ipFamilies:
|
||||
- IPv6
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.ipFamilies[0]
|
||||
value: IPv6
|
||||
|
||||
- it: should set ipFamilies for dual-stack IPv4 primary
|
||||
set:
|
||||
service.ipFamilies:
|
||||
- IPv4
|
||||
- IPv6
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.ipFamilies[0]
|
||||
value: IPv4
|
||||
- equal:
|
||||
path: spec.ipFamilies[1]
|
||||
value: IPv6
|
||||
|
||||
- it: should set ipFamilies for dual-stack IPv6 primary
|
||||
set:
|
||||
service.ipFamilies:
|
||||
- IPv6
|
||||
- IPv4
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.ipFamilies[0]
|
||||
value: IPv6
|
||||
- equal:
|
||||
path: spec.ipFamilies[1]
|
||||
value: IPv4
|
||||
|
||||
- it: should work with PreferDualStack and both families
|
||||
set:
|
||||
service.ipFamilyPolicy: PreferDualStack
|
||||
service.ipFamilies:
|
||||
- IPv4
|
||||
- IPv6
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.ipFamilyPolicy
|
||||
value: PreferDualStack
|
||||
- equal:
|
||||
path: spec.ipFamilies[0]
|
||||
value: IPv4
|
||||
- equal:
|
||||
path: spec.ipFamilies[1]
|
||||
value: IPv6
|
||||
|
||||
- it: should work with RequireDualStack and both families
|
||||
set:
|
||||
service.ipFamilyPolicy: RequireDualStack
|
||||
service.ipFamilies:
|
||||
- IPv6
|
||||
- IPv4
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.ipFamilyPolicy
|
||||
value: RequireDualStack
|
||||
- equal:
|
||||
path: spec.ipFamilies[0]
|
||||
value: IPv6
|
||||
- equal:
|
||||
path: spec.ipFamilies[1]
|
||||
value: IPv4
|
||||
|
||||
- it: should work with SingleStack IPv6 only
|
||||
set:
|
||||
service.ipFamilyPolicy: SingleStack
|
||||
service.ipFamilies:
|
||||
- IPv6
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.ipFamilyPolicy
|
||||
value: SingleStack
|
||||
- equal:
|
||||
path: spec.ipFamilies[0]
|
||||
value: IPv6
|
||||
@@ -0,0 +1,92 @@
|
||||
suite: test startup probe
|
||||
templates:
|
||||
- deployment.yaml
|
||||
tests:
|
||||
- it: should have startup probe by default
|
||||
asserts:
|
||||
- isNotNull:
|
||||
path: spec.template.spec.containers[0].startupProbe
|
||||
|
||||
- it: should use tcpSocket by default
|
||||
asserts:
|
||||
- isNotNull:
|
||||
path: spec.template.spec.containers[0].startupProbe.tcpSocket
|
||||
- equal:
|
||||
path: spec.template.spec.containers[0].startupProbe.tcpSocket.port
|
||||
value: http
|
||||
|
||||
- it: should have default timing values
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.template.spec.containers[0].startupProbe.initialDelaySeconds
|
||||
value: 0
|
||||
- equal:
|
||||
path: spec.template.spec.containers[0].startupProbe.periodSeconds
|
||||
value: 10
|
||||
- equal:
|
||||
path: spec.template.spec.containers[0].startupProbe.failureThreshold
|
||||
value: 30
|
||||
|
||||
- it: should allow custom initialDelaySeconds
|
||||
set:
|
||||
startupProbe.initialDelaySeconds: 5
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.template.spec.containers[0].startupProbe.initialDelaySeconds
|
||||
value: 5
|
||||
|
||||
- it: should allow custom periodSeconds
|
||||
set:
|
||||
startupProbe.periodSeconds: 15
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.template.spec.containers[0].startupProbe.periodSeconds
|
||||
value: 15
|
||||
|
||||
- it: should allow custom failureThreshold
|
||||
set:
|
||||
startupProbe.failureThreshold: 60
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.template.spec.containers[0].startupProbe.failureThreshold
|
||||
value: 60
|
||||
|
||||
- it: should support httpGet probe
|
||||
set:
|
||||
startupProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: http
|
||||
initialDelaySeconds: 0
|
||||
periodSeconds: 10
|
||||
failureThreshold: 30
|
||||
asserts:
|
||||
- isNotNull:
|
||||
path: spec.template.spec.containers[0].startupProbe.httpGet
|
||||
- equal:
|
||||
path: spec.template.spec.containers[0].startupProbe.httpGet.path
|
||||
value: /health
|
||||
- equal:
|
||||
path: spec.template.spec.containers[0].startupProbe.httpGet.port
|
||||
value: http
|
||||
|
||||
- it: should support custom port
|
||||
set:
|
||||
startupProbe.tcpSocket.port: 9000
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.template.spec.containers[0].startupProbe.tcpSocket.port
|
||||
value: 9000
|
||||
|
||||
- it: should calculate correct timeout window
|
||||
set:
|
||||
startupProbe.periodSeconds: 10
|
||||
startupProbe.failureThreshold: 30
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.template.spec.containers[0].startupProbe.periodSeconds
|
||||
value: 10
|
||||
- equal:
|
||||
path: spec.template.spec.containers[0].startupProbe.failureThreshold
|
||||
value: 30
|
||||
# Total startup time allowed: 10 * 30 = 300 seconds (5 minutes)
|
||||
@@ -91,8 +91,17 @@ service:
|
||||
# -- Service type (ClusterIP, NodePort, or LoadBalancer).
|
||||
type: ClusterIP
|
||||
# -- Configure dual-stack IP family policy. See: https://kubernetes.io/docs/concepts/services-networking/dual-stack/
|
||||
# Options: SingleStack, PreferDualStack, RequireDualStack
|
||||
# For IPv6-only clusters, use "SingleStack" with ipFamilies: ["IPv6"]
|
||||
# For dual-stack, use "PreferDualStack" or "RequireDualStack" with ipFamilies: ["IPv4", "IPv6"] or ["IPv6", "IPv4"]
|
||||
ipFamilyPolicy: ""
|
||||
# -- Supported IP families (IPv4, IPv6).
|
||||
# Examples:
|
||||
# IPv4 only: ["IPv4"]
|
||||
# IPv6 only: ["IPv6"]
|
||||
# Dual-stack (IPv4 primary): ["IPv4", "IPv6"]
|
||||
# Dual-stack (IPv6 primary): ["IPv6", "IPv4"]
|
||||
# Note: When using IPv6, ensure your health checks are compatible (consider using httpGet instead of tcpSocket)
|
||||
ipFamilies: []
|
||||
# -- Specific IP address for the LoadBalancer.
|
||||
loadBalancerIP: ""
|
||||
@@ -130,6 +139,25 @@ ingress:
|
||||
# hosts:
|
||||
# - chart-example.local
|
||||
|
||||
# -- HTTPRoute configuration for Gateway API. See: https://gateway-api.sigs.k8s.io/
|
||||
httpRoute:
|
||||
enabled: false
|
||||
annotations: {}
|
||||
# -- Gateway references to attach this HTTPRoute to
|
||||
parentRefs: []
|
||||
# - name: my-gateway
|
||||
# namespace: gateway-system
|
||||
# sectionName: https
|
||||
# -- Hostnames to match for this HTTPRoute
|
||||
hostnames: []
|
||||
# - jellyfin.example.com
|
||||
# -- Rules for routing traffic
|
||||
rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /
|
||||
|
||||
# -- Resource requests and limits for the Jellyfin container.
|
||||
resources: {}
|
||||
# limits:
|
||||
@@ -139,21 +167,39 @@ resources: {}
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
|
||||
# -- Configure liveness probe for Jellyfin.
|
||||
livenessProbe:
|
||||
initialDelaySeconds: 10
|
||||
# -- Configure startup probe for Jellyfin.
|
||||
# This probe gives Jellyfin enough time to start, especially with large media libraries.
|
||||
# After the startup probe succeeds once, liveness and readiness probes take over.
|
||||
startupProbe:
|
||||
tcpSocket:
|
||||
port: http
|
||||
initialDelaySeconds: 0
|
||||
periodSeconds: 10
|
||||
failureThreshold: 30
|
||||
# With these defaults, Jellyfin has up to 5 minutes (30 * 10s) to start.
|
||||
# Adjust failureThreshold if you have very large media libraries or slow storage.
|
||||
|
||||
# -- Configure liveness probe for Jellyfin.
|
||||
# This probe is disabled during startup (startup probe handles initial checks).
|
||||
# Uses httpGet for compatibility with both IPv4 and IPv6.
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: http
|
||||
initialDelaySeconds: 10
|
||||
# successThreshold: 1
|
||||
# failureThreshold: 3
|
||||
# timeoutSeconds: 1
|
||||
# periodSeconds: 10
|
||||
|
||||
# -- Configure readiness probe for Jellyfin.
|
||||
# This probe is disabled during startup (startup probe handles initial checks).
|
||||
# Uses httpGet for compatibility with both IPv4 and IPv6.
|
||||
readinessProbe:
|
||||
initialDelaySeconds: 10
|
||||
tcpSocket:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: http
|
||||
initialDelaySeconds: 10
|
||||
# successThreshold: 1
|
||||
# failureThreshold: 3
|
||||
# timeoutSeconds: 1
|
||||
@@ -197,8 +243,21 @@ jellyfin:
|
||||
command: []
|
||||
# -- Additional arguments for the entrypoint command.
|
||||
args: []
|
||||
# -- Load environment variables from ConfigMap or Secret.
|
||||
# See: https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#configure-all-key-value-pairs-in-a-configmap-as-container-environment-variables
|
||||
# Example:
|
||||
# envFrom:
|
||||
# - configMapRef:
|
||||
# name: jellyfin-config
|
||||
# - secretRef:
|
||||
# name: jellyfin-secrets
|
||||
envFrom: []
|
||||
# -- Additional environment variables for the container.
|
||||
# Example: Workaround for inotify limits (see Troubleshooting section in README)
|
||||
# Example:
|
||||
# env:
|
||||
# - name: JELLYFIN_CACHE_DIR
|
||||
# value: /cache
|
||||
env: []
|
||||
# - name: DOTNET_USE_POLLING_FILE_WATCHER
|
||||
# value: "1"
|
||||
@@ -231,6 +290,22 @@ persistence:
|
||||
storageClass: ''
|
||||
## -- Use an existing PVC for this mount
|
||||
# existingClaim: ''
|
||||
cache:
|
||||
# -- set to false to use emptyDir
|
||||
enabled: false
|
||||
# -- Type of volume for cache storage (pvc, hostPath, emptyDir). If 'enabled' is false, 'emptyDir' is used regardless of this setting.
|
||||
type: pvc
|
||||
# -- Path on the host node for cache storage, only used if type is 'hostPath'.
|
||||
hostPath: ""
|
||||
# -- PVC specific settings, only used if type is 'pvc'.
|
||||
accessMode: ReadWriteOnce
|
||||
size: 10Gi
|
||||
# -- Custom annotations to be added to the PVC
|
||||
annotations: {}
|
||||
# -- If undefined (the default) or set to null, no storageClassName spec is set, choosing the default provisioner.
|
||||
storageClass: ''
|
||||
## -- Use an existing PVC for this mount
|
||||
# existingClaim: ''
|
||||
|
||||
# -- Configuration for metrics collection and monitoring
|
||||
metrics:
|
||||
@@ -263,8 +338,22 @@ metrics:
|
||||
# -- Target labels to add to the scraped metrics
|
||||
targetLabels: []
|
||||
|
||||
# -- additional init containers to run inside the pod.
|
||||
# -- DEPRECATED: Use extraInitContainers instead. Will be removed after 2030.
|
||||
# @deprecated - This parameter is deprecated, use extraInitContainers instead
|
||||
initContainers: []
|
||||
|
||||
# -- Additional init containers to run inside the pod.
|
||||
# Init containers run before the main application container starts.
|
||||
# See: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/
|
||||
# Example:
|
||||
# extraInitContainers:
|
||||
# - name: init-config
|
||||
# image: busybox:1.35
|
||||
# command: ['sh', '-c', 'echo "Initializing..." && sleep 5']
|
||||
# volumeMounts:
|
||||
# - name: config
|
||||
# mountPath: /config
|
||||
extraInitContainers: []
|
||||
|
||||
|
||||
# -- additional sidecar containers to run inside the pod.
|
||||
extraContainers: []
|
||||
Reference in new issue
Block a user