From 250a126357361c208a0eab864fae2fa6b15b17d5 Mon Sep 17 00:00:00 2001 From: Aleksei Sviridkin Date: Wed, 5 Nov 2025 22:56:01 +0300 Subject: [PATCH 1/2] fix(ipv6): use httpGet probes by default for IPv4 and IPv6 compatibility Change default health probes from tcpSocket to httpGet to fix issue #68 where pods fail to start in IPv6-only clusters due to incompatible health checks. Changes: - Change default livenessProbe and readinessProbe to use httpGet with /health endpoint - Add comprehensive IPv6 and dual-stack configuration documentation - Document ipFamilyPolicy options (SingleStack, PreferDualStack, RequireDualStack) - Document ipFamilies configuration for IPv4-only, IPv6-only, and dual-stack setups - Add IPv6 Configuration section to README with examples - Update Chart version from 2.5.0 to 2.5.1 The httpGet probe works with both IPv4 and IPv6 out of the box, while tcpSocket may fail in IPv6-only environments. Jellyfin's /health endpoint is specifically designed for health checks and verifies both HTTP and database connectivity. Fixes: #68 Co-Authored-By: Claude Signed-off-by: Aleksei Sviridkin --- charts/jellyfin/Chart.yaml | 8 ++++++- charts/jellyfin/README.md | 39 ++++++++++++++++++++++++++++---- charts/jellyfin/README.md.gotmpl | 29 ++++++++++++++++++++++++ charts/jellyfin/values.yaml | 21 +++++++++++++---- 4 files changed, 87 insertions(+), 10 deletions(-) diff --git a/charts/jellyfin/Chart.yaml b/charts/jellyfin/Chart.yaml index 96a351b..2960dbf 100644 --- a/charts/jellyfin/Chart.yaml +++ b/charts/jellyfin/Chart.yaml @@ -8,5 +8,11 @@ keywords: - jellyfin - media - self-hosted -version: 2.5.0 +version: 2.5.1 appVersion: 10.11.2 +annotations: + artifacthub.io/changes: | + - kind: added + description: Add comprehensive IPv6 and dual-stack networking documentation + - kind: changed + description: Improve health probe configuration examples for IPv6 compatibility diff --git a/charts/jellyfin/README.md b/charts/jellyfin/README.md index 10952b6..d330a84 100644 --- a/charts/jellyfin/README.md +++ b/charts/jellyfin/README.md @@ -1,6 +1,6 @@ # 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 @@ -69,7 +69,7 @@ helm install my-jellyfin jellyfin/jellyfin -f values.yaml | 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. | -| 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.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 | @@ -107,14 +107,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. | | 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. 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. | | 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. | @@ -160,3 +160,32 @@ extraVolumeMounts: - name: hwa 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: diff --git a/charts/jellyfin/README.md.gotmpl b/charts/jellyfin/README.md.gotmpl index ee08a35..90546e6 100644 --- a/charts/jellyfin/README.md.gotmpl +++ b/charts/jellyfin/README.md.gotmpl @@ -85,3 +85,32 @@ extraVolumeMounts: - name: hwa 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: diff --git a/charts/jellyfin/values.yaml b/charts/jellyfin/values.yaml index 068c0ef..69170b3 100644 --- a/charts/jellyfin/values.yaml +++ b/charts/jellyfin/values.yaml @@ -85,8 +85,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: "" @@ -134,20 +143,24 @@ resources: {} # memory: 128Mi # -- Configure liveness probe for Jellyfin. +# Uses httpGet for compatibility with both IPv4 and IPv6. livenessProbe: - initialDelaySeconds: 10 - tcpSocket: + httpGet: + path: /health port: http + initialDelaySeconds: 10 # successThreshold: 1 # failureThreshold: 3 # timeoutSeconds: 1 # periodSeconds: 10 # -- Configure readiness probe for Jellyfin. +# 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 From 1744d240119ea3f066104fdc423bbf747249484c Mon Sep 17 00:00:00 2001 From: Aleksei Sviridkin Date: Fri, 7 Nov 2025 19:53:08 +0300 Subject: [PATCH 2/2] test(service): add IPv6 and dual-stack configuration tests Add helm-unittest tests for IPv6 and dual-stack Service configuration: - Default behavior (no ipFamilyPolicy/ipFamilies set) - SingleStack, PreferDualStack, RequireDualStack policies - IPv4 only, IPv6 only configurations - Dual-stack with IPv4 primary and IPv6 primary - Combined policy and families configurations Add NOTES.txt with IPv6/dual-stack information: - Display configured IP family policy - Show IP families list - Warning when IPv6 is primary (probe compatibility note) - Warning when IPv6 used without policy Tests ensure IPv6 and dual-stack work correctly for all scenarios. Co-Authored-By: Claude Signed-off-by: Aleksei Sviridkin --- charts/jellyfin/templates/NOTES.txt | 42 ++++++ charts/jellyfin/tests/service_ipv6_test.yaml | 128 +++++++++++++++++++ 2 files changed, 170 insertions(+) create mode 100644 charts/jellyfin/templates/NOTES.txt create mode 100644 charts/jellyfin/tests/service_ipv6_test.yaml diff --git a/charts/jellyfin/templates/NOTES.txt b/charts/jellyfin/templates/NOTES.txt new file mode 100644 index 0000000..0df2ce3 --- /dev/null +++ b/charts/jellyfin/templates/NOTES.txt @@ -0,0 +1,42 @@ +Thank you for installing {{ .Chart.Name }}. + +Your release is named {{ .Release.Name }}. + +To learn more about the release, try: + + $ helm status {{ .Release.Name }} + $ helm get all {{ .Release.Name }} + +{{- if .Values.ingress.enabled }} + +Jellyfin is available via Ingress at: +{{- range .Values.ingress.hosts }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ .host }}{{ (index .paths 0).path }} +{{- end }} +{{- else }} + +To access Jellyfin, you can use port-forwarding: + + $ kubectl port-forward --namespace {{ .Release.Namespace }} svc/{{ include "jellyfin.fullname" . }} {{ .Values.service.port }}:{{ .Values.service.port }} + +Then visit http://localhost:{{ .Values.service.port }} in your browser. +{{- 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 }} diff --git a/charts/jellyfin/tests/service_ipv6_test.yaml b/charts/jellyfin/tests/service_ipv6_test.yaml new file mode 100644 index 0000000..5dee731 --- /dev/null +++ b/charts/jellyfin/tests/service_ipv6_test.yaml @@ -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