Add optional direct-address Mumble service
Validate, publish and promote Mumble chart / chart (push) Successful in 47s

This commit is contained in:
feedc0de committed 2026-10-19 21:54:17 +02:00
1 parent 0fcc92852c
commit 8a17ea4c1c
5 files changed
+35

No files matched your search

+2
View File
@@ -14,6 +14,8 @@ The PostgreSQL subchart is optional. With `postgresql.enabled=true`, set `postgr
The homelab deployment is selected in [homelab-gitops](https://code.brunner.ninja/feedc0de/homelab-gitops/src/branch/main/apps/mumble). It uses the optional PostgreSQL subchart and keeps the existing `default/mumble` Service and Deployment names, the `mumble-secrets` and TLS Secrets, and TCP/UDP port 64738. The old shared PostgreSQL database is deliberately left intact as rollback data. `bootstrap-homelab-secrets.sh` is a guarded, one-time secret recovery/bootstrap helper; it does not deploy workloads. Back up the dedicated PostgreSQL PVC and both Mumble Secrets together.
`directAccess.enabled` optionally creates a second `mumble-direct` Service on the same TCP/UDP ports. Set `directAccess.externalIPs` to addresses already routed to a cluster node. This Service uses cluster-wide endpoint routing, so an address on one node can reach a ready Mumble pod on another node. It leaves the primary LoadBalancer Service and its client-IP policy unchanged. The homelab uses this for the Funkfeuer/OLSR address on `arschrock`.
Chart package versions come from Git tags using `git describe --tags --long`. The tag `v1.5.939` denotes the tested upstream Mumble release; a later chart-only commit publishes a distinct `1.5.939-N-gHASH` chart version. Source CI validates the chart, publishes it to the indexed `brunner.ninja` repository, and promotes only this chart's selected version in GitOps. CI has no Kubernetes credential.
The old `mumble-server.ini` file is ignored because it contains obsolete plaintext credentials. Never commit it, kubeconfigs, generated Secret values, or database dumps.
@@ -0,0 +1,23 @@
{{- if and .Values.mumble.enabled .Values.directAccess.enabled }}
apiVersion: v1
kind: Service
metadata:
name: mumble-direct
labels:
app.kubernetes.io/name: mumble
spec:
type: ClusterIP
externalIPs:
{{ toYaml .Values.directAccess.externalIPs | indent 4 }}
selector:
app.kubernetes.io/name: mumble
ports:
- name: mumble-tcp
port: 64738
targetPort: mumble-tcp
protocol: TCP
- name: mumble-udp
port: 64738
targetPort: mumble-udp
protocol: UDP
{{- end }}
+1
View File
@@ -4,6 +4,7 @@
"properties": {
"image": {"type": "object", "properties": {"repository": {"type": "string", "minLength": 1}, "tag": {"type": "string"}}},
"service": {"type": "object", "properties": {"type": {"enum": ["LoadBalancer", "ClusterIP"]}, "loadBalancerIP": {"type": "string"}, "externalTrafficPolicy": {"enum": ["Local", "Cluster"]}, "annotations": {"type": "object", "additionalProperties": {"type": "string"}}}},
"directAccess": {"type": "object", "properties": {"enabled": {"type": "boolean"}, "externalIPs": {"type": "array", "items": {"type": "string", "format": "ipv4"}}}, "if": {"properties": {"enabled": {"const": true}}}, "then": {"required": ["externalIPs"], "properties": {"externalIPs": {"minItems": 1}}}},
"database": {"type": "object", "properties": {"host": {"type": "string", "minLength": 1}}},
"secrets": {"type": "object", "properties": {"mumble": {"type": "string", "minLength": 1}, "postgresql": {"type": "string", "minLength": 1}, "tls": {"type": "string", "minLength": 1}}},
"config": {"type": "object", "properties": {"welcomeText": {"type": "string"}, "registrationName": {"type": "string"}, "registrationURL": {"type": "string"}, "registrationHostname": {"type": "string"}, "registrationLocation": {"type": "string"}}},
+3
View File
@@ -11,6 +11,9 @@ service:
annotations: {}
loadBalancerIP: ""
externalTrafficPolicy: Local
directAccess:
enabled: false
externalIPs: []
database:
host: postgresql
secrets:
+6
View File
@@ -29,5 +29,11 @@ pod = deployment['spec']['template']['spec']
assert [container['name'] for container in pod['initContainers']] == ['render-config']
assert pod['containers'][0]['image'].endswith('v1.5.939')
assert any(volume.get('secret', {}).get('secretName') == 'mumble-tls' for volume in pod['volumes'])
direct = render('--set', 'directAccess.enabled=true', '--set', 'directAccess.externalIPs[0]=10.12.4.170')
direct_service = next(doc for doc in direct if doc['kind'] == 'Service' and doc['metadata']['name'] == 'mumble-direct')
assert direct_service['spec']['externalIPs'] == ['10.12.4.170']
assert direct_service['spec']['type'] == 'ClusterIP'
assert 'externalTrafficPolicy' not in direct_service['spec']
assert {port['protocol'] for port in direct_service['spec']['ports']} == {'TCP', 'UDP'}
print('Mumble chart renders staged PostgreSQL and active Mumble without cleartext credentials.')
PY