Merge branch 'master-vnext' into feature/add-envfrom-support

This commit is contained in:
Cody Robibero authored and GitHub committed 2025-11-07 18:24:14 -07:00 Unverified
commit fbe25c758e
11 files changed
+851 -15

No files matched your search

+15
View File
@@ -9,10 +9,25 @@ keywords:
- media - media
- self-hosted - self-hosted
version: 2.6.0 version: 2.6.0
version: 3.0.0
appVersion: 10.11.2 appVersion: 10.11.2
annotations: annotations:
artifacthub.io/changes: | 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 - kind: added
description: Add envFrom support to load environment variables from ConfigMap or Secret description: Add envFrom support to load environment variables from ConfigMap or Secret
- kind: added - 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: changed
description: Improve health probe configuration examples for IPv6 compatibility
- kind: changed
description: Add revisionHistoryLimit parameter to control rollback history retention (defaults to 3 instead of Kubernetes default 10) description: Add revisionHistoryLimit parameter to control rollback history retention (defaults to 3 instead of Kubernetes default 10)
+41 -5
View File
@@ -1,6 +1,6 @@
# jellyfin # jellyfin
![Version: 2.5.0](https://img.shields.io/badge/Version-2.5.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 10.11.2](https://img.shields.io/badge/AppVersion-10.11.2-informational?style=flat-square) ![Version: 2.5.1](https://img.shields.io/badge/Version-2.5.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 10.11.2](https://img.shields.io/badge/AppVersion-10.11.2-informational?style=flat-square)
A Helm chart for Jellyfin Media Server A Helm chart for Jellyfin Media Server
@@ -69,7 +69,7 @@ helm install my-jellyfin jellyfin/jellyfin -f values.yaml
| jellyfin.command | list | `[]` | Custom command to use as container entrypoint. | | 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.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. | | jellyfin.env | list | `[]` | Additional environment variables for the container. |
| livenessProbe | object | `{"initialDelaySeconds":10,"tcpSocket":{"port":"http"}}` | Configure liveness probe for Jellyfin. | | livenessProbe | object | `{"httpGet":{"path":"/health","port":"http"},"initialDelaySeconds":10}` | Configure liveness probe for Jellyfin. 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 | 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.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 | | 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 +87,13 @@ helm install my-jellyfin jellyfin/jellyfin -f values.yaml
| metrics.serviceMonitor.tlsConfig | object | `{}` | TLS configuration for scraping metrics | | metrics.serviceMonitor.tlsConfig | object | `{}` | TLS configuration for scraping metrics |
| nameOverride | string | `""` | Override the default name of the chart. | | nameOverride | string | `""` | Override the default name of the chart. |
| nodeSelector | object | `{}` | Node selector for pod scheduling. | | 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.accessMode | string | `"ReadWriteOnce"` | |
| persistence.config.annotations | object | `{}` | Custom annotations to be added to the PVC | | persistence.config.annotations | object | `{}` | Custom annotations to be added to the PVC |
| persistence.config.enabled | bool | `true` | set to false to use emptyDir | | persistence.config.enabled | bool | `true` | set to false to use emptyDir |
@@ -107,14 +114,14 @@ helm install my-jellyfin jellyfin/jellyfin -f values.yaml
| podPrivileges.hostPID | bool | `false` | Enable hostPID namespace. Allows pod to see processes on the host. | | podPrivileges.hostPID | bool | `false` | Enable hostPID namespace. Allows pod to see processes on the host. |
| podSecurityContext | object | `{}` | Security context for the pod. | | podSecurityContext | object | `{}` | Security context for the pod. |
| priorityClassName | string | `""` | Define a priorityClassName 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. Uses httpGet for compatibility with both IPv4 and IPv6. |
| replicaCount | int | `1` | Number of Jellyfin replicas to start. Should be left at 1. | | replicaCount | int | `1` | Number of Jellyfin replicas to start. Should be left at 1. |
| resources | object | `{}` | Resource requests and limits for the Jellyfin container. | | resources | object | `{}` | Resource requests and limits for the Jellyfin container. |
| runtimeClassName | string | `""` | Define a custom runtimeClassName for the pod. | | runtimeClassName | string | `""` | Define a custom runtimeClassName for the pod. |
| securityContext | object | `{}` | Security context for the container. | | securityContext | object | `{}` | Security context for the container. |
| service.annotations | object | `{}` | Annotations for the service. | | service.annotations | object | `{}` | Annotations for the service. |
| service.ipFamilies | list | `[]` | Supported IP families (IPv4, IPv6). | | 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/ | | 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.labels | object | `{}` | Labels for the service. |
| service.loadBalancerClass | string | `""` | Class of the LoadBalancer. | | service.loadBalancerClass | string | `""` | Class of the LoadBalancer. |
| service.loadBalancerIP | string | `""` | Specific IP address for the LoadBalancer. | | service.loadBalancerIP | string | `""` | Specific IP address for the LoadBalancer. |
@@ -160,3 +167,32 @@ extraVolumeMounts:
- name: hwa - name: hwa
mountPath: /dev/dri mountPath: /dev/dri
``` ```
## 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/>
+29
View File
@@ -85,3 +85,32 @@ extraVolumeMounts:
- name: hwa - name: hwa
mountPath: /dev/dri mountPath: /dev/dri
``` ```
## 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/>
+150 -1
View File
@@ -1,9 +1,103 @@
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 }}. Your release is named {{ .Release.Name }}.
To learn more about the release, try: 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 status {{ .Release.Name }}
$ helm get all {{ .Release.Name }} $ helm get all {{ .Release.Name }}
@@ -35,6 +129,61 @@ Environment Configuration:
{{- 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 }}
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
{{- 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: Deployment Configuration:
Revision History Limit: {{ .Values.revisionHistoryLimit }} Revision History Limit: {{ .Values.revisionHistoryLimit }}
{{- $limit := int .Values.revisionHistoryLimit }} {{- $limit := int .Values.revisionHistoryLimit }}
+30 -2
View File
@@ -115,6 +115,10 @@ spec:
hostPort: 1900 hostPort: 1900
protocol: UDP protocol: UDP
{{- end }} {{- end }}
{{- with .Values.startupProbe }}
startupProbe:
{{- toYaml . | nindent 12 }}
{{- end }}
livenessProbe: livenessProbe:
{{- toYaml .Values.livenessProbe | nindent 12 }} {{- toYaml .Values.livenessProbe | nindent 12 }}
readinessProbe: readinessProbe:
@@ -126,15 +130,24 @@ spec:
name: config name: config
- mountPath: /media - mountPath: /media
name: media name: media
- mountPath: /cache
name: cache
{{- with .Values.volumeMounts }} {{- with .Values.volumeMounts }}
{{- toYaml . | nindent 12 }} {{- toYaml . | nindent 12 }}
{{- end }} {{- end }}
{{- with .Values.extraContainers }} {{- with .Values.extraContainers }}
{{- toYaml . | nindent 8 }} {{- toYaml . | nindent 8 }}
{{- end }} {{- 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: initContainers:
{{- toYaml . | nindent 6 }} {{- if .Values.initContainers }}
{{- toYaml .Values.initContainers | nindent 6 }}
{{- end }}
{{- if .Values.extraInitContainers }}
{{- toYaml .Values.extraInitContainers | nindent 6 }}
{{- end }}
{{- end }} {{- end }}
volumes: volumes:
- name: config - name: config
@@ -159,6 +172,21 @@ spec:
{{- else }} {{- else }}
emptyDir: {} emptyDir: {}
{{- end }} {{- 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 }} {{- with .Values.volumes }}
{{- toYaml . | nindent 8 }} {{- toYaml . | nindent 8 }}
{{- end }} {{- end }}
@@ -43,3 +43,26 @@ spec:
storageClassName: {{ . | quote }} storageClassName: {{ . | quote }}
{{- end }} {{- end }}
{{- 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,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)
+64 -7
View File
@@ -91,8 +91,17 @@ service:
# -- Service type (ClusterIP, NodePort, or LoadBalancer). # -- Service type (ClusterIP, NodePort, or LoadBalancer).
type: ClusterIP type: ClusterIP
# -- Configure dual-stack IP family policy. See: https://kubernetes.io/docs/concepts/services-networking/dual-stack/ # -- 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: "" ipFamilyPolicy: ""
# -- Supported IP families (IPv4, IPv6). # -- 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: [] ipFamilies: []
# -- Specific IP address for the LoadBalancer. # -- Specific IP address for the LoadBalancer.
loadBalancerIP: "" loadBalancerIP: ""
@@ -139,21 +148,39 @@ resources: {}
# cpu: 100m # cpu: 100m
# memory: 128Mi # memory: 128Mi
# -- Configure liveness probe for Jellyfin. # -- Configure startup probe for Jellyfin.
livenessProbe: # This probe gives Jellyfin enough time to start, especially with large media libraries.
initialDelaySeconds: 10 # After the startup probe succeeds once, liveness and readiness probes take over.
startupProbe:
tcpSocket: tcpSocket:
port: http 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 # successThreshold: 1
# failureThreshold: 3 # failureThreshold: 3
# timeoutSeconds: 1 # timeoutSeconds: 1
# periodSeconds: 10 # periodSeconds: 10
# -- Configure readiness probe for Jellyfin. # -- 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: readinessProbe:
initialDelaySeconds: 10 httpGet:
tcpSocket: path: /health
port: http port: http
initialDelaySeconds: 10
# successThreshold: 1 # successThreshold: 1
# failureThreshold: 3 # failureThreshold: 3
# timeoutSeconds: 1 # timeoutSeconds: 1
@@ -241,6 +268,22 @@ persistence:
storageClass: '' storageClass: ''
## -- Use an existing PVC for this mount ## -- Use an existing PVC for this mount
# existingClaim: '' # 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 # -- Configuration for metrics collection and monitoring
metrics: metrics:
@@ -273,8 +316,22 @@ metrics:
# -- Target labels to add to the scraped metrics # -- Target labels to add to the scraped metrics
targetLabels: [] 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: [] extraInitContainers: []
# -- additional sidecar containers to run inside the pod. # -- additional sidecar containers to run inside the pod.
extraContainers: [] extraContainers: []