Import manifests reverse-engineered from live cluster

Captured 2026-07-26 from rpi-master (k3s v1.30.3) and cleaned of runtime
fields. Six apps as per-app kustomizations: vaultwarden, searxng,
home-assistant, nginx, pihole(+unbound), unified-streaming.

Intentional divergences from live state:
- pihole WEBPASSWORD and USP_LICENSE_KEY moved from inline plaintext env
  to secretKeyRef (secrets gitignored; templates in secret.example.yaml)
- HA ingress defaultBackend fixed (pointed at nonexistent service)
- unifiedstreaming-svc kept as ClusterIP (LoadBalancer could never bind
  port 80 behind svclb-traefik)

Validated against the live cluster with kubectl apply --dry-run=server:
no immutable-field conflicts; one-time kubectl replace procedure for the
two env->secretKeyRef migrations documented in README.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
jasonwitty
2026-07-26 02:13:56 -07:00
parent ec9b422f87
commit 8afac39d03
40 changed files with 1179 additions and 1 deletions
+74
View File
@@ -0,0 +1,74 @@
# Originally installed via helm chart home-assistant-13.3.0 (release record no
# longer in cluster); managed as a raw manifest since. Selector labels are
# immutable — do not change them.
# NOTE: /config/configuration.yaml (on the PV, not in git) must keep
# http.trusted_proxies: [10.42.0.0/16] so traefik can reach HA from any node.
apiVersion: apps/v1
kind: Deployment
metadata:
name: home-assistant
namespace: home-assistant
labels:
app.kubernetes.io/instance: home-assistant
app.kubernetes.io/name: home-assistant
spec:
replicas: 1
revisionHistoryLimit: 3
selector:
matchLabels:
app.kubernetes.io/instance: home-assistant
app.kubernetes.io/name: home-assistant
strategy:
type: Recreate
template:
metadata:
labels:
app.kubernetes.io/instance: home-assistant
app.kubernetes.io/name: home-assistant
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: cpu
operator: In
values:
- arm
- key: controller
operator: NotIn
values:
- "true"
containers:
- name: home-assistant
image: ghcr.io/home-assistant/home-assistant:stable
imagePullPolicy: Always
env:
- name: TZ
value: UTC
ports:
- name: http
containerPort: 8123
protocol: TCP
startupProbe:
tcpSocket:
port: 8123
failureThreshold: 30
periodSeconds: 5
livenessProbe:
tcpSocket:
port: 8123
failureThreshold: 3
periodSeconds: 10
readinessProbe:
tcpSocket:
port: 8123
failureThreshold: 3
periodSeconds: 10
volumeMounts:
- name: config
mountPath: /config
volumes:
- name: config
persistentVolumeClaim:
claimName: home-assistant
+37
View File
@@ -0,0 +1,37 @@
# NOTE: the live object's defaultBackend pointed at a service named
# "home-assistant", which does not exist (the real service is
# "home-assistant-svc"). Fixed here — this is the one intentional divergence
# from the cluster state captured 2026-07-26.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: home-assistant
namespace: home-assistant
spec:
ingressClassName: traefik
defaultBackend:
service:
name: home-assistant-svc
port:
number: 80
rules:
- host: ha.wittyoneoff.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: home-assistant-svc
port:
number: 80
- host: ha-origin.wittyoneoff.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: home-assistant-svc
port:
number: 80
+8
View File
@@ -0,0 +1,8 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- namespace.yaml
- storage.yaml
- deployment.yaml
- service.yaml
- ingress.yaml
+4
View File
@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: home-assistant
+15
View File
@@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: home-assistant-svc
namespace: home-assistant
spec:
type: ClusterIP
selector:
app.kubernetes.io/instance: home-assistant
app.kubernetes.io/name: home-assistant
ports:
- name: http
port: 80
targetPort: 8123
protocol: TCP
+30
View File
@@ -0,0 +1,30 @@
# /config lives on GlusterFS (/mnt/gvolume0 mounted on every node).
# Known risk: HA recorder DB on gluster + non-atomic renames → occasional
# .storage write errors. See homelab notes.
apiVersion: v1
kind: PersistentVolume
metadata:
name: home-assistant-pv
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
volumeMode: Filesystem
hostPath:
path: /mnt/gvolume0/home-assistant
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: home-assistant
namespace: home-assistant
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: ""
volumeName: home-assistant-pv
+59
View File
@@ -0,0 +1,59 @@
# Created via Rancher originally — the workload.user.cattle.io selector label
# is immutable on the live object; do not change it.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: nginx
labels:
workload.user.cattle.io/workloadselector: apps.deployment-nginx-nginx
spec:
replicas: 3
selector:
matchLabels:
workload.user.cattle.io/workloadselector: apps.deployment-nginx-nginx
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
template:
metadata:
labels:
workload.user.cattle.io/workloadselector: apps.deployment-nginx-nginx
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: cpu
operator: In
values:
- arm
- key: controller
operator: NotIn
values:
- "true"
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: Always
ports:
- name: http
containerPort: 80
protocol: TCP
volumeMounts:
- name: vol-vnbxq
mountPath: /usr/share/nginx/html
subPath: www
- name: vol-vnbxq
mountPath: /etc/nginx/conf
subPath: conf
- name: vol-vnbxq
mountPath: /etc/nginx/conf.d
subPath: conf.d
volumes:
- name: vol-vnbxq
persistentVolumeClaim:
claimName: nginx
+28
View File
@@ -0,0 +1,28 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx
namespace: nginx
spec:
ingressClassName: traefik
rules:
- host: www.wittyoneoff.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx
port:
number: 80
- host: www.ramonaajj.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx
port:
number: 80
+8
View File
@@ -0,0 +1,8 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- namespace.yaml
- storage.yaml
- deployment.yaml
- service.yaml
- ingress.yaml
+4
View File
@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: nginx
+14
View File
@@ -0,0 +1,14 @@
apiVersion: v1
kind: Service
metadata:
name: nginx
namespace: nginx
spec:
type: ClusterIP
selector:
workload.user.cattle.io/workloadselector: apps.deployment-nginx-nginx
ports:
- name: http
port: 80
targetPort: 80
protocol: TCP
+35
View File
@@ -0,0 +1,35 @@
# Static site content + nginx config live on GlusterFS:
# /mnt/gvolume0/nginx/www → /usr/share/nginx/html
# /mnt/gvolume0/nginx/conf → /etc/nginx/conf
# /mnt/gvolume0/nginx/conf.d → /etc/nginx/conf.d
apiVersion: v1
kind: PersistentVolume
metadata:
name: nginx-gvolume0
spec:
capacity:
storage: 50Gi
accessModes:
- ReadWriteOnce
- ReadOnlyMany
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
volumeMode: Filesystem
hostPath:
path: /mnt/gvolume0/nginx
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nginx
namespace: nginx
spec:
accessModes:
- ReadWriteOnce
- ReadOnlyMany
- ReadWriteMany
resources:
requests:
storage: 50Gi
storageClassName: ""
volumeName: nginx-gvolume0
+86
View File
@@ -0,0 +1,86 @@
# DIVERGENCE from live state (intentional): the live deployment has WEBPASSWORD
# as a plaintext env value. Here it comes from the `pihole-admin` secret —
# create it (see secret.example.yaml) BEFORE applying this, or the pod will
# fail with CreateContainerConfigError.
apiVersion: apps/v1
kind: Deployment
metadata:
name: pihole
namespace: pihole
labels:
app: pihole
spec:
replicas: 1
selector:
matchLabels:
app: pihole
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 0
maxUnavailable: 1
template:
metadata:
labels:
app: pihole
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: cpu
operator: In
values:
- arm
- key: model
operator: In
values:
- raspi
containers:
- name: pihole
image: pihole/pihole:latest
imagePullPolicy: IfNotPresent
env:
- name: TZ
value: America/Los_Angeles
- name: WEBPASSWORD
valueFrom:
secretKeyRef:
name: pihole-admin
key: WEBPASSWORD
- name: PIHOLE_UID
value: "0"
ports:
- containerPort: 53
protocol: TCP
- containerPort: 53
protocol: UDP
- containerPort: 67
protocol: UDP
- containerPort: 80
protocol: TCP
- containerPort: 443
protocol: TCP
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: "1"
memory: 2Gi
securityContext:
privileged: true
volumeMounts:
- name: gv-pihole
mountPath: /etc/pihole
- name: gv-pihole-dnsmasq-volume
mountPath: /etc/dnsmasq.d
volumes:
- name: gv-pihole
persistentVolumeClaim:
claimName: pihole-gvolume0
- name: gv-pihole-dnsmasq-volume
persistentVolumeClaim:
claimName: pihole-dnsmasq-volume
+54
View File
@@ -0,0 +1,54 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: unbound
namespace: pihole
labels:
app: unbound
spec:
replicas: 3
selector:
matchLabels:
app: unbound
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
template:
metadata:
labels:
app: unbound
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: cpu
operator: In
values:
- arm
- key: model
operator: In
values:
- raspi
containers:
- name: unbound
image: docker.io/mvance/unbound-rpi:latest
imagePullPolicy: Always
ports:
- name: svc-53-udp
containerPort: 53
protocol: UDP
- name: svc-53-tcp
containerPort: 53
protocol: TCP
resources:
requests:
cpu: 250m
memory: 50Mi
limits:
cpu: "1"
memory: 1Gi
+10
View File
@@ -0,0 +1,10 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
# secret.example.yaml is intentionally NOT listed — copy it to secret.yaml
# (gitignored) and apply manually once per cluster.
resources:
- namespace.yaml
- storage.yaml
- deployment-pihole.yaml
- deployment-unbound.yaml
- service.yaml
+4
View File
@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: pihole
+13
View File
@@ -0,0 +1,13 @@
# Copy to secret.yaml (gitignored), set the real admin password, apply once:
# kubectl apply -f secret.yaml
# Or create directly without a file:
# kubectl create secret generic pihole-admin -n pihole \
# --from-literal=WEBPASSWORD='...'
apiVersion: v1
kind: Secret
metadata:
name: pihole-admin
namespace: pihole
type: Opaque
stringData:
WEBPASSWORD: CHANGE-ME
+53
View File
@@ -0,0 +1,53 @@
# pihole-svc is type LoadBalancer → k3s klipper-lb (svclb) binds host ports
# 8000/53/67 on the nodes it schedules on. NodePorts are pinned so they
# survive re-creation.
apiVersion: v1
kind: Service
metadata:
name: pihole-svc
namespace: pihole
spec:
type: LoadBalancer
externalTrafficPolicy: Cluster
selector:
app: pihole
ports:
- name: http-admin
port: 8000
targetPort: 80
nodePort: 31120
protocol: TCP
- name: tcp-53
port: 53
targetPort: 53
nodePort: 32580
protocol: TCP
- name: udp-53
port: 53
targetPort: 53
nodePort: 31281
protocol: UDP
- name: udp-67
port: 67
targetPort: 67
nodePort: 31025
protocol: UDP
---
apiVersion: v1
kind: Service
metadata:
name: unbound-service
namespace: pihole
spec:
type: ClusterIP
selector:
app: unbound
ports:
- name: udp-53
port: 53
targetPort: 53
protocol: UDP
- name: tcp-53
port: 53
targetPort: 53
protocol: TCP
+55
View File
@@ -0,0 +1,55 @@
apiVersion: v1
kind: PersistentVolume
metadata:
name: pihole-gvolume0-pv
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
volumeMode: Filesystem
hostPath:
path: /mnt/gvolume0/pihole
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pihole-dnsmasq-volume-pv
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
volumeMode: Filesystem
hostPath:
path: /mnt/gvolume0/pihole-dnsmasq-volume
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pihole-gvolume0
namespace: pihole
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: ""
volumeName: pihole-gvolume0-pv
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pihole-dnsmasq-volume
namespace: pihole
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: ""
volumeName: pihole-dnsmasq-volume-pv
+78
View File
@@ -0,0 +1,78 @@
# Helm release searxng-1723974683 (chart searxng-1.0.0) in the *default*
# namespace — the release is still recorded in the cluster, so if you ever
# `helm upgrade` it, helm and this manifest will fight. Prefer retiring the
# helm release (helm delete --no-hooks would delete resources; instead just
# treat this repo as the source of truth and never run helm against it).
# Names keep the timestamped release suffix because selectors are immutable.
# NOTE (faithful to live state): TZ value "America/Los Angeles" is missing the
# underscore — an invalid tzdata name, so searxng falls back to UTC. Kept as-is;
# fix to America/Los_Angeles when convenient.
apiVersion: apps/v1
kind: Deployment
metadata:
name: searxng-1723974683
namespace: default
labels:
app.kubernetes.io/instance: searxng-1723974683
app.kubernetes.io/name: searxng
spec:
replicas: 1
revisionHistoryLimit: 3
selector:
matchLabels:
app.kubernetes.io/instance: searxng-1723974683
app.kubernetes.io/name: searxng
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
template:
metadata:
labels:
app.kubernetes.io/instance: searxng-1723974683
app.kubernetes.io/name: searxng
spec:
containers:
- name: searxng-1723974683
image: searxng/searxng:latest
imagePullPolicy: Always
env:
- name: AUTOCOMPLETE
value: google
- name: BASE_URL
value: http://searxng.wittyoneoff.com/
- name: INSTANCE_NAME
value: witty-one-off-searxng
- name: TZ
value: America/Los Angeles
ports:
- name: http
containerPort: 8080
protocol: TCP
startupProbe:
httpGet:
path: /healthz
port: 8080
failureThreshold: 30
periodSeconds: 5
livenessProbe:
httpGet:
path: /healthz
port: 8080
failureThreshold: 3
periodSeconds: 10
readinessProbe:
httpGet:
path: /healthz
port: 8080
failureThreshold: 3
periodSeconds: 10
volumeMounts:
- name: searxng-config
mountPath: /etc/searxng/settings.yml
subPath: settings.yml
volumes:
- name: searxng-config
secret:
secretName: searxng-1723974683-config
+33
View File
@@ -0,0 +1,33 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: searxng-ingress
namespace: default
spec:
ingressClassName: traefik
defaultBackend:
service:
name: searxng-1723974683
port:
number: 8080
rules:
- host: searxng.wittyoneoff.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: searxng-1723974683
port:
number: 8080
- host: origin-searxng.wittyoneoff.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: searxng-1723974683
port:
number: 8080
+8
View File
@@ -0,0 +1,8 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
# secret.example.yaml is intentionally NOT listed — copy it to secret.yaml
# (gitignored) and apply manually once per cluster.
resources:
- deployment.yaml
- service.yaml
- ingress.yaml
+14
View File
@@ -0,0 +1,14 @@
# Copy to secret.yaml (gitignored), set a real secret_key, and apply once:
# kubectl apply -f secret.yaml
# The secret already exists in the cluster; this file only documents its shape.
apiVersion: v1
kind: Secret
metadata:
name: searxng-1723974683-config
namespace: default
type: Opaque
stringData:
settings.yml: |
server:
secret_key: CHANGE-ME
use_default_settings: true
+18
View File
@@ -0,0 +1,18 @@
apiVersion: v1
kind: Service
metadata:
name: searxng-1723974683
namespace: default
labels:
app.kubernetes.io/instance: searxng-1723974683
app.kubernetes.io/name: searxng
spec:
type: ClusterIP
selector:
app.kubernetes.io/instance: searxng-1723974683
app.kubernetes.io/name: searxng
ports:
- name: http
port: 8080
targetPort: http
protocol: TCP
+69
View File
@@ -0,0 +1,69 @@
# DIVERGENCE from live state (intentional): the live deployment has
# USP_LICENSE_KEY as a plaintext env value. Here it comes from the
# `usp-license` secret — create it (see secret.example.yaml) BEFORE applying
# this. The Rancher-era selector label is immutable; do not change it.
apiVersion: apps/v1
kind: Deployment
metadata:
name: unifiedstreaming
namespace: unified-streaming
labels:
workload.user.cattle.io/workloadselector: apps.deployment-unified-streaming-unifiedstreaming
spec:
replicas: 3
selector:
matchLabels:
workload.user.cattle.io/workloadselector: apps.deployment-unified-streaming-unifiedstreaming
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
template:
metadata:
labels:
app: unifiedstreaming
workload.user.cattle.io/workloadselector: apps.deployment-unified-streaming-unifiedstreaming
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: cpu
operator: In
values:
- arm
- key: controller
operator: NotIn
values:
- "true"
containers:
- name: unifiedstreaming
image: unifiedstreaming/origin:latest
imagePullPolicy: Always
env:
- name: USP_LICENSE_KEY
valueFrom:
secretKeyRef:
name: usp-license
key: USP_LICENSE_KEY
livenessProbe:
httpGet:
path: /
port: 80
failureThreshold: 3
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 80
failureThreshold: 3
periodSeconds: 10
volumeMounts:
- name: vol-apn2a
mountPath: /var/www/unified-origin
volumes:
- name: vol-apn2a
persistentVolumeClaim:
claimName: unified-streaming-pvc
+18
View File
@@ -0,0 +1,18 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: unified-streaming-ing
namespace: unified-streaming
spec:
ingressClassName: traefik
rules:
- host: unified.wittyoneoff.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: unifiedstreaming-svc
port:
number: 80
+10
View File
@@ -0,0 +1,10 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
# secret.example.yaml is intentionally NOT listed — copy it to secret.yaml
# (gitignored) and apply manually once per cluster.
resources:
- namespace.yaml
- storage.yaml
- deployment.yaml
- service.yaml
- ingress.yaml
+4
View File
@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: unified-streaming
@@ -0,0 +1,16 @@
# Copy to secret.yaml (gitignored), paste the real USP license key, apply once:
# kubectl apply -f secret.yaml
# Or create directly:
# kubectl create secret generic usp-license -n unified-streaming \
# --from-literal=USP_LICENSE_KEY='<base64-looking license blob>'
# The current key can be read from the live deployment:
# kubectl get deploy -n unified-streaming unifiedstreaming \
# -o jsonpath='{.spec.template.spec.containers[0].env[?(@.name=="USP_LICENSE_KEY")].value}'
apiVersion: v1
kind: Secret
metadata:
name: usp-license
namespace: unified-streaming
type: Opaque
stringData:
USP_LICENSE_KEY: CHANGE-ME
+18
View File
@@ -0,0 +1,18 @@
# ClusterIP on purpose: this was type LoadBalancer for ~2 years, but klipper-lb
# can never bind host port 80 (svclb-traefik owns it on every node), so the
# svclb pods sat Pending forever. Traffic flows through the ingress. Changed
# to ClusterIP 2026-07-26.
apiVersion: v1
kind: Service
metadata:
name: unifiedstreaming-svc
namespace: unified-streaming
spec:
type: ClusterIP
selector:
app: unifiedstreaming
ports:
- name: http
port: 80
targetPort: 80
protocol: TCP
+32
View File
@@ -0,0 +1,32 @@
# Origin content (ism/ismv etc.) on GlusterFS, served by all replicas.
apiVersion: v1
kind: PersistentVolume
metadata:
name: unified-streaming-pv
spec:
capacity:
storage: 100Gi
accessModes:
- ReadWriteOnce
- ReadOnlyMany
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
volumeMode: Filesystem
hostPath:
path: /mnt/gvolume0/unified-streaming
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: unified-streaming-pvc
namespace: unified-streaming
spec:
accessModes:
- ReadWriteOnce
- ReadOnlyMany
- ReadWriteMany
resources:
requests:
storage: 100Gi
storageClassName: ""
volumeName: unified-streaming-pv
+75
View File
@@ -0,0 +1,75 @@
# Originally installed via helm chart vaultwarden-5.1.0 (release record no longer
# in cluster); managed as a raw manifest since. Selector labels are immutable —
# do not change them.
apiVersion: apps/v1
kind: Deployment
metadata:
name: bitwarden-vaultwarden
namespace: bitwarden
labels:
app.kubernetes.io/instance: bitwarden
app.kubernetes.io/name: vaultwarden
spec:
replicas: 1
revisionHistoryLimit: 3
selector:
matchLabels:
app.kubernetes.io/instance: bitwarden
app.kubernetes.io/name: vaultwarden
strategy:
type: Recreate
template:
metadata:
labels:
app.kubernetes.io/instance: bitwarden
app.kubernetes.io/name: vaultwarden
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: cpu
operator: In
values:
- arm
- key: controller
operator: NotIn
values:
- "true"
containers:
- name: bitwarden-vaultwarden
image: vaultwarden/server:1.35.4
imagePullPolicy: IfNotPresent
env:
- name: DATA_FOLDER
value: config
ports:
- name: http
containerPort: 80
protocol: TCP
- name: websocket
containerPort: 3012
protocol: TCP
startupProbe:
tcpSocket:
port: 80
failureThreshold: 30
periodSeconds: 5
livenessProbe:
tcpSocket:
port: 80
failureThreshold: 3
periodSeconds: 10
readinessProbe:
tcpSocket:
port: 80
failureThreshold: 3
periodSeconds: 10
volumeMounts:
- name: config
mountPath: /config
volumes:
- name: config
persistentVolumeClaim:
claimName: bitwarden-gvolume0
+23
View File
@@ -0,0 +1,23 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: bitwarden
namespace: bitwarden
spec:
ingressClassName: traefik
defaultBackend:
service:
name: bitwarden-vaultwarden-svc
port:
number: 8080
rules:
- host: pm.wittyoneoff.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: bitwarden-vaultwarden-svc
port:
number: 8080
+8
View File
@@ -0,0 +1,8 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- namespace.yaml
- storage.yaml
- deployment.yaml
- service.yaml
- ingress.yaml
+4
View File
@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: bitwarden
+19
View File
@@ -0,0 +1,19 @@
apiVersion: v1
kind: Service
metadata:
name: bitwarden-vaultwarden-svc
namespace: bitwarden
spec:
type: ClusterIP
selector:
app.kubernetes.io/instance: bitwarden
app.kubernetes.io/name: vaultwarden
ports:
- name: http
port: 8080
targetPort: 80
protocol: TCP
- name: websocket
port: 3012
targetPort: websocket
protocol: TCP
+30
View File
@@ -0,0 +1,30 @@
# GlusterFS-backed volume: /mnt/gvolume0 is the gluster mount present on every node.
apiVersion: v1
kind: PersistentVolume
metadata:
name: bitwarden-pv
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
- ReadWriteMany
- ReadOnlyMany
persistentVolumeReclaimPolicy: Retain
volumeMode: Filesystem
hostPath:
path: /mnt/gvolume0/bitwarden
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: bitwarden-gvolume0
namespace: bitwarden
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: ""
volumeName: bitwarden-pv