Merge pull request #89 from lexfrei/feature/add-inotify-workaround-docs

This commit is contained in:
Cody Robibero authored and GitHub committed 2025-11-07 18:42:36 -07:00 Unverified
commit 5f5b9224cd
5 files changed
+111 -9

No files matched your search

+4 -3
View File
@@ -8,7 +8,6 @@ keywords:
- jellyfin - jellyfin
- media - media
- self-hosted - self-hosted
version: 2.6.0
version: 3.0.0 version: 3.0.0
appVersion: 10.11.2 appVersion: 10.11.2
annotations: annotations:
@@ -17,6 +16,8 @@ annotations:
description: Deprecate initContainers parameter in favor of extraInitContainers for consistency (will be removed after 2030) description: Deprecate initContainers parameter in favor of extraInitContainers for consistency (will be removed after 2030)
- kind: fixed - kind: fixed
description: Fix extraInitContainers not working (was using wrong parameter name in template) 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 - kind: added
description: Add support for Gateway API HTTPRoute resource description: Add support for Gateway API HTTPRoute resource
- kind: added - kind: added
@@ -29,7 +30,7 @@ annotations:
description: Add persistence.cache configuration for dedicated cache volume support description: Add persistence.cache configuration for dedicated cache volume support
- kind: added - kind: added
description: Add comprehensive IPv6 and dual-stack networking documentation 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 - kind: changed
description: Improve health probe configuration examples for IPv6 compatibility 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)
+50 -6
View File
@@ -1,7 +1,6 @@
# jellyfin # jellyfin
![Version: 2.6.0](https://img.shields.io/badge/Version-2.6.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: 3.0.0](https://img.shields.io/badge/Version-3.0.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
@@ -59,7 +58,7 @@ 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 | | 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 | | 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. | | 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. | | 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 | 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.hostnames | list | `[]` | Hostnames to match for this HTTPRoute |
@@ -70,11 +69,13 @@ helm install my-jellyfin jellyfin/jellyfin -f values.yaml
| image.tag | string | `""` | Jellyfin container image tag. Leave empty to automatically use the Chart's app version. | | 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/ | | 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/ | | 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.args | list | `[]` | Additional arguments for the entrypoint command. |
| 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. Example: Workaround for inotify limits (see Troubleshooting section in README) Example: env: - name: JELLYFIN_CACHE_DIR value: /cache |
| livenessProbe | object | `{"httpGet":{"path":"/health","port":"http"},"initialDelaySeconds":10}` | Configure liveness probe for Jellyfin. Uses httpGet for compatibility with both IPv4 and IPv6. | | 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 | 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 |
@@ -119,9 +120,10 @@ 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 | `{"httpGet":{"path":"/health","port":"http"},"initialDelaySeconds":10}` | Configure readiness probe for Jellyfin. Uses httpGet for compatibility with both IPv4 and IPv6. | | 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. | | 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. |
| 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. | | 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. |
@@ -139,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.automount | bool | `true` | Automatically mount API credentials for the service account. |
| serviceAccount.create | bool | `true` | Specifies whether to create a 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. | | 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. | | tolerations | list | `[]` | Tolerations for pod scheduling. |
| volumeMounts | list | `[]` | Additional volume mounts for the Jellyfin container. | | volumeMounts | list | `[]` | Additional volume mounts for the Jellyfin container. |
| volumes | list | `[]` | Additional volumes to mount in the Jellyfin pod. | | volumes | list | `[]` | Additional volumes to mount in the Jellyfin pod. |
@@ -200,6 +203,47 @@ extraVolumeMounts:
mountPath: /dev/dri mountPath: /dev/dri
``` ```
## Troubleshooting
### inotify Instance Limit Reached
**Problem:** Jellyfin crashes with error:
```
System.IO.IOException: The configured user limit (128) on the number of inotify instances has been reached
```
**Root cause:** The Linux kernel has a limit on inotify instances (file system watchers) per user. Jellyfin uses inotify to monitor media libraries for changes.
**Proper solution (recommended):**
Increase the inotify limit on the Kubernetes nodes:
```bash
# Temporary (until reboot)
sysctl -w fs.inotify.max_user_instances=512
# Permanent
echo "fs.inotify.max_user_instances=512" >> /etc/sysctl.conf
sysctl -p
```
Recommended values:
- `fs.inotify.max_user_instances`: 512 or higher
- `fs.inotify.max_user_watches`: 524288 or higher (if you have large media libraries)
**Workaround (if you cannot modify host settings):**
If you're running on a managed Kubernetes cluster where you cannot modify node-level settings, you can force Jellyfin to use polling instead of inotify. **Note: This is less efficient and may increase CPU usage and delay change detection.**
```yaml
jellyfin:
env:
- name: DOTNET_USE_POLLING_FILE_WATCHER
value: "1"
```
This workaround disables inotify file watching in favor of periodic polling, which doesn't require inotify instances but is less efficient.
## IPv6 Configuration ## 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. 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.
+41
View File
@@ -113,6 +113,47 @@ extraVolumeMounts:
mountPath: /dev/dri mountPath: /dev/dri
``` ```
## Troubleshooting
### inotify Instance Limit Reached
**Problem:** Jellyfin crashes with error:
```
System.IO.IOException: The configured user limit (128) on the number of inotify instances has been reached
```
**Root cause:** The Linux kernel has a limit on inotify instances (file system watchers) per user. Jellyfin uses inotify to monitor media libraries for changes.
**Proper solution (recommended):**
Increase the inotify limit on the Kubernetes nodes:
```bash
# Temporary (until reboot)
sysctl -w fs.inotify.max_user_instances=512
# Permanent
echo "fs.inotify.max_user_instances=512" >> /etc/sysctl.conf
sysctl -p
```
Recommended values:
- `fs.inotify.max_user_instances`: 512 or higher
- `fs.inotify.max_user_watches`: 524288 or higher (if you have large media libraries)
**Workaround (if you cannot modify host settings):**
If you're running on a managed Kubernetes cluster where you cannot modify node-level settings, you can force Jellyfin to use polling instead of inotify. **Note: This is less efficient and may increase CPU usage and delay change detection.**
```yaml
jellyfin:
env:
- name: DOTNET_USE_POLLING_FILE_WATCHER
value: "1"
```
This workaround disables inotify file watching in favor of periodic polling, which doesn't require inotify instances but is less efficient.
## IPv6 Configuration ## 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. 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.
+13
View File
@@ -147,6 +147,15 @@ To access Jellyfin, you can use port-forwarding:
Then visit http://localhost:{{ .Values.service.port }} in your browser. Then visit http://localhost:{{ .Values.service.port }} in your browser.
{{- end }} {{- end }}
For troubleshooting common issues, see the README:
- inotify instance limit errors
- Hardware acceleration setup
- Network configuration
Useful resources:
Documentation: https://jellyfin.org/docs/
Troubleshooting: See README.md in the chart repository
{{- if .Values.jellyfin.envFrom }} {{- if .Values.jellyfin.envFrom }}
Environment Configuration: Environment Configuration:
@@ -175,6 +184,8 @@ Startup Configuration:
⚠ NOTE: Startup timeout is very long ({{ div $startupTimeout 60 }}+ minutes). ⚠ NOTE: Startup timeout is very long ({{ div $startupTimeout 60 }}+ minutes).
Consider optimizing your media library or reducing failureThreshold. Consider optimizing your media library or reducing failureThreshold.
{{- end }} {{- end }}
{{- end }}
Persistence Configuration: 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 }} 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 }} 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 }}
@@ -197,6 +208,8 @@ Cache Volume:
{{- if and .Values.persistence.cache.enabled (eq .Values.persistence.cache.type "hostPath") }} {{- 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 ⚠ WARNING: Using hostPath for cache - ensure {{ .Values.persistence.cache.hostPath }} exists on the node
{{- end }}
{{- if or .Values.service.ipFamilyPolicy .Values.service.ipFamilies }} {{- if or .Values.service.ipFamilyPolicy .Values.service.ipFamilies }}
Service IP Configuration: Service IP Configuration:
+3
View File
@@ -253,11 +253,14 @@ jellyfin:
# name: jellyfin-secrets # name: jellyfin-secrets
envFrom: [] envFrom: []
# -- Additional environment variables for the container. # -- Additional environment variables for the container.
# Example: Workaround for inotify limits (see Troubleshooting section in README)
# Example: # Example:
# env: # env:
# - name: JELLYFIN_CACHE_DIR # - name: JELLYFIN_CACHE_DIR
# value: /cache # value: /cache
env: [] env: []
# - name: DOTNET_USE_POLLING_FILE_WATCHER
# value: "1"
persistence: persistence:
config: config: