Compare commits

..

4 Commits

Author SHA1 Message Date
gilgamezh 0a3f5dfc80 docs: add airvpn wireguard key + verification notes 2026-01-17 11:16:55 +01:00
gilgamezh 34f1e08f2c argocd: register gluetun and nzbget applications 2026-01-17 11:16:48 +01:00
gilgamezh bf8252970a media: add nzbget with pvc and proxy routing 2026-01-17 11:16:43 +01:00
gilgamezh 1bf2ea313f media: add gluetun (AirVPN wireguard) with proxy service 2026-01-17 11:16:38 +01:00
22 changed files with 802 additions and 0 deletions
+26
View File
@@ -0,0 +1,26 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: gluetun
namespace: argocd
annotations:
spec:
project: default
source:
repoURL: http://gitea-http.gitea.svc.cluster.local:3000/admin/turingpi.git
targetRevision: HEAD
path: custom_helm_charts/gluetun
helm:
releaseName: gluetun
valueFiles:
- ../../helm-values/gluetun_values.yaml
destination:
server: https://kubernetes.default.svc
namespace: default
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- ServerSideApply=true
+26
View File
@@ -0,0 +1,26 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: nzbget
namespace: argocd
annotations:
spec:
project: default
source:
repoURL: http://gitea-http.gitea.svc.cluster.local:3000/admin/turingpi.git
targetRevision: HEAD
path: custom_helm_charts/nzbget
helm:
releaseName: nzbget
valueFiles:
- ../../helm-values/nzbget_values.yaml
destination:
server: https://kubernetes.default.svc
namespace: default
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- ServerSideApply=true
+21
View File
@@ -0,0 +1,21 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj
+6
View File
@@ -0,0 +1,6 @@
apiVersion: v1
appVersion: "1.0"
description: Gluetun - VPN client with HTTP proxy
name: gluetun
version: 0.1.0
icon: https://raw.githubusercontent.com/qdm12/gluetun/master/.github/logo.png
+20
View File
@@ -0,0 +1,20 @@
# Usenet stack (Gluetun + NZBGet)
Service endpoints:
- NZBGet UI: nzbget.default.svc.cluster.local:6789
- Gluetun HTTP proxy: gluetun.default.svc.cluster.local:8888
AirVPN WireGuard values:
- Update `helm-values/gluetun_values.yaml`:
- `secret.privateKey` -> AirVPN WireGuard private key
- `secret.addresses` -> WireGuard tunnel address(es) (IPv4 /32 and optional IPv6)
- `env.SERVER_HOSTNAMES` -> stable AirVPN server hostname
- Alternatively set `secret.create: false` and provide a Secret named `gluetun-wireguard` with keys `WIREGUARD_PRIVATE_KEY` and `WIREGUARD_ADDRESSES`.
Validation:
- ArgoCD health: `argocd app get gluetun` and `argocd app get nzbget`
- WireGuard up: `kubectl -n default logs deploy/gluetun | rg -i "wireguard|tunnel"`
- VPN egress from NZBGet: `kubectl -n default exec deploy/nzbget -- curl -s ifconfig.me`
- NZBGet UI: `kubectl -n default port-forward deploy/nzbget 6789:6789`
Note: NZBGet is configured to use the HTTP proxy via `HTTP_PROXY`/`HTTPS_PROXY`. If your NNTP traffic does not honor proxy settings, consider using a proxy-aware downloader or running the downloader in the same pod as Gluetun.
@@ -0,0 +1,19 @@
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range .Values.ingress.hosts }}
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "gluetun.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get svc -w {{ template "gluetun.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "gluetun.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "gluetun.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8888 to use your application"
kubectl port-forward $POD_NAME 8888:{{ .Values.service.port }}
{{- end }}
@@ -0,0 +1,32 @@
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "gluetun.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "gluetun.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- if contains $name .Release.Name -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "gluetun.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}
@@ -0,0 +1,55 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ template "gluetun.fullname" . }}
labels:
app: {{ template "gluetun.name" . }}
chart: {{ template "gluetun.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ template "gluetun.name" . }}
release: {{ .Release.Name }}
template:
metadata:
labels:
app: {{ template "gluetun.name" . }}
release: {{ .Release.Name }}
spec:
volumes:
{{ toYaml .Values.volumes | indent 6 }}
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
securityContext:
{{ toYaml .Values.securityContext | indent 12 }}
env:
{{ toYaml .Values.env | indent 12 }}
ports:
- name: http-proxy
containerPort: {{ .Values.service.port }}
protocol: TCP
livenessProbe:
{{ toYaml .Values.livenessProbe | indent 12 }}
readinessProbe:
{{ toYaml .Values.readinessProbe | indent 12 }}
volumeMounts:
{{ toYaml .Values.volumeMounts | indent 12 }}
resources:
{{ toYaml .Values.resources | indent 12 }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{ toYaml . | indent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{ toYaml . | indent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{ toYaml . | indent 8 }}
{{- end }}
@@ -0,0 +1,38 @@
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "gluetun.fullname" . -}}
{{- $ingressPath := .Values.ingress.path -}}
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: {{ $fullName }}
labels:
app: {{ template "gluetun.name" . }}
chart: {{ template "gluetun.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
{{- with .Values.ingress.annotations }}
annotations:
{{ toYaml . | indent 4 }}
{{- end }}
spec:
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ . }}
http:
paths:
- path: {{ $ingressPath }}
backend:
serviceName: {{ $fullName }}
servicePort: http
{{- end }}
{{- end }}
@@ -0,0 +1,15 @@
{{- if .Values.secret.create -}}
apiVersion: v1
kind: Secret
metadata:
name: {{ .Values.secret.name }}
labels:
app: {{ template "gluetun.name" . }}
chart: {{ template "gluetun.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
type: Opaque
stringData:
WIREGUARD_PRIVATE_KEY: {{ .Values.secret.privateKey | quote }}
WIREGUARD_ADDRESSES: {{ .Values.secret.addresses | quote }}
{{- end }}
@@ -0,0 +1,19 @@
apiVersion: v1
kind: Service
metadata:
name: {{ template "gluetun.fullname" . }}
labels:
app: {{ template "gluetun.name" . }}
chart: {{ template "gluetun.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: {{ .Values.service.port }}
protocol: TCP
name: http-proxy
selector:
app: {{ template "gluetun.name" . }}
release: {{ .Release.Name }}
+100
View File
@@ -0,0 +1,100 @@
replicaCount: 1
image:
repository: qmcgaw/gluetun
tag: latest
pullPolicy: IfNotPresent
env:
- name: VPN_SERVICE_PROVIDER
value: "airvpn"
- name: VPN_TYPE
value: "wireguard"
- name: WIREGUARD_PRIVATE_KEY
valueFrom:
secretKeyRef:
name: gluetun-wireguard
key: WIREGUARD_PRIVATE_KEY
- name: WIREGUARD_ADDRESSES
valueFrom:
secretKeyRef:
name: gluetun-wireguard
key: WIREGUARD_ADDRESSES
- name: SERVER_HOSTNAMES
value: "REPLACE_ME"
- name: HTTPPROXY
value: "on"
- name: HTTPPROXY_LOG
value: "off"
- name: FIREWALL_INPUT_PORTS
value: "8888"
- name: TZ
value: "Europe/Amsterdam"
secret:
create: true
name: gluetun-wireguard
privateKey: "REPLACE_ME"
addresses: "REPLACE_ME"
service:
type: ClusterIP
port: 8888
ingress:
enabled: false
annotations:
kubernetes.io/ingress.class: nginx
kubernetes.io/tls-acme: "true"
path: /
hosts:
- gluetun.example.org
tls:
- secretName: gluetun-example-org
hosts:
- gluetun.example.org
volumes:
- name: dev-tun
hostPath:
path: /dev/net/tun
volumeMounts:
- name: dev-tun
mountPath: "/dev/net/tun"
securityContext:
allowPrivilegeEscalation: false
capabilities:
add:
- NET_ADMIN
livenessProbe:
tcpSocket:
port: 8888
initialDelaySeconds: 10
periodSeconds: 20
timeoutSeconds: 2
failureThreshold: 3
readinessProbe:
tcpSocket:
port: 8888
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3
resources:
requests:
memory: 128Mi
cpu: 100m
limits:
memory: 512Mi
cpu: 500m
nodeSelector: {}
tolerations: []
affinity: {}
+21
View File
@@ -0,0 +1,21 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj
+5
View File
@@ -0,0 +1,5 @@
apiVersion: v1
appVersion: "1.0"
description: NZBGet - Usenet downloader
name: nzbget
version: 0.1.0
@@ -0,0 +1,19 @@
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range .Values.ingress.hosts }}
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "nzbget.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get svc -w {{ template "nzbget.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "nzbget.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "nzbget.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:6789 to use your application"
kubectl port-forward $POD_NAME 6789:{{ .Values.service.port }}
{{- end }}
@@ -0,0 +1,32 @@
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "nzbget.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "nzbget.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- if contains $name .Release.Name -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "nzbget.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}
@@ -0,0 +1,53 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ template "nzbget.fullname" . }}
labels:
app: {{ template "nzbget.name" . }}
chart: {{ template "nzbget.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ template "nzbget.name" . }}
release: {{ .Release.Name }}
template:
metadata:
labels:
app: {{ template "nzbget.name" . }}
release: {{ .Release.Name }}
spec:
volumes:
{{ toYaml .Values.volumes | indent 6 }}
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
env:
{{ toYaml .Values.env | indent 12 }}
ports:
- name: http
containerPort: {{ .Values.service.port }}
protocol: TCP
livenessProbe:
{{ toYaml .Values.livenessProbe | indent 12 }}
readinessProbe:
{{ toYaml .Values.readinessProbe | indent 12 }}
volumeMounts:
{{ toYaml .Values.volumeMounts | indent 12 }}
resources:
{{ toYaml .Values.resources | indent 12 }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{ toYaml . | indent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{ toYaml . | indent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{ toYaml . | indent 8 }}
{{- end }}
@@ -0,0 +1,38 @@
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "nzbget.fullname" . -}}
{{- $ingressPath := .Values.ingress.path -}}
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: {{ $fullName }}
labels:
app: {{ template "nzbget.name" . }}
chart: {{ template "nzbget.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
{{- with .Values.ingress.annotations }}
annotations:
{{ toYaml . | indent 4 }}
{{- end }}
spec:
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ . }}
http:
paths:
- path: {{ $ingressPath }}
backend:
serviceName: {{ $fullName }}
servicePort: http
{{- end }}
{{- end }}
@@ -0,0 +1,19 @@
apiVersion: v1
kind: Service
metadata:
name: {{ template "nzbget.fullname" . }}
labels:
app: {{ template "nzbget.name" . }}
chart: {{ template "nzbget.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: {{ .Values.service.port }}
protocol: TCP
name: http
selector:
app: {{ template "nzbget.name" . }}
release: {{ .Release.Name }}
+82
View File
@@ -0,0 +1,82 @@
replicaCount: 1
image:
repository: lscr.io/linuxserver/nzbget
tag: latest
pullPolicy: IfNotPresent
env:
- name: PUID
value: "1000"
- name: PGID
value: "1000"
- name: TZ
value: "Europe/Amsterdam"
- name: HTTP_PROXY
value: "http://gluetun.default.svc.cluster.local:8888"
- name: HTTPS_PROXY
value: "http://gluetun.default.svc.cluster.local:8888"
- name: NO_PROXY
value: "localhost,127.0.0.1,.svc,.cluster.local"
service:
type: ClusterIP
port: 6789
ingress:
enabled: false
annotations:
kubernetes.io/ingress.class: nginx
kubernetes.io/tls-acme: "true"
path: /
hosts:
- nzbget.example.org
tls:
- secretName: nzbget-example-org
hosts:
- nzbget.example.org
volumes:
- name: plex-data
persistentVolumeClaim:
claimName: plex-data
volumeMounts:
- name: plex-data
mountPath: "/config"
subPath: "configs/nzbget"
- name: plex-data
mountPath: "/downloads"
subPath: "usenet"
livenessProbe:
tcpSocket:
port: 6789
initialDelaySeconds: 10
periodSeconds: 20
timeoutSeconds: 2
failureThreshold: 3
readinessProbe:
tcpSocket:
port: 6789
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3
resources:
requests:
memory: "500Mi"
cpu: "500m"
ephemeral-storage: "50Mi"
limits:
memory: "2Gi"
cpu: "2"
ephemeral-storage: "1Gi"
nodeSelector: {}
tolerations: []
affinity: {}
+87
View File
@@ -0,0 +1,87 @@
replicaCount: 1
image:
repository: qmcgaw/gluetun
tag: "latest"
pullPolicy: Always
env:
- name: VPN_SERVICE_PROVIDER
value: "airvpn"
- name: VPN_TYPE
value: "wireguard"
- name: WIREGUARD_PRIVATE_KEY
valueFrom:
secretKeyRef:
name: gluetun-wireguard
key: WIREGUARD_PRIVATE_KEY
- name: WIREGUARD_ADDRESSES
valueFrom:
secretKeyRef:
name: gluetun-wireguard
key: WIREGUARD_ADDRESSES
- name: SERVER_HOSTNAMES
value: "REPLACE_ME"
- name: HTTPPROXY
value: "on"
- name: HTTPPROXY_LOG
value: "off"
- name: FIREWALL_INPUT_PORTS
value: "8888"
- name: TZ
value: "Europe/Amsterdam"
secret:
create: true
name: gluetun-wireguard
privateKey: "REPLACE_ME"
addresses: "REPLACE_ME"
service:
type: ClusterIP
port: 8888
volumes:
- name: dev-tun
hostPath:
path: /dev/net/tun
volumeMounts:
- name: dev-tun
mountPath: "/dev/net/tun"
securityContext:
allowPrivilegeEscalation: false
capabilities:
add:
- NET_ADMIN
livenessProbe:
tcpSocket:
port: 8888
initialDelaySeconds: 10
periodSeconds: 20
timeoutSeconds: 2
failureThreshold: 3
readinessProbe:
tcpSocket:
port: 8888
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3
resources:
requests:
memory: 128Mi
cpu: 100m
limits:
memory: 512Mi
cpu: 500m
nodeSelector: {}
tolerations: []
affinity: {}
+69
View File
@@ -0,0 +1,69 @@
replicaCount: 1
image:
repository: lscr.io/linuxserver/nzbget
tag: "latest"
pullPolicy: Always
env:
- name: PUID
value: "1000"
- name: PGID
value: "1000"
- name: TZ
value: "Europe/Amsterdam"
- name: HTTP_PROXY
value: "http://gluetun.default.svc.cluster.local:8888"
- name: HTTPS_PROXY
value: "http://gluetun.default.svc.cluster.local:8888"
- name: NO_PROXY
value: "localhost,127.0.0.1,.svc,.cluster.local"
service:
type: ClusterIP
port: 6789
volumes:
- name: plex-data
persistentVolumeClaim:
claimName: "plex-data"
volumeMounts:
- name: plex-data
mountPath: "/config"
subPath: "configs/nzbget"
- name: plex-data
mountPath: "/downloads"
subPath: "usenet"
livenessProbe:
tcpSocket:
port: 6789
initialDelaySeconds: 10
periodSeconds: 20
timeoutSeconds: 2
failureThreshold: 3
readinessProbe:
tcpSocket:
port: 6789
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3
resources:
requests:
memory: "500Mi"
cpu: "500m"
ephemeral-storage: "50Mi"
limits:
memory: "2Gi"
cpu: "2"
ephemeral-storage: "1Gi"
nodeSelector: {}
tolerations: []
affinity: {}