Compare commits

..
1 Commits
Author SHA1 Message Date
ivanch ddfca37fba infra: add haven-notify Deployment/Service/Ingress manifest
Moved from server-scripts/haven-notify/deploy. Haven Notify is an
internal Discord webhook notifier, catalogued under infra/ alongside
Beszel/WireGuard/Code Config per the repo README.
2026-07-13 12:06:28 -03:00
86 changed files with 1239 additions and 2991 deletions
-4
View File
@@ -1,4 +0,0 @@
.gitattributes text eol=lf
*.yaml text eol=lf
*.yml text eol=lf
*.md text eol=lf
-42
View File
@@ -1,42 +0,0 @@
name: Trigger Renovate
on:
workflow_dispatch: {}
jobs:
trigger-renovate:
name: Trigger Renovate
runs-on: runner-slim-amd64
env:
KUBE_CONFIG: ${{ secrets.KUBE_CONFIG }}
steps:
- name: Create a one-off Renovate job
shell: bash
run: |
set -eu
if [ -z "${KUBE_CONFIG}" ]; then
echo "KUBE_CONFIG is not set or is empty."
exit 1
fi
WORK_DIR="${RUNNER_TEMP:-/tmp}/renovate-${GITHUB_RUN_ID:-$$}"
mkdir -p "${WORK_DIR}"
trap 'rm -rf "${WORK_DIR}"' EXIT
apk add --no-cache curl
KUBECTL_VERSION="$(curl -fsSL https://dl.k8s.io/release/stable.txt)"
curl -fsSLo "${WORK_DIR}/kubectl" "https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/amd64/kubectl"
chmod 0755 "${WORK_DIR}/kubectl"
KUBECONFIG="${WORK_DIR}/kubeconfig"
umask 077
printf '%s' "${KUBE_CONFIG}" | tr -d '\r' > "${KUBECONFIG}"
RUN_ID="$(printf '%s' "${GITHUB_RUN_ID:-$(date -u +%Y%m%d%H%M%S)}" | tr -cd 'a-z0-9')"
JOB_NAME="renovate-manual-${RUN_ID}"
"${WORK_DIR}/kubectl" --kubeconfig "${KUBECONFIG}" version --client
"${WORK_DIR}/kubectl" --kubeconfig "${KUBECONFIG}" --namespace cronjobs get cronjob renovate
"${WORK_DIR}/kubectl" --kubeconfig "${KUBECONFIG}" --namespace cronjobs create job "${JOB_NAME}" --from=cronjob/renovate
"${WORK_DIR}/kubectl" --kubeconfig "${KUBECONFIG}" --namespace cronjobs get job "${JOB_NAME}" -o wide
+13 -11
View File
@@ -1,15 +1,17 @@
media/
default/*tt*
certs/ca*
lab/*
sandbox/*
!lab/nfs-pod.yaml
rbac
cronjobs
*.crt
*.key
*.pem
*.pfx
# Secrets & Environment files
.env
.env.*
*.env
group_vars/**/vault.yml
!group_vars/**/vault.yml.example
*kubeconfig*
chacal/
# Ansible artifacts
*.retry
secrets/
+54 -22
View File
@@ -12,25 +12,57 @@ For setup details, see [SETUP.md](SETUP.md).
The repository name references my local TLD, `.haven` ;)
## Repository Layout
```
haven/
├── bootstrap/
├── namespaces.yaml # cluster namespaces
│ ├── secretstores.yaml # cluster secret stores for BitWarden ESO
│ ├── address-pool.yaml # cluster IP pool for MetalLB
│ ├── argocd-install/ # Argo CD install manifests + ingress
│ └── root-app.yaml # root Application watching apps/root
├── secrets/
│ ├── adguard.yaml # adguard credentials from BitWarden
│ ├── <app>.yaml # <app> credentials from BitWarden
│ └── ...
├── apps/
│ ├── root/
│ │ ├── kustomization.yaml # points to applicationset.yaml
│ │ └── applicationset.yaml# auto-discovers apps/*/*.yaml
│ └── <namespace>/ # e.g., dev/, default/, infra/, monitoring/
│ ├── <app-1>.yaml # all-in-one manifest per app
│ ├── <app-2>.yaml # ...
| └──── ...
```
## Namespaces
- default
- ArchiveBox
- Homarr
- Homepage
- It-tools
- Notepad
- Searxng
- Uptimekuma
- Vaultwarden
- OpenWebUI
- Paperless
- cloud
- Cloudreve
- Slink
- dns
- AdGuardHome
- AdGuardSync
- infra
- [Haven Notify](https://git.ivanch.me/ivanch/server-scripts/src/branch/main/haven-notify)
- Beszel
- Beszel Agent (running as a DaemonSet)
- Code Config (VS Code for internal config editing)
- WireGuard Easy
- dev
- Gitea Runner (x64)
- Gitea Runner (arm64)
- monitoring
- Grafana
- Prometheus
- Node Exporter
- Kube State Metrics
- Loki
- Alloy
#### Miscellaneous namespaces
- lab (a playground/sandbox namespace)
- nfs-pod (for testing and accessing NFS mounts)
- metallb-system
- MetalLB components
- cert-manager
- cert-manager components
- docker-ingress
- nginx ingress controller components for Docker-based services
## Todo
- Move ArchiveBox data to its own PVC on the NAS
- Move Uptime Kuma to the infra namespace
- Add links to each application's documentation
- Add links to server scripts
- Move Alloy to the monitoring namespace
- Install Loki, Grafana, and Prometheus via Helm charts
- Configure Loki and Prometheus to use PVCs
+11
View File
@@ -0,0 +1,11 @@
# Helm configuration for Alloy (OSS monitoring collector)
This directory contains Helm configuration for deploying Grafana Alloy, an open-source observability data collector.
## Quick Install
```bash
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update
helm install alloy grafana/alloy --namespace alloy -f values.yaml
```
+107
View File
@@ -0,0 +1,107 @@
alloy:
clustering:
enabled: false # Single node deployment
configMap:
create: true
content: |-
discovery.kubernetes "all_pods" {
role = "pod"
selectors {
role = "pod"
field = "spec.nodeName=" + coalesce(env("HOSTNAME"), constants.hostname)
}
}
discovery.relabel "all_pods" {
targets = discovery.kubernetes.all_pods.targets
rule {
source_labels = ["__meta_kubernetes_namespace"]
target_label = "namespace"
}
rule {
source_labels = ["__meta_kubernetes_pod_name"]
target_label = "pod"
}
rule {
source_labels = ["__meta_kubernetes_pod_container_name"]
target_label = "container"
}
rule {
source_labels = ["__meta_kubernetes_pod_label_app_kubernetes_io_name"]
target_label = "app"
}
}
loki.source.kubernetes "all_logs" {
targets = discovery.relabel.all_pods.output
forward_to = [loki.write.main.receiver]
}
discovery.kubernetes "shared_pods" {
role = "pod"
selectors {
role = "pod"
field = "metadata.namespace=chacal"
}
}
discovery.relabel "shared_pods" {
targets = discovery.kubernetes.shared_pods.targets
rule {
source_labels = ["__meta_kubernetes_namespace"]
target_label = "namespace"
}
rule {
source_labels = ["__meta_kubernetes_pod_name"]
target_label = "pod"
}
rule {
source_labels = ["__meta_kubernetes_pod_container_name"]
target_label = "container"
}
rule {
source_labels = ["__meta_kubernetes_pod_label_app_kubernetes_io_name"]
target_label = "app"
}
}
loki.source.kubernetes "shared_logs" {
targets = discovery.relabel.shared_pods.output
forward_to = [loki.write.shared.receiver]
}
loki.write "main" {
endpoint {
url = "http://loki.monitoring.svc.cluster.local:3100/loki/api/v1/push"
headers = {
"X-Scope-OrgID" = "main",
}
}
}
loki.write "shared" {
endpoint {
url = "http://loki.monitoring.svc.cluster.local:3100/loki/api/v1/push"
headers = {
"X-Scope-OrgID" = "chacal",
}
}
}
mounts:
varlog: true # Mount host /var/log for pod logs
controller:
type: daemonset # Run on every node
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 200m
memory: 256Mi
-4
View File
@@ -1,4 +0,0 @@
---
profile: basic
exclude_paths:
- collections/
-13
View File
@@ -1,13 +0,0 @@
# Encrypted secrets
group_vars/all/vault.yml
# Installed collections
collections/
# Ansible retry files
*.retry
# Local controller environment and test caches
.venv/
__pycache__/
.pytest_cache/
-9
View File
@@ -1,9 +0,0 @@
[defaults]
inventory = inventory.yml
host_key_checking = True
retry_files_enabled = False
stdout_callback = default
result_format = yaml
collections_path = ./collections
roles_path = ./roles
interpreter_python = auto_silent
-53
View File
@@ -1,53 +0,0 @@
---
# Proxmox connection: local API access (the controller reaches the node directly).
# This is the "proxmox" group — not an SSH target, just connection params.
all:
children:
proxmox_nodes:
hosts:
otherside:
ansible_host: otherside.haven
ansible_connection: local # we call the Proxmox API, not SSH
astrid:
ansible_host: astrid.haven
ansible_connection: local # we call the Proxmox API, not SSH
k3s_cluster:
children:
grp_k3s_server: # group name == group_vars/grp_k3s_server.yml
hosts:
iris:
ansible_host: iris.haven
ansible_user: root
ansible_python_interpreter: /usr/bin/python3
grp_k3s_agent: # group name == group_vars/grp_k3s_agent.yml
hosts:
vega:
ansible_host: vega.haven
ansible_user: root
ansible_python_interpreter: /usr/bin/python3
nebula:
ansible_host: nebula.haven
ansible_user: root
ansible_python_interpreter: /usr/bin/python3
nexus:
ansible_host: nexus.haven
ansible_user: root
ansible_python_interpreter: /usr/bin/python3
polaris:
ansible_host: polaris.haven
ansible_user: root
ansible_python_interpreter: /usr/bin/python3
lxcs:
children:
grp_docker_build: # group name == group_vars/grp_docker_build.yml
hosts:
docker_build:
ansible_host: docker-build.haven
ansible_user: root
ansible_python_interpreter: /usr/bin/python3
grp_redis: # group name == group_vars/grp_redis.yml
hosts:
redis:
ansible_host: redis.haven
ansible_user: root
ansible_python_interpreter: /usr/bin/python3
-108
View File
@@ -1,108 +0,0 @@
## Updates k3s in the entire cluster
- name: Update k3s Control Plane
hosts: grp_k3s_server
serial: 1
gather_facts: false
become: true
tasks:
- name: Update k3s on control plane node
ansible.builtin.shell: >
sh <(curl -sfL https://get.k3s.io)
args:
executable: /bin/bash
register: k3s_update
- name: Print update output
ansible.builtin.debug:
var: k3s_update
- name: Update k3s Agents
hosts: grp_k3s_agent
serial: 1
gather_facts: false
become: true
tasks:
- name: Cordon agent node
ansible.builtin.command: kubectl cordon {{ inventory_hostname }}
delegate_to: "{{ groups['grp_k3s_server'][0] }}"
environment:
KUBECONFIG: /etc/rancher/k3s/k3s.yaml
ignore_errors: true
- name: Drain agent node
ansible.builtin.command: >
kubectl drain {{ inventory_hostname }}
--ignore-daemonsets
--delete-emptydir-data
--force
--timeout=60s
delegate_to: "{{ groups['grp_k3s_server'][0] }}"
environment:
KUBECONFIG: /etc/rancher/k3s/k3s.yaml
ignore_errors: true
- name: Kill k3s-agent process
ansible.builtin.shell: k3s-killall.sh
ignore_errors: true
- name: Update k3s on agent node
ansible.builtin.shell: >
sh <(curl -sfL https://get.k3s.io)
args:
executable: /bin/bash
register: k3s_update
- name: Restart k3s-agent service
ansible.builtin.systemd:
name: k3s-agent
state: restarted
- name: Fetch authoritative CA bundle from control-plane
ansible.builtin.slurp:
src: /var/lib/rancher/k3s/server/tls/{{ item }}
delegate_to: "{{ groups['grp_k3s_server'][0] }}"
register: ca_bundle
loop:
- client-ca.crt
- server-ca.crt
- name: Install server CAs into agent trust store
ansible.builtin.copy:
dest: "/var/lib/rancher/k3s/agent/{{ item.item }}"
content: "{{ item.content | b64decode }}"
owner: root
group: root
mode: "0600"
loop: "{{ ca_bundle.results }}"
loop_control:
label: "{{ item.item }}"
- name: Stop agent and clear stale client certs signed by old CA
ansible.builtin.shell: |
systemctl stop k3s-agent
rm -f /var/lib/rancher/k3s/agent/client-kubelet.crt \
/var/lib/rancher/k3s/agent/client-k3s-controller.crt \
/var/lib/rancher/k3s/agent/client-kube-proxy.crt \
/var/lib/rancher/k3s/agent/serving-kubelet.crt \
/var/lib/rancher/k3s/agent/kubelet.kubeconfig \
/var/lib/rancher/k3s/agent/k3scontroller.kubeconfig \
/var/lib/rancher/k3s/agent/kubeproxy.kubeconfig \
/var/lib/rancher/k3s/agent/client-kubeconfig.yaml
args:
executable: /bin/bash
- name: Restart k3s-agent so it re-issues certs against the server CA
ansible.builtin.systemd:
name: k3s-agent
state: restarted
- name: Print update output
ansible.builtin.debug:
var: k3s_update
- name: Uncordon agent node
ansible.builtin.command: kubectl uncordon {{ inventory_hostname }}
delegate_to: "{{ groups['grp_k3s_server'][0] }}"
environment:
KUBECONFIG: /etc/rancher/k3s/k3s.yaml
ignore_errors: true
-2
View File
@@ -1,2 +0,0 @@
-r requirements-python.txt
ansible-lint==26.6.0
-3
View File
@@ -1,3 +0,0 @@
ansible-core==2.21.4
proxmoxer==2.3.0
requests==2.34.2
-6
View File
@@ -1,6 +0,0 @@
---
collections:
- name: community.proxmox
version: "2.0.0"
- name: community.general
version: "13.4.0"
-128
View File
@@ -1,128 +0,0 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: affine
namespace: cloud
labels:
app: affine
spec:
replicas: 1
selector:
matchLabels:
app: affine
strategy:
type: Recreate
template:
metadata:
labels:
app: affine
spec:
containers:
- name: affine
image: ghcr.io/toeverything/affine:0.27.4
command:
[
"sh",
"-c",
"node ./scripts/self-host-predeploy.js && node ./dist/main.js",
]
env:
- name: AFFINE_CONFIG_PATH
value: "/root/.affine/config"
- name: AFFINE_SERVER_EXTERNAL_URL
value: "http://affine.haven"
- name: AFFINE_SERVER_HOST
value: "0.0.0.0"
- name: AFFINE_SERVER_PORT
value: "3010"
- name: AFFINE_SERVER_HTTPS
value: "false"
- name: AFFINE_SERVER_SUBPATH
value: "/"
- name: AFFINE_ENABLE_SYNC_FROM_STARTUP
value: "true"
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: affine-secret
key: DB_CONNECTION_URL
- name: REDIS_SERVER_HOST
value: "redis.haven"
- name: REDIS_SERVER_PORT
value: "6379"
ports:
- containerPort: 3010
name: http
readinessProbe:
httpGet:
path: /
port: 3010
initialDelaySeconds: 20
periodSeconds: 10
failureThreshold: 6
resources:
requests:
cpu: 200m
memory: 512Mi
limits:
cpu: 2000m
memory: 2Gi
volumeMounts:
- name: config
mountPath: /root/.affine/config
volumes:
- name: config
persistentVolumeClaim:
claimName: affine-config
terminationGracePeriodSeconds: 30
---
apiVersion: v1
kind: Service
metadata:
name: affine
namespace: cloud
labels:
app: affine
spec:
type: ClusterIP
selector:
app: affine
ports:
- name: http
port: 3010
protocol: TCP
targetPort: http
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: affine-config
namespace: cloud
spec:
storageClassName: "nfs-client"
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: affine
namespace: cloud
labels:
app: affine
spec:
rules:
- host: affine.haven
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: affine
port:
number: 3010
-39
View File
@@ -1,39 +0,0 @@
apiVersion: batch/v1
kind: CronJob
metadata:
name: renovate
namespace: cronjobs
spec:
schedule: "0 12 * * 0" # every Sunday 12:00
concurrencyPolicy: Forbid
jobTemplate:
spec:
template:
spec:
containers:
- name: renovate
image: renovate/renovate:44.103.7
args:
- ivanch/haven
env:
- name: LOG_LEVEL
value: debug
- name: RENOVATE_AUTODISCOVER
value: "false"
- name: RENOVATE_PLATFORM
value: "gitea"
- name: RENOVATE_ENDPOINT
value: "https://git.ivanch.me"
- name: RENOVATE_GIT_AUTHOR
value: "Renovate Bot <bot@renovateapp.com>"
- name: RENOVATE_TOKEN
valueFrom:
secretKeyRef:
name: renovate-bot
key: RENOVATE_TOKEN
- name: RENOVATE_GITHUB_COM_TOKEN
valueFrom:
secretKeyRef:
name: renovate-bot
key: RENOVATE_GITHUB_COM_TOKEN
restartPolicy: Never
-151
View File
@@ -1,151 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: changedetection
namespace: default
labels:
app.kubernetes.io/name: changedetection
spec:
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app.kubernetes.io/name: changedetection
strategy:
type: Recreate
template:
metadata:
labels:
app.kubernetes.io/name: changedetection
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- iris
containers:
- name: changedetection
image: lscr.io/linuxserver/changedetection.io:latest
imagePullPolicy: Always
env:
- name: PUID
value: "1000"
- name: PGID
value: "1000"
- name: TZ
value: "Etc/UTC"
- name: BASE_URL
value: "http://change.haven/"
- name: PLAYWRIGHT_DRIVER_URL
value: "ws://localhost:3000"
ports:
- containerPort: 5000
name: http
protocol: TCP
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 2000m
memory: 1Gi
securityContext:
allowPrivilegeEscalation: false
runAsUser: 0
volumeMounts:
- name: config
mountPath: /config
- name: browser-sockpuppet-chrome
image: dgtlmoon/sockpuppetbrowser:latest
imagePullPolicy: Always
env:
- name: SCREEN_WIDTH
value: "1920"
- name: SCREEN_HEIGHT
value: "1024"
- name: SCREEN_DEPTH
value: "16"
- name: MAX_CONCURRENT_CHROME_PROCESSES
value: "10"
ports:
- containerPort: 3000
name: ws
protocol: TCP
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 2000m
memory: 4Gi
securityContext:
allowPrivilegeEscalation: false
capabilities:
add:
- SYS_ADMIN
drop:
- ALL
volumes:
- name: config
persistentVolumeClaim:
claimName: changedetection-config
dnsPolicy: ClusterFirst
restartPolicy: Always
terminationGracePeriodSeconds: 30
---
apiVersion: v1
kind: Service
metadata:
name: changedetection
namespace: default
labels:
app.kubernetes.io/name: changedetection
spec:
type: ClusterIP
selector:
app.kubernetes.io/name: changedetection
ports:
- name: http
port: 5000
protocol: TCP
targetPort: http
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: changedetection-config
namespace: default
spec:
storageClassName: "nfs-client"
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
limits:
storage: 2Gi
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: changedetection
namespace: default
labels:
app.kubernetes.io/name: changedetection
spec:
rules:
- host: change.haven
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: changedetection
port:
number: 5000
-129
View File
@@ -1,129 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: playwright
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: playwright
strategy:
type: Recreate
template:
metadata:
labels:
app: playwright
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- preference:
matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- iris
weight: 100
containers:
- command:
- npx
- -y
- playwright@1.58.0
- run-server
- --port
- "3000"
- --host
- 0.0.0.0
env:
- name: TZ
value: America/Sao_Paulo
image: mcr.microsoft.com/playwright:v1.63.0-noble
name: playwright
ports:
- containerPort: 3000
protocol: TCP
resources:
limits:
cpu: "4"
memory: 4Gi
requests:
cpu: 500m
memory: 512Mi
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /dev/shm
name: dshm
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
volumes:
- emptyDir:
medium: Memory
name: dshm
status:
availableReplicas: 1
conditions:
- lastTransitionTime: "2026-05-29T15:54:24Z"
lastUpdateTime: "2026-07-22T10:14:35Z"
message: ReplicaSet "playwright-86c74d7c78" has successfully progressed.
reason: NewReplicaSetAvailable
status: "True"
type: Progressing
- lastTransitionTime: "2026-08-28T06:04:14Z"
lastUpdateTime: "2026-08-28T06:04:14Z"
message: Deployment has minimum availability.
reason: MinimumReplicasAvailable
status: "True"
type: Available
observedGeneration: 95
readyReplicas: 1
replicas: 1
terminatingReplicas: 0
updatedReplicas: 1
---
apiVersion: v1
kind: Service
metadata:
name: playwright
namespace: default
spec:
internalTrafficPolicy: Cluster
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- port: 3000
protocol: TCP
targetPort: 3000
selector:
app: playwright
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: playwright
namespace: default
spec:
rules:
- host: playwright.haven
http:
paths:
- backend:
service:
name: playwright
port:
number: 3000
path: /
pathType: Prefix
status:
loadBalancer:
ingress:
- ip: 192.168.20.204
-110
View File
@@ -1,110 +0,0 @@
---
# 1) Deployment - Stirling-PDF
apiVersion: apps/v1
kind: Deployment
metadata:
name: stirlingpdf
namespace: default
labels:
app: stirlingpdf
spec:
replicas: 1
selector:
matchLabels:
app: stirlingpdf
template:
metadata:
labels:
app: stirlingpdf
spec:
containers:
- name: stirlingpdf
image: stirlingtools/stirling-pdf:latest
imagePullPolicy: Always
env:
- name: TZ
value: "America/Sao_Paulo"
- name: DOCKER_ENABLE_SECURITY
value: "false"
- name: SECURITY_ENABLELOGIN
value: "false"
ports:
- containerPort: 8080
name: http
readinessProbe:
httpGet:
path: /
port: 8080
initialDelaySeconds: 20
periodSeconds: 10
resources:
requests:
cpu: 100m
memory: 1Gi
limits:
cpu: 2000m
memory: 2Gi
securityContext:
allowPrivilegeEscalation: false
runAsUser: 0
volumeMounts:
- name: config
mountPath: /configs
volumes:
- name: config
persistentVolumeClaim:
claimName: stirlingpdf-config
terminationGracePeriodSeconds: 30
---
# 2) Service
apiVersion: v1
kind: Service
metadata:
name: stirlingpdf
namespace: default
labels:
app: stirlingpdf
spec:
type: ClusterIP
selector:
app: stirlingpdf
ports:
- name: http
port: 8080
protocol: TCP
targetPort: http
---
# 3) PersistentVolumeClaim
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: stirlingpdf-config
namespace: default
spec:
storageClassName: "nfs-client"
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
# 4) Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: stirlingpdf
namespace: default
labels:
app: stirlingpdf
spec:
rules:
- host: stirling.haven
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: stirlingpdf
port:
number: 8080
-198
View File
@@ -1,198 +0,0 @@
# --- ConfigMap for the AMD64 Runner ---
apiVersion: v1
kind: ConfigMap
metadata:
name: gitea-runner-amd64-config
namespace: dev
data:
config.yaml: |
# Registration token and Gitea instance URL should be managed via secrets
runner:
capacity: 4
timeout: 1h
labels:
- "ubuntu-amd64:docker://docker.gitea.com/runner-images:ubuntu-latest"
- "ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest"
- "ubuntu-slim:docker://docker.gitea.com/runner-images:ubuntu-latest-slim"
- "runner-full:docker://git.ivanch.me/ivanch/runner-images:full"
- "runner-slim:docker://git.ivanch.me/ivanch/runner-images:slim"
- "runner-full-amd64:docker://git.ivanch.me/ivanch/runner-images:full"
- "runner-slim-amd64:docker://git.ivanch.me/ivanch/runner-images:slim"
---
# --- ConfigMap for the ARM64 Runner ---
apiVersion: v1
kind: ConfigMap
metadata:
name: gitea-runner-arm64-config
namespace: dev
data:
config.yaml: |
runner:
capacity: 4
timeout: 1h
labels:
- "ubuntu-arm64:docker://docker.gitea.com/runner-images:ubuntu-latest"
- "runner-full-arm64:docker://git.ivanch.me/ivanch/runner-images:full"
- "runner-slim-arm64:docker://git.ivanch.me/ivanch/runner-images:slim"
---
# PersistentVolumeClaim for AMD64
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: gitea-runner-amd64-pvc
namespace: dev
spec:
storageClassName: "nfs-client"
accessModes:
- ReadWriteMany
resources:
requests:
storage: 8Mi
---
# PersistentVolumeClaim for ARM64
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: gitea-runner-arm64-pvc
namespace: dev
spec:
storageClassName: "nfs-client"
accessModes:
- ReadWriteMany
resources:
requests:
storage: 8Mi
---
# --- Deployment for the AMD64 Runner ---
apiVersion: apps/v1
kind: Deployment
metadata:
name: gitea-runner-amd64
namespace: dev
spec:
replicas: 1
selector:
matchLabels:
app: gitea-runner-amd64
template:
metadata:
labels:
app: gitea-runner-amd64
spec:
containers:
- name: gitea-runner
image: gitea/act_runner:latest
imagePullPolicy: Always
resources:
requests:
cpu: "500m"
memory: "512Mi"
limits:
cpu: "4000m"
memory: "4Gi"
volumeMounts:
- name: config-volume
mountPath: /etc/gitea-runner/config.yaml
subPath: config.yaml
- name: docker-socket
mountPath: /var/run/docker.sock
- name: gitea-runner-amd64-pvc
mountPath: /data
env:
- name: GITEA_RUNNER_REGISTRATION_TOKEN
valueFrom:
secretKeyRef:
name: gitea-runner-token
key: REGISTRATION_TOKEN
- name: GITEA_INSTANCE_URL
value: https://git.ivanch.me
- name: GITEA_RUNNER_NAME
value: k8s-runner-amd64
- name: CONFIG_FILE
value: /etc/gitea-runner/config.yaml
volumes:
- name: config-volume
configMap:
name: gitea-runner-amd64-config
- name: docker-socket
hostPath:
path: /var/run/docker.sock
- name: gitea-runner-amd64-pvc
persistentVolumeClaim:
claimName: gitea-runner-amd64-pvc
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- iris
---
# --- Deployment for the ARM64 Runner ---
apiVersion: apps/v1
kind: Deployment
metadata:
name: gitea-runner-arm64
namespace: dev
spec:
replicas: 1
selector:
matchLabels:
app: gitea-runner-arm64
template:
metadata:
labels:
app: gitea-runner-arm64
spec:
containers:
- name: gitea-runner
image: gitea/act_runner:latest
imagePullPolicy: Always
resources:
requests:
cpu: "500m"
memory: "512Mi"
limits:
cpu: "4000m"
memory: "4Gi"
volumeMounts:
- name: config-volume
mountPath: /etc/gitea-runner/config.yaml
subPath: config.yaml
- name: docker-socket
mountPath: /var/run/docker.sock
- name: gitea-runner-arm64-pvc
mountPath: /data
env:
- name: GITEA_RUNNER_REGISTRATION_TOKEN
valueFrom:
secretKeyRef:
name: gitea-runner-token
key: REGISTRATION_TOKEN
- name: GITEA_INSTANCE_URL
value: https://git.ivanch.me
- name: GITEA_RUNNER_NAME
value: k8s-runner-arm64
- name: CONFIG_FILE
value: /etc/gitea-runner/config.yaml
volumes:
- name: config-volume
configMap:
name: gitea-runner-arm64-config
- name: docker-socket
hostPath:
path: /var/run/docker.sock
- name: gitea-runner-arm64-pvc
persistentVolumeClaim:
claimName: gitea-runner-arm64-pvc
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- nexus
-114
View File
@@ -1,114 +0,0 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: adguardsync-pvc
namespace: dns
spec:
storageClassName: "nfs-client"
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Mi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: adguardsync
namespace: dns
spec:
strategy:
type: Recreate
replicas: 1
selector:
matchLabels:
app: adguardsync
template:
metadata:
labels:
app: adguardsync
spec:
containers:
- name: adguardsync
image: ghcr.io/bakito/adguardhome-sync:v0.9.3
ports:
- containerPort: 8080
protocol: TCP
name: web-port
env:
- name: CRON
value: "0 * * * *"
- name: RUN_ON_START
value: "true"
- name: LOG_LEVEL
value: "info"
- name: ORIGIN_URL
value: "http://adguard.haven"
- name: ORIGIN_USERNAME
valueFrom:
secretKeyRef:
name: adguardhome-password
key: username
- name: ORIGIN_PASSWORD
valueFrom:
secretKeyRef:
name: adguardhome-password
key: password
- name: REPLICA1_URL
value: "http://adguard2.haven"
- name: REPLICA1_USERNAME
valueFrom:
secretKeyRef:
name: adguardhome-password
key: username
- name: REPLICA1_PASSWORD
valueFrom:
secretKeyRef:
name: adguardhome-password
key: password
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
volumeMounts:
- name: adguardsync-storage
mountPath: /config
volumes:
- name: adguardsync-storage
persistentVolumeClaim:
claimName: adguardsync-pvc
---
apiVersion: v1
kind: Service
metadata:
name: adguardsync-svc
namespace: dns
spec:
type: ClusterIP
selector:
app: adguardsync
ports:
- name: web
port: 8080
targetPort: 8080
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: adguardsync-ingress
namespace: dns
spec:
rules:
- host: adguardsync.haven
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: adguardsync-svc
port:
number: 8080
-178
View File
@@ -1,178 +0,0 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: adguardhome-pvc
namespace: dns
spec:
storageClassName: "nfs-client"
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: adguardhome
namespace: dns
spec:
strategy:
type: Recreate
replicas: 1
selector:
matchLabels:
app: adguardhome
template:
metadata:
labels:
app: adguardhome
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: kubernetes.io/arch
operator: In
values:
- arm64
containers:
- name: adguardhome
image: adguard/adguardhome:v0.107.79
ports:
- containerPort: 53
protocol: TCP
- containerPort: 53
protocol: UDP
- containerPort: 3000
protocol: TCP
name: install-port
- containerPort: 80
protocol: TCP
name: web-port
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 1000m
memory: 2Gi
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
volumeMounts:
- name: adguardhome-storage
mountPath: /opt/adguardhome/work
- name: adguardhome-storage
mountPath: /opt/adguardhome/conf
volumes:
- name: adguardhome-storage
persistentVolumeClaim:
claimName: adguardhome-pvc
---
apiVersion: v1
kind: Service
metadata:
name: adguardhome-svc
namespace: dns
spec:
type: LoadBalancer
selector:
app: adguardhome
loadBalancerIP: 192.168.20.200
ports:
- name: dns-tcp
port: 53
targetPort: 53
protocol: TCP
- name: dns-udp
port: 53
targetPort: 53
protocol: UDP
- name: web
port: 80
targetPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: adguardhome-lan-svc
namespace: dns
spec:
type: LoadBalancer
selector:
app: adguardhome
loadBalancerIP: 192.168.15.200
ports:
- name: dns-tcp
port: 53
targetPort: 53
protocol: TCP
- name: dns-udp
port: 53
targetPort: 53
protocol: UDP
- name: web
port: 80
targetPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: adguard-install-svc
namespace: dns
spec:
type: ClusterIP
selector:
app: adguardhome
ports:
- name: install
port: 3000
targetPort: 3000
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: adguardhome-ingress
namespace: dns
spec:
rules:
- host: adguard.haven
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: adguardhome-svc
port:
number: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: adguardhome-install-ingress
namespace: dns
spec:
rules:
- host: install.adguard.haven
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: adguard-install-svc
port:
number: 3000
-37
View File
@@ -1,37 +0,0 @@
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: beszel-agent
namespace: infra
spec:
selector:
matchLabels:
app: beszel-agent
template:
metadata:
labels:
app: beszel-agent
spec:
hostNetwork: true
containers:
- env:
- name: PORT
value: "45876"
- name: KEY
valueFrom:
secretKeyRef:
name: beszel-key
key: SECRET-KEY
image: henrygd/beszel-agent:0.20.0
name: beszel-agent
ports:
- containerPort: 45876
hostPort: 45876
resources:
requests:
memory: "64Mi"
cpu: "50m"
limits:
memory: "128Mi"
cpu: "200m"
restartPolicy: Always
-197
View File
@@ -1,197 +0,0 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: bitwarden-cli-ca
namespace: infra
labels:
app.kubernetes.io/name: bitwarden-cli
data:
# Public CA certificate used by the internal-ca ClusterIssuer. Keep this in
# sync if the issuer CA is rotated.
haven-ca.crt: |
-----BEGIN CERTIFICATE-----
MIIFBzCCAu+gAwIBAgIUGFrjEo+WOxJpMnJqU/RQ881kWI8wDQYJKoZIhvcNAQEL
BQAwEzERMA8GA1UEAwwISGF2ZW4gQ0EwHhcNMjUwOTA3MTUxNTE3WhcNMzUwOTA1
MTUxNTE3WjATMREwDwYDVQQDDAhIYXZlbiBDQTCCAiIwDQYJKoZIhvcNAQEBBQAD
ggIPADCCAgoCggIBAK+8DxQfCYdRfGnJoEu0CiSuw64lnUFryvzy3GPkfGEEzc3f
ZiH6pUUIpQnrbVc1wdq3ojEOveGyLIqWxkljz8gEaMDJwB7udOxfbgv0QFI4cFKs
QzB+g3VVf74mYHvqfGB1suxmdVJ8YxcW3rQl7XD94PLxfoZuQ8IKKjskaQnYXUGH
wi6YBmIjpxr23lvT5cTbd5YgTFYVXDzM8nWtmnd2Wa9WkNZtKaHQKIeiNEpUPV0+
KSHVQC7vdmGmbUZXWpK2jmLFWfYaI0vXUal0CyMv1QidTd5LsDCI4Y+dx4mSBLuu
ip5V4Wm1DxttyaKUZM2vhzHEsDSVHz/xqx9nJeoJJuP+OirQVETD3FcN5PNVkWXu
EHQAqUciBh1CMJKKT74SE5oTT1/Eni9N2uYlvXsOs3ne6TTjZYxcL6VU+aqyYvvF
oMo3DX2a5nZvht4E1BtCd4I/RlnOw5QBAvWbFJqpbo/DTAGo/WBgv7jXCGail+uQ
r7iLoKFnhGq0WB9d2UUg6qDRD11I1nZANkv4t3Z2HFbG4XxdpttPm7JjxlcC3gGa
AfE3rChmAQPWPLSn6msOcfA+l5OD9SoSYU9nHy81T2q06Kfg/VWDdz7Wvi+WNZ20
gcfZPUZQsLlgZeyjmoA27D7ayO5uxjTWCi35kIgKcDDutyHctPRQs5zlTD35AgMB
AAGjUzBRMB0GA1UdDgQWBBSqABoe6cCk5vMc3LfnZfhiMbJ+kjAfBgNVHSMEGDAW
gBSqABoe6cCk5vMc3LfnZfhiMbJ+kjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3
DQEBCwUAA4ICAQAWAqQgFYEH14J2pwKptLb/K2C2oT9XLVnArQ5PKOzyWWhfZXsr
3YB707XJ7ju12n5gBgjCK4R66IG/iYNfHdBfhb9M1BVJ3T035RH8d6lhlZbxC02s
ZIMrQxDVFRrWm7gxcQiMILfPl2hJmsLf9XIUTBzPWFj9E+wExXrDYdiZXU+a/9qP
JvLKZA7T2lSBu+XtccySVLHXoxZ/A/c7Gp8XYJ2srZ2tXGN+j1dXiSMWHD/fpdxs
3GDKFnOOz2NTjHhYvBR94sOx3UkA3Pz+ufcHFBWWh23iGOPDDjh0vqAKItz2G0Kb
9B99XVnHWHamaZ2tV40x7lVn1mo9ImFVtxW2XDQ/NkRB9PuT2ryGE67Ey/Zfoq5M
0gZXIMtuMS25dTB8gQ8PKlXluIf4EbaDXhFk5xFHz5NP0E5Um4SxJP8H30/+UUPd
bu/TMcNiiAgxaTLBbE3nw/L7bYfH+5KuTLlp17H0UEtSI1GosgGYooov+Zbj4ZF8
Ko108LKAFDGe8/uQVeuo00CrEqXwVRtCCkv+LBcCJDicoyqWbp4GCBp+IVN0nxWX
xIRYVtQZCmA3hSH3rwt0/2dBxkcta4YkHZUEZ+EXaFl3z1tcbErOhBvupBvnBuZP
Rp2yvEJuuY6M1j+CZrfCm7qMipXTGPQ11Q7hf6jJ0xzxjTkV9TyV1ptPPQ==
-----END CERTIFICATE-----
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: bitwarden-cli
namespace: infra
labels:
app.kubernetes.io/name: bitwarden-cli
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: bitwarden-cli
template:
metadata:
labels:
app.kubernetes.io/name: bitwarden-cli
spec:
nodeSelector:
kubernetes.io/arch: amd64
containers:
- name: bitwarden-cli
image: ghcr.io/charlesthomas/bitwarden-cli:2026.8.0 # 2026.9.0 requires Vaultwarden's unimplemented user-key-ID backfill API
imagePullPolicy: IfNotPresent
# Override the baked entrypoint so --disable-origin-protection is
# actually passed (it was commented out in the image's entrypoint.sh,
# which made bw serve reject all cross-pod requests -> connection refused).
command: ["/bin/bash", "-lc"]
args:
- |
set -e
bw config server "${BW_HOST}"
# Authenticate. Prefer the API key if client creds are present.
login() {
if [ -n "$BW_CLIENTID" ] && [ -n "$BW_CLIENTSECRET" ]; then
echo "Using apikey to log in"
BW_SESSION=$(bw login --apikey --raw) || return 1
else
echo "Using password to log in"
BW_SESSION=$(bw login "${BW_USER}" --passwordenv BW_PASSWORD --raw) || return 1
fi
export BW_SESSION
}
login
# Warm the vault cache once at startup so bw serve has data immediately.
bw sync
bw status
# Keep the session alive
echo "Starting periodic bw login+sync loop (every 5m)"
(
while true; do
sleep 300
login || true
echo "[$(date -u +%FT%TZ)] bw sync"
bw sync >/dev/null 2>&1 || echo "[$(date -u +%FT%TZ)] bw sync failed"
done
) &
echo 'Running `bw serve` on port 8087'
bw serve --hostname 0.0.0.0 --disable-origin-protection
env:
# Bitwarden CLI is Node-based and needs the internal issuer CA to
# verify the HTTPS certificate for vault.haven.
- name: NODE_EXTRA_CA_CERTS
value: /etc/ssl/certs/haven-ca.crt
# Use the in-cluster ingress. The public endpoint currently
# returns 502 from inside the cluster.
- name: BW_HOST
value: https://vault.haven
- name: BW_USER
valueFrom:
secretKeyRef:
name: bitwarden-cli
key: BW_USERNAME
- name: BW_PASSWORD
valueFrom:
secretKeyRef:
name: bitwarden-cli
key: BW_PASSWORD
volumeMounts:
- name: haven-ca
mountPath: /etc/ssl/certs/haven-ca.crt
subPath: haven-ca.crt
readOnly: true
ports:
- name: http
containerPort: 8087
protocol: TCP
startupProbe:
tcpSocket: { port: 8087 }
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 30
readinessProbe:
tcpSocket: { port: 8087 }
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 3
livenessProbe:
tcpSocket: { port: 8087 }
periodSeconds: 15
timeoutSeconds: 3
failureThreshold: 6
resources:
limits:
cpu: 400m
memory: 512Mi
requests:
cpu: 50m
memory: 128Mi
volumes:
- name: haven-ca
configMap:
name: bitwarden-cli-ca
---
apiVersion: v1
kind: Service
metadata:
name: bitwarden-cli
namespace: infra
labels:
app.kubernetes.io/name: bitwarden-cli
spec:
type: ClusterIP
selector:
app.kubernetes.io/name: bitwarden-cli
ports:
- name: http
port: 8087
targetPort: http
protocol: TCP
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: bw-cli
namespace: infra
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: bitwarden-cli
policyTypes:
- Ingress
ingress:
- from:
# ESO pods in the external-secrets namespace.
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: external-secrets
podSelector:
matchLabels:
app.kubernetes.io/name: external-secrets
-26
View File
@@ -1,26 +0,0 @@
apiVersion: helm.cattle.io/v1
kind: HelmChart
metadata:
name: csi-driver-nfs
namespace: infra
spec:
repo: https://kubernetes-csi.github.io/csi-driver-nfs
chart: csi-driver-nfs
version: 4.13.4
targetNamespace: infra
valuesContent: |-
controller:
replicas: 1
logLevel: 5
defaultOnDeletePolicy: retain
storageClasses:
- name: nfs-client
annotations:
storageclass.kubernetes.io/is-default-class: "true"
parameters:
server: nfs-config.haven
share: /export/config
subDir: ${pvc.metadata.namespace}/${pvc.metadata.name}
onDelete: retain
reclaimPolicy: Retain
volumeBindingMode: Immediate
-11
View File
@@ -1,11 +0,0 @@
apiVersion: helm.cattle.io/v1
kind: HelmChart
metadata:
name: external-secrets
namespace: kube-system
spec:
repo: https://charts.external-secrets.io
chart: external-secrets
version: 2.7.0
targetNamespace: external-secrets
createNamespace: true
-138
View File
@@ -1,138 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: file-nginx
namespace: infra
labels:
app: file-nginx
spec:
replicas: 1
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
selector:
matchLabels:
app: file-nginx
template:
metadata:
labels:
app: file-nginx
annotations:
checksum/file-nginx-conf: "4235705a54e5003a340f1a4e164c3e3239fd4327d9aa9ecf0c640a3655def3c9"
spec:
containers:
- name: nginx
image: nginx:alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
securityContext:
allowPrivilegeEscalation: false
runAsUser: 0
volumeMounts:
- name: html
mountPath: /usr/share/nginx/data
- name: nginx-conf
mountPath: /etc/nginx/conf.d/default.conf
subPath: default.conf
startupProbe:
httpGet:
path: /
port: 80
failureThreshold: 30
periodSeconds: 5
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 10
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi
volumes:
- name: html
nfs:
server: vega.haven
path: /export/Fast
- name: nginx-conf
configMap:
name: file-nginx-conf
---
apiVersion: v1
kind: ConfigMap
metadata:
name: file-nginx-conf
namespace: infra
data:
default.conf: |
server {
listen 80;
listen [::]:80;
server_name _;
root /usr/share/nginx/data/file-nginx;
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
location = /index.html {
# The legacy static page is now the live directory browser.
return 302 /;
}
location / {
# Bypass the static welcome page so every directory is browsable.
index __directory_listing__;
try_files $uri $uri/ =404;
}
}
---
apiVersion: v1
kind: Service
metadata:
name: file-nginx
namespace: infra
spec:
selector:
app: file-nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: file-nginx
namespace: infra
annotations:
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-origin: "*"
spec:
rules:
- host: file-nginx.haven
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: file-nginx
port:
number: 80
-32
View File
@@ -1,32 +0,0 @@
apiVersion: helm.cattle.io/v1
kind: HelmChart
metadata:
name: traefik
namespace: kube-system
spec:
repo: https://traefik.github.io/charts
chart: traefik
version: 41.2.0
targetNamespace: traefik
createNamespace: true
valuesContent: |-
deployment:
replicas: 2
ingressClass:
enabled: true
isDefaultClass: true
name: traefik
service:
annotations:
metallb.io/ip-allocated-from-pool: default-pool
metallb.io/loadBalancerIPs: "192.168.20.204"
spec:
type: LoadBalancer
externalTrafficPolicy: Local
resources:
requests:
cpu: 100m
memory: 90Mi
limits:
cpu: 1000m
memory: 256Mi
-156
View File
@@ -1,156 +0,0 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: wg-easy-pvc
namespace: infra
spec:
storageClassName: "nfs-client"
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: wg-easy
namespace: infra
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
replicas: 1
selector:
matchLabels:
app: wg-easy
template:
metadata:
labels:
app: wg-easy
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- preference:
matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- polaris
weight: 100
containers:
- name: wg-easy
image: ghcr.io/wg-easy/wg-easy:15.4.0
ports:
- containerPort: 51820
protocol: UDP
name: wg-port
- containerPort: 51821
protocol: TCP
name: web-port
env:
- name: LANG
value: en
- name: WG_MTU
value: "1420"
- name: UI_TRAFFIC_STATS
value: "true"
- name: INSECURE
value: "true"
- name: UI_ENABLE_SORT_CLIENTS
value: "true"
securityContext:
capabilities:
add:
- NET_ADMIN
- SYS_MODULE
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 2000m
memory: 1Gi
livenessProbe:
httpGet:
path: /
port: 51821
initialDelaySeconds: 15
periodSeconds: 30
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /
port: 51821
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 2
volumeMounts:
- name: wg-easy-volume
mountPath: /etc/wireguard
- name: kernel-modules
mountPath: /lib/modules
readOnly: true
restartPolicy: Always
volumes:
- name: wg-easy-volume
persistentVolumeClaim:
claimName: wg-easy-pvc
- name: kernel-modules
hostPath:
path: /lib/modules
type: Directory
---
apiVersion: v1
kind: Service
metadata:
name: wg-easy-svc
namespace: infra
spec:
type: LoadBalancer
selector:
app: wg-easy
loadBalancerIP: 192.168.20.203
ports:
- name: wg-port
port: 51820
targetPort: 51820
protocol: UDP
- name: web-port
port: 51821
targetPort: 51821
protocol: TCP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: wg-easy-ingress
namespace: infra
spec:
rules:
- host: vpn.haven
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: wg-easy-svc
port:
number: 51821
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: wg-easy-pdb
namespace: infra
spec:
minAvailable: 1
selector:
matchLabels:
app: wg-easy
-10
View File
@@ -1,10 +0,0 @@
apiVersion: helm.cattle.io/v1
kind: HelmChart
metadata:
name: metallb
namespace: kube-system
spec:
repo: https://metallb.github.io/metallb
chart: metallb
version: 0.15.2
targetNamespace: metallb-system
-123
View File
@@ -1,123 +0,0 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
chart: true
metadata:
name: alloy
namespace: argocd
finalizers: [resources-finalizer.argocd.argoproj.io]
spec:
project: default
destination:
server: https://kubernetes.default.svc
namespace: monitoring
syncPolicy:
automated: { prune: true, selfHeal: true }
syncOptions: [CreateNamespace=true, ServerSideApply=true]
source:
repoURL: https://grafana.github.io/helm-charts
chart: alloy
targetRevision: 1.12.1
helm:
valuesObject:
controller:
type: daemonset
alloy:
clustering: { enabled: false }
mounts:
varlog: true
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 200m
memory: 256Mi
configMap:
create: true
content: |-
discovery.kubernetes "all_pods" {
role = "pod"
selectors {
role = "pod"
field = "spec.nodeName=" + coalesce(env("HOSTNAME"), constants.hostname)
}
}
discovery.relabel "all_pods" {
targets = discovery.kubernetes.all_pods.targets
rule {
source_labels = ["__meta_kubernetes_namespace"]
target_label = "namespace"
}
rule {
source_labels = ["__meta_kubernetes_pod_name"]
target_label = "pod"
}
rule {
source_labels = ["__meta_kubernetes_pod_container_name"]
target_label = "container"
}
rule {
source_labels = ["__meta_kubernetes_pod_label_app_kubernetes_io_name"]
target_label = "app"
}
}
loki.source.kubernetes "all_logs" {
targets = discovery.relabel.all_pods.output
forward_to = [loki.write.main.receiver]
}
discovery.kubernetes "shared_pods" {
role = "pod"
selectors {
role = "pod"
field = "metadata.namespace=chacal"
}
}
discovery.relabel "shared_pods" {
targets = discovery.kubernetes.shared_pods.targets
rule {
source_labels = ["__meta_kubernetes_namespace"]
target_label = "namespace"
}
rule {
source_labels = ["__meta_kubernetes_pod_name"]
target_label = "pod"
}
rule {
source_labels = ["__meta_kubernetes_pod_container_name"]
target_label = "container"
}
rule {
source_labels = ["__meta_kubernetes_pod_label_app_kubernetes_io_name"]
target_label = "app"
}
}
loki.source.kubernetes "shared_logs" {
targets = discovery.relabel.shared_pods.output
forward_to = [loki.write.shared.receiver]
}
loki.write "main" {
endpoint {
url = "http://loki.monitoring.svc.cluster.local:3100/loki/api/v1/push"
headers = {
"X-Scope-OrgID" = "main",
}
}
}
loki.write "shared" {
endpoint {
url = "http://loki.monitoring.svc.cluster.local:3100/loki/api/v1/push"
headers = {
"X-Scope-OrgID" = "chacal",
}
}
}
-145
View File
@@ -1,145 +0,0 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: kube-state-metrics
namespace: monitoring
labels:
app: kube-state-metrics
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/version: 2.19.1
automountServiceAccountToken: false
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: kube-state-metrics
labels:
app: kube-state-metrics
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/version: 2.19.1
rules:
- apiGroups: [""]
resources:
- nodes
- pods
- persistentvolumeclaims
verbs: ["list", "watch"]
- apiGroups: ["apps"]
resources:
- statefulsets
- daemonsets
- deployments
- replicasets
verbs: ["list", "watch"]
- apiGroups: ["batch"]
resources:
- cronjobs
- jobs
verbs: ["list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kube-state-metrics
labels:
app: kube-state-metrics
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/version: 2.19.1
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: kube-state-metrics
subjects:
- kind: ServiceAccount
name: kube-state-metrics
namespace: monitoring
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: kube-state-metrics
namespace: monitoring
labels:
app: kube-state-metrics
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/version: 2.19.1
spec:
replicas: 1
selector:
matchLabels:
app: kube-state-metrics
template:
metadata:
labels:
app: kube-state-metrics
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/version: 2.19.1
spec:
automountServiceAccountToken: true
serviceAccountName: kube-state-metrics
nodeSelector:
kubernetes.io/os: linux
containers:
- name: kube-state-metrics
image: registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.20.0
imagePullPolicy: IfNotPresent
args:
- --resources=cronjobs,daemonsets,deployments,jobs,nodes,persistentvolumeclaims,pods,replicasets,statefulsets
ports:
- name: http-metrics
containerPort: 8080
protocol: TCP
livenessProbe:
httpGet:
path: /livez
port: http-metrics
initialDelaySeconds: 5
timeoutSeconds: 5
readinessProbe:
httpGet:
path: /readyz
port: 8081
initialDelaySeconds: 5
timeoutSeconds: 5
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 65534
seccompProfile:
type: RuntimeDefault
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 256Mi
---
apiVersion: v1
kind: Service
metadata:
name: kube-state-metrics
namespace: monitoring
labels:
app: kube-state-metrics
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/version: 2.19.1
spec:
type: ClusterIP
selector:
app: kube-state-metrics
ports:
- name: http-metrics
port: 8080
targetPort: http-metrics
protocol: TCP
-46
View File
@@ -1,46 +0,0 @@
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: haven-apps
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- git:
repoURL: https://git.ivanch.me/ivanch/haven.git
revision: main
files:
- path: "apps/*/*.yaml"
- path: "apps/root/*.yaml"
exclude: true
template:
metadata:
name: '{{ .path.filename | trimSuffix ".yaml" }}'
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
source:
repoURL: https://git.ivanch.me/ivanch/haven.git
targetRevision: main
path: "{{ .path.path }}"
directory:
include: "{{ .path.filename }}"
destination:
server: https://kubernetes.default.svc
namespace: "{{ index .path.segments 1 }}"
syncPolicy:
automated:
prune: true
selfHeal: true
templatePatch: |
{{- if hasKey . "chart" }}
spec:
source:
$patch: replace
{{- toYaml .spec.source | nindent 4 }}
syncPolicy:
syncOptions: [CreateNamespace=true, ServerSideApply=true]
{{- end }}
-5
View File
@@ -1,5 +0,0 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- applicationset.yaml
-22
View File
@@ -1,22 +0,0 @@
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: default-pool
namespace: metallb-system
spec:
addresses:
- 192.168.15.200/32 # reserved for DNS 1
- 192.168.15.202/32 # reserved for wg-easy
- 192.168.15.203/32 # reserved for k3s ingress
- 192.168.20.200/32 # reserved for DNS 1
# - 192.168.20.201 is reserved for DNS 2
- 192.168.20.202-192.168.20.220
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: default-advertisement
namespace: metallb-system
spec:
ipAddressPools:
- default-pool
@@ -1,23 +0,0 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
labels:
app.kubernetes.io/name: argocd-cm
app.kubernetes.io/part-of: argocd
data:
accounts.api: apiKey
accounts.api.enabled: "true"
---
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-rbac-cm
namespace: argocd
labels:
app.kubernetes.io/name: argocd-rbac-cm
app.kubernetes.io/part-of: argocd
data:
policy.csv: |
g, api, role:readonly
-17
View File
@@ -1,17 +0,0 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: argocd-server
namespace: argocd
spec:
rules:
- host: argocd.haven
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: argocd-server
port:
number: 80
@@ -1,12 +0,0 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: argocd
resources:
- https://github.com/argoproj/argo-cd.git/manifests/cluster-install?ref=stable
- ingress.yaml
patches:
- path: server-insecure-patch.yaml
- path: argocd-api-user.yaml
@@ -1,6 +0,0 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cmd-params-cm
data:
server.insecure: "true"
-128
View File
@@ -1,128 +0,0 @@
---
# ==============================================================================
# Core / System Namespaces
# ==============================================================================
apiVersion: v1
kind: Namespace
metadata:
name: default
---
apiVersion: v1
kind: Namespace
metadata:
name: kube-node-lease
---
apiVersion: v1
kind: Namespace
metadata:
name: kube-public
---
apiVersion: v1
kind: Namespace
metadata:
name: kube-system
---
# ==============================================================================
# Infrastructure, Ingress & GitOps
# ==============================================================================
apiVersion: v1
kind: Namespace
metadata:
name: argocd
---
apiVersion: v1
kind: Namespace
metadata:
name: cert-manager
---
apiVersion: v1
kind: Namespace
metadata:
name: dns
---
apiVersion: v1
kind: Namespace
metadata:
name: docker-ingress
---
apiVersion: v1
kind: Namespace
metadata:
name: external-secrets
labels:
name: external-secrets
---
apiVersion: v1
kind: Namespace
metadata:
name: infra
---
apiVersion: v1
kind: Namespace
metadata:
name: metallb-system
---
# ==============================================================================
# Observability & Monitoring
# ==============================================================================
apiVersion: v1
kind: Namespace
metadata:
name: monitoring
---
# ==============================================================================
# Storage & Data
# ==============================================================================
apiVersion: v1
kind: Namespace
metadata:
name: garage
labels:
name: garage
---
# ==============================================================================
# Environments & Workloads
# ==============================================================================
apiVersion: v1
kind: Namespace
metadata:
name: chacal
---
apiVersion: v1
kind: Namespace
metadata:
name: cloud
---
apiVersion: v1
kind: Namespace
metadata:
name: cronjobs
---
apiVersion: v1
kind: Namespace
metadata:
name: dev
---
apiVersion: v1
kind: Namespace
metadata:
name: lab
---
apiVersion: v1
kind: Namespace
metadata:
name: media
---
apiVersion: v1
kind: Namespace
metadata:
name: mindforge
---
apiVersion: v1
kind: Namespace
metadata:
name: vpn-session-pods
labels:
pod-security.kubernetes.io/audit: privileged
pod-security.kubernetes.io/enforce: privileged
pod-security.kubernetes.io/warn: privileged
-20
View File
@@ -1,20 +0,0 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: root
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
source:
repoURL: https://git.ivanch.me/ivanch/haven.git
targetRevision: main
path: apps/root
destination:
server: https://kubernetes.default.svc
namespace: argocd
syncPolicy:
automated:
prune: true
selfHeal: true
-20
View File
@@ -1,20 +0,0 @@
apiVersion: external-secrets.io/v1
kind: ClusterSecretStore
metadata: { name: bitwarden-login }
spec:
provider:
webhook:
url: "http://bitwarden-cli.infra.svc:8087/object/item/{{ .remoteRef.key }}"
result: { jsonPath: "$.data.login.{{ .remoteRef.property }}" }
---
apiVersion: external-secrets.io/v1
kind: ClusterSecretStore
metadata: { name: bitwarden-fields }
spec:
provider:
webhook:
url: "http://bitwarden-cli.infra.svc:8087/object/item/{{ .remoteRef.key }}"
result:
{
jsonPath: '$.data.fields[?@.name=="{{ .remoteRef.property }}"].value',
}
+8
View File
@@ -0,0 +1,8 @@
# internal-issuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: internal-ca
spec:
ca:
secretName: internal-ca-secret
@@ -1,3 +1,4 @@
# 2) Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
@@ -16,6 +17,7 @@ spec:
containers:
- name: cloudreve
image: cloudreve/cloudreve:v4
imagePullPolicy: Always
ports:
- containerPort: 5212
name: http
@@ -51,6 +53,11 @@ spec:
value: "disable"
- name: CR_CONF_Redis.Server
value: ""
- name: CR_CONF_Redis.Password
valueFrom:
secretKeyRef:
name: cloudreve-secret
key: REDIS_PASSWORD
volumeMounts:
- name: cloudreve-data
mountPath: /cloudreve/data
@@ -67,6 +74,7 @@ spec:
server: 192.168.15.99
path: /export/Storage/Cloud
---
# 3) Service (HTTP)
apiVersion: v1
kind: Service
metadata:
@@ -82,6 +90,7 @@ spec:
name: http
---
# 4) Service (Slave node / WebDAV — optional)
apiVersion: v1
kind: Service
metadata:
@@ -102,11 +111,14 @@ spec:
protocol: UDP
---
# 5) PersistentVolumeClaim
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: cloudreve-data
namespace: cloud
annotations:
nfs.io/storage-path: "cloudreve-data"
spec:
storageClassName: "nfs-client"
accessModes:
@@ -117,6 +129,7 @@ spec:
limits:
storage: 50Gi
---
# 6) Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
@@ -127,6 +140,7 @@ metadata:
nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
spec:
ingressClassName: nginx
rules:
- host: cloud.haven
http:
@@ -139,6 +153,7 @@ spec:
port:
number: 5212
---
# 7) Ingress Public
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
@@ -149,6 +164,7 @@ metadata:
nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
spec:
ingressClassName: nginx
rules:
- host: cloud.ivanch.me
http:
@@ -99,6 +99,8 @@ kind: PersistentVolumeClaim
metadata:
name: slink-data
namespace: cloud
annotations:
nfs.io/storage-path: "slink-data"
spec:
storageClassName: "nfs-client"
accessModes:
@@ -120,6 +122,7 @@ metadata:
nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
spec:
ingressClassName: nginx
rules:
- host: slink.haven
http:
@@ -65,17 +65,14 @@ spec:
- name: SONIC_PASSWORD
valueFrom:
secretKeyRef:
name: archivebox-password
name: password
key: password
- name: ADMIN_USERNAME
valueFrom:
secretKeyRef:
name: archivebox-password
key: password
value: "ivanch"
- name: ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: archivebox-password
name: password
key: password
- name: CSRF_TRUSTED_ORIGINS
value: "archive.haven"
@@ -124,11 +121,14 @@ spec:
port: 8000
targetPort: 8000
---
# 3) PersistentVolumeClaim
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: archivebox-data
namespace: default
annotations:
nfs.io/storage-path: "archivebox-data"
spec:
storageClassName: "nfs-client"
accessModes:
@@ -145,6 +145,7 @@ metadata:
name: archivebox-ingress
namespace: default
spec:
ingressClassName: nginx
rules:
- host: "archive.haven"
http:
@@ -113,7 +113,7 @@ spec:
imagePullPolicy: Always
env:
- name: HOMEPAGE_ALLOWED_HOSTS
value: "*"
value: homepage.haven # required, may need port. See gethomepage.dev/installation/#homepage_allowed_hosts
ports:
- name: http
containerPort: 3000
@@ -157,6 +157,8 @@ kind: PersistentVolumeClaim
metadata:
name: homepage-config
namespace: default
annotations:
nfs.io/storage-path: "homepage-config"
spec:
storageClassName: "nfs-client"
accessModes:
@@ -190,6 +192,7 @@ metadata:
labels:
app.kubernetes.io/name: homepage
spec:
ingressClassName: nginx
rules:
- host: "homepage.haven"
http:
@@ -53,6 +53,7 @@ metadata:
name: it-tools-ingress
namespace: default
spec:
ingressClassName: nginx
rules:
- host: "tools.haven"
http:
@@ -1,4 +1,5 @@
---
# 1) Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
@@ -18,6 +19,9 @@ spec:
- name: notepad
image: jdreinhardt/minimalist-web-notepad:latest
imagePullPolicy: Always
# The image entrypoint runs `chown -R www-data:www-data` on the NFS-mounted
# _tmp dir, which fails because the NFS export uses all_squash (anonuid=65534).
# Override the entrypoint to skip chown — ownership is handled by the NFS server.
command:
- sh
- -c
@@ -43,6 +47,7 @@ spec:
claimName: notepad-data
---
# 2) Service
apiVersion: v1
kind: Service
metadata:
@@ -56,11 +61,14 @@ spec:
- port: 80
targetPort: 80
---
# 3) PersistentVolumeClaim
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: notepad-data
namespace: default
annotations:
nfs.io/storage-path: "notepad-data"
spec:
storageClassName: "nfs-client"
accessModes:
@@ -69,12 +77,14 @@ spec:
requests:
storage: 1Gi
---
# 4) Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: notepad
namespace: default
spec:
ingressClassName: nginx
rules:
- host: notepad.haven
http:
@@ -1,3 +1,4 @@
# 1) Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
@@ -56,6 +57,7 @@ spec:
persistentVolumeClaim:
claimName: openwebui-data
---
# 2) Service
apiVersion: v1
kind: Service
metadata:
@@ -69,11 +71,14 @@ spec:
- port: 8080
targetPort: 8080
---
# 3) PersistentVolumeClaim
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: openwebui-data
namespace: default
annotations:
nfs.io/storage-path: "openwebui-data"
spec:
storageClassName: "nfs-client"
accessModes:
@@ -84,6 +89,7 @@ spec:
limits:
storage: 10Gi
---
# 4) Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
@@ -92,6 +98,7 @@ metadata:
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
spec:
ingressClassName: nginx
rules:
- host: openwebui.haven
http:
@@ -46,30 +46,10 @@ spec:
value: '{"invalidate_digital_signatures": true}'
- name: PAPERLESS_DBHOST
value: postgresql.haven
- name: PAPERLESS_DBNAME
valueFrom:
secretKeyRef:
name: paperless-secret
key: PAPERLESS_DBNAME
- name: PAPERLESS_DBUSER
valueFrom:
secretKeyRef:
name: paperless-secret
key: PAPERLESS_DBUSER
- name: PAPERLESS_DBPASSWORD
valueFrom:
secretKeyRef:
name: paperless-secret
key: PAPERLESS_DBPASSWORD
- name: PAPERLESS_REDIS
value: "redis://redis.haven:6379"
- name: PAPERLESS_PORT
value: "8000"
- name: PAPERLESS_SECRET_KEY
valueFrom:
secretKeyRef:
name: paperless-secret
key: PAPERLESS_SECRET_KEY
ports:
- containerPort: 8000
name: paperless-port
@@ -118,6 +98,8 @@ kind: PersistentVolumeClaim
metadata:
name: paperless-data
namespace: default
annotations:
nfs.io/storage-path: "paperless-data"
spec:
storageClassName: "nfs-client"
accessModes:
@@ -135,6 +117,7 @@ metadata:
name: paperless
namespace: default
spec:
ingressClassName: nginx
rules:
- host: paperless.haven
http:
@@ -63,6 +63,8 @@ kind: PersistentVolumeClaim
metadata:
name: searxng-config
namespace: default
annotations:
nfs.io/storage-path: "searxng-config"
spec:
storageClassName: "nfs-client"
accessModes:
@@ -78,6 +80,7 @@ metadata:
name: searxng
namespace: default
spec:
ingressClassName: nginx
rules:
- host: search.haven
http:
@@ -20,6 +20,7 @@ spec:
containers:
- name: uptimekuma
image: louislam/uptime-kuma:2
imagePullPolicy: Always
env:
- name: PUID
value: "1000"
@@ -75,6 +76,8 @@ kind: PersistentVolumeClaim
metadata:
name: uptimekuma-config
namespace: default
annotations:
nfs.io/storage-path: "uptimekuma-config"
spec:
storageClassName: "nfs-client"
accessModes:
@@ -90,6 +93,7 @@ metadata:
name: uptimekuma
namespace: default
spec:
ingressClassName: nginx
rules:
- host: uptimekuma.haven
http:
@@ -17,7 +17,8 @@ spec:
spec:
containers:
- name: vaultwarden
image: vaultwarden/server:1.37.3
image: vaultwarden/server:latest
imagePullPolicy: Always
env:
- name: DOMAIN
value: "https://vault.haven"
@@ -29,31 +30,6 @@ spec:
ports:
- containerPort: 80
name: vault-port
# /alive requires no authentication and verifies the Vaultwarden process
startupProbe:
httpGet:
path: /alive
port: vault-port
scheme: HTTP
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 30
readinessProbe:
httpGet:
path: /alive
port: vault-port
scheme: HTTP
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 3
livenessProbe:
httpGet:
path: /alive
port: vault-port
scheme: HTTP
periodSeconds: 15
timeoutSeconds: 3
failureThreshold: 6
volumeMounts:
- name: vaultwarden-data
mountPath: /data
@@ -89,6 +65,8 @@ kind: PersistentVolumeClaim
metadata:
name: vaultwarden-data
namespace: default
annotations:
nfs.io/storage-path: "vaultwarden-data"
spec:
storageClassName: "nfs-client"
accessModes:
@@ -107,6 +85,7 @@ metadata:
cert-manager.io/cluster-issuer: internal-ca
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- vault.haven
@@ -130,6 +109,7 @@ metadata:
name: vaultwarden-public
namespace: default
spec:
ingressClassName: nginx
rules:
- host: vault.ivanch.me
http:
+6
View File
@@ -0,0 +1,6 @@
## Creating gitea-runner secrets
```bash
kubectl create secret generic gitea-runner-token \
--from-literal=REGISTRATION_TOKEN='your_gitea_runner_token' -n dev
```
+196
View File
@@ -0,0 +1,196 @@
# --- ConfigMap for the AMD64 Runner ---
apiVersion: v1
kind: ConfigMap
metadata:
name: gitea-runner-amd64-config
namespace: dev
data:
config.yaml: |
# Registration token and Gitea instance URL should be managed via secrets
runner:
capacity: 4
timeout: 1h
labels:
- "ubuntu-amd64:docker://docker.gitea.com/runner-images:ubuntu-latest"
- "ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest"
- "ubuntu-slim:docker://docker.gitea.com/runner-images:ubuntu-latest-slim"
---
# --- ConfigMap for the ARM64 Runner ---
apiVersion: v1
kind: ConfigMap
metadata:
name: gitea-runner-arm64-config
namespace: dev
data:
config.yaml: |
runner:
capacity: 4
timeout: 1h
labels:
- "ubuntu-arm64:docker://docker.gitea.com/runner-images:ubuntu-latest"
---
# PersistentVolumeClaim for AMD64
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: gitea-runner-amd64-pvc
namespace: dev
annotations:
nfs.io/storage-path: "gitea-runner-amd64-pvc"
spec:
storageClassName: "nfs-client"
accessModes:
- ReadWriteMany
resources:
requests:
storage: 8Mi
---
# PersistentVolumeClaim for ARM64
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: gitea-runner-arm64-pvc
namespace: dev
annotations:
nfs.io/storage-path: "gitea-runner-arm64-pvc"
spec:
storageClassName: "nfs-client"
accessModes:
- ReadWriteMany
resources:
requests:
storage: 8Mi
---
# --- Deployment for the AMD64 Runner ---
apiVersion: apps/v1
kind: Deployment
metadata:
name: gitea-runner-amd64
namespace: dev
spec:
replicas: 1
selector:
matchLabels:
app: gitea-runner-amd64
template:
metadata:
labels:
app: gitea-runner-amd64
spec:
containers:
- name: gitea-runner
image: gitea/act_runner:latest
imagePullPolicy: Always
resources:
requests:
cpu: "500m"
memory: "512Mi"
limits:
cpu: "4000m"
memory: "4Gi"
volumeMounts:
- name: config-volume
mountPath: /etc/gitea-runner/config.yaml
subPath: config.yaml
- name: docker-socket
mountPath: /var/run/docker.sock
- name: gitea-runner-amd64-pvc
mountPath: /data
env:
- name: GITEA_RUNNER_REGISTRATION_TOKEN
valueFrom:
secretKeyRef:
name: gitea-runner-token
key: REGISTRATION_TOKEN
- name: GITEA_INSTANCE_URL
value: https://git.ivanch.me
- name: GITEA_RUNNER_NAME
value: k8s-runner-amd64
- name: CONFIG_FILE
value: /etc/gitea-runner/config.yaml
volumes:
- name: config-volume
configMap:
name: gitea-runner-amd64-config
- name: docker-socket
hostPath:
path: /var/run/docker.sock
- name: gitea-runner-amd64-pvc
persistentVolumeClaim:
claimName: gitea-runner-amd64-pvc
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- iris
---
# --- Deployment for the ARM64 Runner ---
apiVersion: apps/v1
kind: Deployment
metadata:
name: gitea-runner-arm64
namespace: dev
spec:
replicas: 1
selector:
matchLabels:
app: gitea-runner-arm64
template:
metadata:
labels:
app: gitea-runner-arm64
spec:
containers:
- name: gitea-runner
image: gitea/act_runner:latest
imagePullPolicy: Always
resources:
requests:
cpu: "500m"
memory: "512Mi"
limits:
cpu: "4000m"
memory: "4Gi"
volumeMounts:
- name: config-volume
mountPath: /etc/gitea-runner/config.yaml
subPath: config.yaml
- name: docker-socket
mountPath: /var/run/docker.sock
- name: gitea-runner-arm64-pvc
mountPath: /data
env:
- name: GITEA_RUNNER_REGISTRATION_TOKEN
valueFrom:
secretKeyRef:
name: gitea-runner-token
key: REGISTRATION_TOKEN
- name: GITEA_INSTANCE_URL
value: https://git.ivanch.me
- name: GITEA_RUNNER_NAME
value: k8s-runner-arm64
- name: CONFIG_FILE
value: /etc/gitea-runner/config.yaml
volumes:
- name: config-volume
configMap:
name: gitea-runner-arm64-config
- name: docker-socket
hostPath:
path: /var/run/docker.sock
- name: gitea-runner-arm64-pvc
persistentVolumeClaim:
claimName: gitea-runner-arm64-pvc
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- nexus
+118
View File
@@ -0,0 +1,118 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: adguardsync-pvc
namespace: dns
annotations:
nfs.io/storage-path: "adguardsync-config"
spec:
storageClassName: "nfs-client"
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Mi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: adguardsync
namespace: dns
spec:
strategy:
type: Recreate
replicas: 1
selector:
matchLabels:
app: adguardsync
template:
metadata:
labels:
app: adguardsync
spec:
containers:
- name: adguardsync
image: ghcr.io/bakito/adguardhome-sync:latest
imagePullPolicy: Always
ports:
- containerPort: 8080
protocol: TCP
name: web-port
env:
- name: CRON
value: "0 * * * *"
- name: RUN_ON_START
value: "true"
- name: LOG_LEVEL
value: "info"
- name: ORIGIN_URL
value: "http://adguard.haven"
- name: ORIGIN_USERNAME
valueFrom:
secretKeyRef:
name: adguardhome-password
key: username
- name: ORIGIN_PASSWORD
valueFrom:
secretKeyRef:
name: adguardhome-password
key: password
- name: REPLICA1_URL
value: "http://adguard2.haven"
- name: REPLICA1_USERNAME
valueFrom:
secretKeyRef:
name: adguardhome-password
key: username
- name: REPLICA1_PASSWORD
valueFrom:
secretKeyRef:
name: adguardhome-password
key: password
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
volumeMounts:
- name: adguardsync-storage
mountPath: /config
volumes:
- name: adguardsync-storage
persistentVolumeClaim:
claimName: adguardsync-pvc
---
apiVersion: v1
kind: Service
metadata:
name: adguardsync-svc
namespace: dns
spec:
type: ClusterIP
selector:
app: adguardsync
ports:
- name: web
port: 8080
targetPort: 8080
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: adguardsync-ingress
namespace: dns
spec:
ingressClassName: nginx
rules:
- host: adguardsync.haven
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: adguardsync-svc
port:
number: 8080
+173
View File
@@ -0,0 +1,173 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: adguardhome-pvc
namespace: dns
annotations:
nfs.io/storage-path: "adguardhome-config"
spec:
storageClassName: "nfs-client"
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: adguardhome
namespace: dns
spec:
strategy:
type: Recreate
replicas: 1
selector:
matchLabels:
app: adguardhome
template:
metadata:
labels:
app: adguardhome
spec:
containers:
- name: adguardhome
image: adguard/adguardhome:latest
imagePullPolicy: Always
ports:
- containerPort: 53
protocol: TCP
- containerPort: 53
protocol: UDP
- containerPort: 3000
protocol: TCP
name: install-port
- containerPort: 80
protocol: TCP
name: web-port
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 1000m
memory: 2Gi
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
volumeMounts:
- name: adguardhome-storage
mountPath: /opt/adguardhome/work
- name: adguardhome-storage
mountPath: /opt/adguardhome/conf
volumes:
- name: adguardhome-storage
persistentVolumeClaim:
claimName: adguardhome-pvc
---
apiVersion: v1
kind: Service
metadata:
name: adguardhome-svc
namespace: dns
spec:
type: LoadBalancer
selector:
app: adguardhome
loadBalancerIP: 192.168.20.200
ports:
- name: dns-tcp
port: 53
targetPort: 53
protocol: TCP
- name: dns-udp
port: 53
targetPort: 53
protocol: UDP
- name: web
port: 80
targetPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: adguardhome-lan-svc
namespace: dns
spec:
type: LoadBalancer
selector:
app: adguardhome
loadBalancerIP: 192.168.15.200
ports:
- name: dns-tcp
port: 53
targetPort: 53
protocol: TCP
- name: dns-udp
port: 53
targetPort: 53
protocol: UDP
- name: web
port: 80
targetPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: adguard-install-svc
namespace: dns
spec:
type: ClusterIP
selector:
app: adguardhome
ports:
- name: install
port: 3000
targetPort: 3000
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: adguardhome-ingress
namespace: dns
spec:
ingressClassName: nginx
rules:
- host: adguard.haven
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: adguardhome-svc
port:
number: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: adguardhome-install-ingress
namespace: dns
spec:
ingressClassName: nginx
rules:
- host: install.adguard.haven
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: adguard-install-svc
port:
number: 3000
+4
View File
@@ -0,0 +1,4 @@
## Create namespace
```bash
kubectl create namespace docker-ingress
```
+44
View File
@@ -0,0 +1,44 @@
# docker-node: iris.haven
# port: 4100
# Service
apiVersion: v1
kind: Service
metadata:
name: changedetection-service
namespace: docker-ingress
spec:
ports:
- port: 80
targetPort: 4100
---
# Endpoints
apiVersion: v1
kind: Endpoints
metadata:
name: changedetection-service
namespace: docker-ingress
subsets:
- addresses:
- ip: 192.168.20.100
ports:
- port: 4100
---
# Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: changedetection-ingress
namespace: docker-ingress
spec:
rules:
- host: change.haven
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: changedetection-service
port:
number: 80
+47
View File
@@ -0,0 +1,47 @@
# docker-node: iris.haven
# port: 4100
# Service
apiVersion: v1
kind: Service
metadata:
name: dockge-service
namespace: docker-ingress
spec:
ports:
- name: http
protocol: TCP
port: 80
targetPort: 5001
---
apiVersion: v1
kind: Endpoints
metadata:
name: dockge-service
namespace: docker-ingress
subsets:
- addresses:
- ip: 192.168.20.100
ports:
- name: http
protocol: TCP
port: 5001
---
# Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: dockge-ingress
namespace: docker-ingress
spec:
rules:
- host: dockge.haven
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: dockge-service
port:
number: 80
+3
View File
@@ -0,0 +1,3 @@
```bash
kubectl create secret generic beszel-key --from-literal=SECRET-KEY=<KEY> -n infra
```
+31
View File
@@ -0,0 +1,31 @@
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: beszel-agent
namespace: infra
spec:
selector:
matchLabels:
app: beszel-agent
template:
metadata:
labels:
app: beszel-agent
spec:
hostNetwork: true
containers:
- env:
- name: PORT
value: "45876"
- name: KEY
valueFrom:
secretKeyRef:
name: beszel-key
key: SECRET-KEY
image: henrygd/beszel-agent:0.17.0
imagePullPolicy: Always
name: beszel-agent
ports:
- containerPort: 45876
hostPort: 45876
restartPolicy: Always
+5 -8
View File
@@ -26,17 +26,11 @@ spec:
- amd64
containers:
- name: beszel
image: ghcr.io/henrygd/beszel/beszel:0.20.0
image: ghcr.io/henrygd/beszel/beszel:0.17.0
imagePullPolicy: Always
ports:
- containerPort: 8090
name: beszel-port
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
volumeMounts:
- name: beszel-config
mountPath: /beszel_data
@@ -65,6 +59,8 @@ kind: PersistentVolumeClaim
metadata:
name: beszel-config
namespace: infra
annotations:
nfs.io/storage-path: "beszel-config"
spec:
storageClassName: "nfs-client"
accessModes:
@@ -80,6 +76,7 @@ metadata:
name: beszel
namespace: infra
spec:
ingressClassName: nginx
rules:
- host: beszel.haven
http:
@@ -44,7 +44,7 @@ spec:
cpu: 200m
limits:
memory: 1Gi
cpu: 2000m
cpu: 500m
ports:
- containerPort: 8443
name: code-port
@@ -82,6 +82,8 @@ kind: PersistentVolumeClaim
metadata:
name: code-config
namespace: infra
annotations:
nfs.io/storage-path: "code-config"
spec:
storageClassName: "nfs-client"
accessModes:
@@ -97,6 +99,7 @@ metadata:
name: code-config
namespace: infra
spec:
ingressClassName: nginx
rules:
- host: code-config.haven
http:
@@ -2,16 +2,10 @@ apiVersion: apps/v1
kind: Deployment
metadata:
name: haven-notify
namespace: infra
labels:
app: haven-notify
spec:
replicas: 2
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
replicas: 1
selector:
matchLabels:
app: haven-notify
@@ -44,20 +38,11 @@ spec:
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi
---
apiVersion: v1
kind: Service
metadata:
name: haven-notify
namespace: infra
spec:
selector:
app: haven-notify
@@ -70,8 +55,9 @@ apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: haven-notify
namespace: infra
namespace: default
spec:
ingressClassName: nginx
rules:
- host: notify.haven
http:
+124
View File
@@ -0,0 +1,124 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: wg-easy-pvc
namespace: infra
annotations:
nfs.io/storage-path: "wg-easy-config"
spec:
storageClassName: "nfs-client"
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: wg-easy
namespace: infra
spec:
strategy:
type: Recreate
replicas: 1
selector:
matchLabels:
app: wg-easy
template:
metadata:
labels:
app: wg-easy
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- nexus
containers:
- name: wg-easy
image: ghcr.io/wg-easy/wg-easy:latest
imagePullPolicy: Always
ports:
- containerPort: 51820
protocol: UDP
name: wg-port
- containerPort: 51821
protocol: TCP
name: web-port
env:
- name: LANG
value: en
- name: WG_HOST
value: vpn.ivanch.me
- name: WG_MTU
value: "1420"
- name: UI_TRAFFIC_STATS
value: "true"
- name: UI_CHART_TYPE
value: "0"
- name: WG_ENABLE_ONE_TIME_LINKS
value: "true"
- name: UI_ENABLE_SORT_CLIENTS
value: "true"
securityContext:
capabilities:
add:
- NET_ADMIN
- SYS_MODULE
resources:
requests:
cpu: 100m
memory: 256Mi
volumeMounts:
- name: wg-easy-volume
mountPath: /etc/wireguard
restartPolicy: Always
volumes:
- name: wg-easy-volume
persistentVolumeClaim:
claimName: wg-easy-pvc
---
apiVersion: v1
kind: Service
metadata:
name: wg-easy-svc
namespace: infra
spec:
type: LoadBalancer
selector:
app: wg-easy
loadBalancerIP: 192.168.20.203
ports:
- name: wg-port
port: 51820
targetPort: 51820
protocol: UDP
- name: web-port
port: 51821
targetPort: 51821
protocol: TCP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: wg-easy-ingress
namespace: infra
spec:
ingressClassName: nginx
rules:
- host: vpn.haven
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: wg-easy-svc
port:
number: 51821
+37
View File
@@ -0,0 +1,37 @@
apiVersion: v1
kind: Pod
metadata:
name: nfs-pod
spec:
containers:
- name: nfs-container
image: alpine:latest
env:
- name: PUID
value: "1000"
- name: PGID
value: "1000"
volumeMounts:
- name: nfs-backup
mountPath: /mnt/Backup
- name: nfs-storage
mountPath: /mnt/Storage
command: ["/bin/sh", "-c", "sleep infinity"]
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 800m
memory: 256Mi
securityContext:
privileged: true
volumes:
- name: nfs-backup
nfs:
server: 192.168.15.99
path: /srv/dev-md1/Backup
- name: nfs-storage
nfs:
server: 192.168.15.99
path: /export/Storage
+22
View File
@@ -0,0 +1,22 @@
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: default-pool
namespace: metallb-system
spec:
addresses:
- 192.168.15.200/32 # reserved for DNS 1
- 192.168.15.202/32 # reserved for wg-easy
- 192.168.15.203/32 # reserved for k3s ingress
- 192.168.20.200/32 # reserved for DNS 1
# - 192.168.20.201 is reserved for DNS 2
- 192.168.20.202-192.168.20.220
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: default-advertisement
namespace: metallb-system
spec:
ipAddressPools:
- default-pool
@@ -47,10 +47,10 @@ spec:
resources:
requests:
cpu: 250m
memory: 512Mi
memory: 750Mi
limits:
memory: 2Gi
cpu: 1000m
memory: 1Gi
cpu: 500m
volumeMounts:
- mountPath: /var/lib/grafana
name: grafana-pv
@@ -64,6 +64,8 @@ kind: PersistentVolumeClaim
metadata:
name: grafana-pvc
namespace: monitoring
annotations:
nfs.io/storage-path: "grafana-data"
spec:
storageClassName: "nfs-client"
accessModes:
@@ -92,6 +94,7 @@ metadata:
namespace: monitoring
name: grafana
spec:
ingressClassName: nginx
rules:
- host: grafana.haven
http:
@@ -110,6 +113,7 @@ metadata:
namespace: monitoring
name: grafana-public
spec:
ingressClassName: nginx
rules:
- host: grafanah.ivanch.me
http:
+109
View File
@@ -0,0 +1,109 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: kube-state-metrics
namespace: monitoring
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: kube-state-metrics
rules:
- apiGroups: [""]
resources:
- nodes
- pods
- services
- endpoints
- namespaces
- replicationcontrollers
verbs: ["list", "watch"]
- apiGroups: ["extensions", "apps"]
resources:
- daemonsets
- deployments
- replicasets
- statefulsets
verbs: ["list", "watch"]
- apiGroups: ["batch"]
resources:
- cronjobs
- jobs
verbs: ["list", "watch"]
- apiGroups: ["autoscaling"]
resources:
- horizontalpodautoscalers
verbs: ["list", "watch"]
- apiGroups: ["policy"]
resources:
- poddisruptionbudgets
verbs: ["list", "watch"]
- apiGroups: ["storage.k8s.io"]
resources:
- storageclasses
- volumeattachments
verbs: ["list", "watch"]
- apiGroups: ["apps"]
resources:
- replicasets
verbs: ["list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kube-state-metrics
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: kube-state-metrics
subjects:
- kind: ServiceAccount
name: kube-state-metrics
namespace: monitoring
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: kube-state-metrics
namespace: monitoring
labels:
app: kube-state-metrics
spec:
replicas: 1
selector:
matchLabels:
app: kube-state-metrics
template:
metadata:
labels:
app: kube-state-metrics
spec:
serviceAccountName: kube-state-metrics
containers:
- name: kube-state-metrics
image: registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.13.0
ports:
- name: http-metrics
containerPort: 8080
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 256Mi
---
apiVersion: v1
kind: Service
metadata:
name: kube-state-metrics
namespace: monitoring
labels:
app: kube-state-metrics
spec:
ports:
- name: http-metrics
port: 8080
targetPort: http-metrics
selector:
app: kube-state-metrics
@@ -5,8 +5,6 @@ metadata:
namespace: monitoring
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: loki
@@ -26,21 +24,13 @@ spec:
mountPath: /etc/loki/config
- name: loki-storage
mountPath: /tmp/loki
resources:
requests:
cpu: 100m
memory: 1Gi
limits:
cpu: 200m
memory: 1Gi
volumes:
- name: config
configMap:
name: loki-config
- name: loki-storage
nfs:
server: nexus.haven
path: /export/sandbox/loki
emptyDir:
medium: Memory
---
apiVersion: v1
kind: ConfigMap
@@ -82,12 +72,7 @@ data:
limits_config:
allow_structured_metadata: true
retention_period: 72h
max_query_lookback: 72h
# Global per-tenant cap: <= 0.1 MB/s sustained keeps this sandbox disk bounded.
ingestion_rate_strategy: global
ingestion_rate_mb: 0.1
ingestion_burst_size_mb: 0.5
retention_period: 0
ingester:
lifecycler:
@@ -100,12 +85,7 @@ data:
chunk_target_size: 1536000
compactor:
working_directory: /tmp/loki/compactor
compaction_interval: 10m
retention_enabled: true
retention_delete_delay: 2h
retention_delete_worker_count: 10
delete_request_store: filesystem
retention_enabled: false
---
apiVersion: v1
kind: Service
@@ -7,8 +7,6 @@ metadata:
app: prometheus
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: prometheus
@@ -24,9 +22,7 @@ spec:
args:
- "--config.file=/etc/prometheus/prometheus.yml"
- "--storage.tsdb.path=/prometheus"
- "--storage.tsdb.retention.time=2d"
# Keep a generous buffer on the 117 GiB sandbox filesystem; WAL may exceed this briefly.
- "--storage.tsdb.retention.size=8GB"
- "--storage.tsdb.retention.time=1d"
- "--web.enable-lifecycle"
ports:
- containerPort: 9090
@@ -48,15 +44,17 @@ spec:
persistentVolumeClaim:
claimName: prometheus-pvc
- name: prometheus-storage
nfs:
server: nexus.haven
path: /export/sandbox/prometheus
emptyDir:
medium: Memory
sizeLimit: 256Mi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: prometheus-pvc
namespace: monitoring
annotations:
nfs.io/storage-path: "prometheus-config"
spec:
storageClassName: "nfs-client"
accessModes:
@@ -65,19 +63,6 @@ spec:
requests:
storage: 1Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: prometheus-storage-pvc
namespace: monitoring
spec:
storageClassName: "nfs-client"
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
---
# Service URL - http://prometheus.monitoring.svc.cluster.local:9090
apiVersion: v1
kind: Service
@@ -111,7 +96,7 @@ metadata:
labels:
app: prometheus
rules:
- apiGroups: [""]
- apiGroups: [""]
resources:
- nodes
- nodes/proxy
@@ -119,11 +104,11 @@ rules:
- endpoints
- pods
verbs: ["get", "list", "watch"]
- apiGroups: ["extensions"]
- apiGroups: ["extensions"]
resources:
- ingresses
verbs: ["get", "list", "watch"]
- apiGroups: ["networking.k8s.io"]
- apiGroups: ["networking.k8s.io"]
resources:
- ingresses
verbs: ["get", "list", "watch"]
@@ -140,6 +125,6 @@ roleRef:
kind: ClusterRole
name: prometheus
subjects:
- kind: ServiceAccount
- kind: ServiceAccount
name: prometheus
namespace: monitoring
-21
View File
@@ -1,21 +0,0 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"prHourlyLimit": 0,
"kubernetes": {
"managerFilePatterns": [
"/\\.yaml$/"
]
},
"packageRules": [
{
"description": "Skip local registry images (built by CI, not upstream deps)",
"matchDatasources": [
"docker"
],
"matchPackageNames": [
"git.ivanch.me/**"
],
"enabled": false
}
]
}
-24
View File
@@ -1,24 +0,0 @@
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata: { name: adguardhome-password, namespace: dns }
spec:
refreshInterval: 1h
target:
name: adguardhome-password
deletionPolicy: Retain
template:
type: Opaque
data:
username: "{{ .username }}"
password: "{{ .password }}"
data:
- secretKey: username
remoteRef:
{ key: 5bc7e63f-18bb-482c-bc3e-740e03b26334, property: username }
sourceRef:
{ storeRef: { name: bitwarden-login, kind: ClusterSecretStore } }
- secretKey: password
remoteRef:
{ key: 5bc7e63f-18bb-482c-bc3e-740e03b26334, property: password }
sourceRef:
{ storeRef: { name: bitwarden-login, kind: ClusterSecretStore } }
-36
View File
@@ -1,36 +0,0 @@
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata: { name: affine, namespace: cloud }
spec:
refreshInterval: 1h
target:
name: affine-secret
deletionPolicy: Retain
template:
type: Opaque
data:
DB_USERNAME: "{{ .DB_USERNAME }}"
DB_PASSWORD: "{{ .DB_PASSWORD }}"
DB_NAME: "{{ .DB_NAME }}"
DB_URL: "{{ .DB_URL }}"
DB_CONNECTION_URL: "postgres://{{ .DB_USERNAME }}:{{ .DB_PASSWORD }}@{{ .DB_URL }}:5432/{{ .DB_NAME }}"
data:
- secretKey: DB_USERNAME
remoteRef:
{ key: 4f15af1c-9b66-41d0-80db-a99ebe50e91f, property: username }
sourceRef:
{ storeRef: { name: bitwarden-login, kind: ClusterSecretStore } }
- secretKey: DB_PASSWORD
remoteRef:
{ key: 4f15af1c-9b66-41d0-80db-a99ebe50e91f, property: password }
sourceRef:
{ storeRef: { name: bitwarden-login, kind: ClusterSecretStore } }
- secretKey: DB_NAME
remoteRef:
{ key: 4f15af1c-9b66-41d0-80db-a99ebe50e91f, property: DB_NAME }
sourceRef:
{ storeRef: { name: bitwarden-fields, kind: ClusterSecretStore } }
- secretKey: DB_URL
remoteRef: { key: 4f15af1c-9b66-41d0-80db-a99ebe50e91f, property: DB_URL }
sourceRef:
{ storeRef: { name: bitwarden-fields, kind: ClusterSecretStore } }
-24
View File
@@ -1,24 +0,0 @@
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata: { name: archivebox-password, namespace: default }
spec:
refreshInterval: 1h
target:
name: archivebox-password
deletionPolicy: Retain
template:
type: Opaque
data:
username: "{{ .username }}"
password: "{{ .password }}"
data:
- secretKey: username
remoteRef:
{ key: 6b4ca371-dcd4-4e31-aebe-8e5ea48b1fb9, property: username }
sourceRef:
{ storeRef: { name: bitwarden-login, kind: ClusterSecretStore } }
- secretKey: password
remoteRef:
{ key: 6b4ca371-dcd4-4e31-aebe-8e5ea48b1fb9, property: password }
sourceRef:
{ storeRef: { name: bitwarden-login, kind: ClusterSecretStore } }
-30
View File
@@ -1,30 +0,0 @@
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata: { name: cloudreve, namespace: cloud }
spec:
refreshInterval: 1h
target:
name: cloudreve-secret
deletionPolicy: Retain
template:
type: Opaque
data:
DB_USER: "{{ .DB_USER }}"
DB_PASSWORD: "{{ .DB_PASSWORD }}"
DB_NAME: "{{ .DB_NAME }}"
data:
- secretKey: DB_USER
remoteRef:
{ key: 8c25cac9-e9e8-4970-bdf4-31f9aee19276, property: username }
sourceRef:
{ storeRef: { name: bitwarden-login, kind: ClusterSecretStore } }
- secretKey: DB_PASSWORD
remoteRef:
{ key: 8c25cac9-e9e8-4970-bdf4-31f9aee19276, property: password }
sourceRef:
{ storeRef: { name: bitwarden-login, kind: ClusterSecretStore } }
- secretKey: DB_NAME
remoteRef:
{ key: 8c25cac9-e9e8-4970-bdf4-31f9aee19276, property: DB_NAME }
sourceRef:
{ storeRef: { name: bitwarden-fields, kind: ClusterSecretStore } }
-21
View File
@@ -1,21 +0,0 @@
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata: { name: discord-webhook, namespace: infra }
spec:
refreshInterval: 1h
target:
name: discord-webhook
deletionPolicy: Retain
template:
type: Opaque
data:
HAVEN_WEBHOOK_URL: "{{ .HAVEN_WEBHOOK_URL }}"
data:
- secretKey: HAVEN_WEBHOOK_URL
remoteRef:
{
key: afd065bd-be8f-4e3c-a06e-e9d3089cb8f7,
property: HAVEN_WEBHOOK_URL,
}
sourceRef:
{ storeRef: { name: bitwarden-fields, kind: ClusterSecretStore } }
-21
View File
@@ -1,21 +0,0 @@
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata: { name: gitea-runner, namespace: dev }
spec:
refreshInterval: 1h
target:
name: gitea-runner-token
deletionPolicy: Retain
template:
type: Opaque
data:
REGISTRATION_TOKEN: "{{ .REGISTRATION_TOKEN }}"
data:
- secretKey: REGISTRATION_TOKEN
remoteRef:
{
key: 4e286657-b5de-4354-be2e-d1649b0fd527,
property: REGISTRATION_TOKEN,
}
sourceRef:
{ storeRef: { name: bitwarden-fields, kind: ClusterSecretStore } }
-18
View File
@@ -1,18 +0,0 @@
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata: { name: kasbot, namespace: default }
spec:
refreshInterval: 1h
target:
name: kasbot-secrets
deletionPolicy: Retain
template:
type: Opaque
data:
KASBOT_TOKEN: "{{ .KASBOT_TOKEN }}"
data:
- secretKey: KASBOT_TOKEN
remoteRef:
{ key: 885a7d90-95be-494f-af88-300ac6a7e210, property: KASBOT_TOKEN }
sourceRef:
{ storeRef: { name: bitwarden-fields, kind: ClusterSecretStore } }
-27
View File
@@ -1,27 +0,0 @@
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata: { name: openwebui, namespace: default }
spec:
refreshInterval: 1h
target:
name: openwebui-secret
deletionPolicy: Retain
template:
type: Opaque
data:
DATABASE_URL: "postgresql://{{ .username }}:{{ .password }}@postgresql.haven:5432/{{ .dbname }}"
data:
- secretKey: username
remoteRef:
{ key: e80ff314-7445-4b61-b5c5-69285ea72586, property: username }
sourceRef:
{ storeRef: { name: bitwarden-login, kind: ClusterSecretStore } }
- secretKey: password
remoteRef:
{ key: e80ff314-7445-4b61-b5c5-69285ea72586, property: password }
sourceRef:
{ storeRef: { name: bitwarden-login, kind: ClusterSecretStore } }
- secretKey: dbname
remoteRef: { key: e80ff314-7445-4b61-b5c5-69285ea72586, property: dbname }
sourceRef:
{ storeRef: { name: bitwarden-fields, kind: ClusterSecretStore } }
-48
View File
@@ -1,48 +0,0 @@
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata: { name: paperless, namespace: default }
spec:
refreshInterval: 1h
target:
name: paperless-secret
deletionPolicy: Retain
template:
type: Opaque
data:
PAPERLESS_DBNAME: "{{ .PAPERLESS_DBNAME }}"
PAPERLESS_DBUSER: "{{ .PAPERLESS_DBUSER }}"
PAPERLESS_DBPASSWORD: "{{ .PAPERLESS_DBPASSWORD }}"
PAPERLESS_SECRET_KEY: "{{ .PAPERLESS_SECRET_KEY }}"
data:
- secretKey: PAPERLESS_DBNAME
remoteRef:
{
key: 05426e55-fe04-4c16-8697-8a258928257a,
property: PAPERLESS_DBNAME,
}
sourceRef:
{ storeRef: { name: bitwarden-fields, kind: ClusterSecretStore } }
- secretKey: PAPERLESS_DBUSER
remoteRef:
{
key: 05426e55-fe04-4c16-8697-8a258928257a,
property: PAPERLESS_DBUSER,
}
sourceRef:
{ storeRef: { name: bitwarden-fields, kind: ClusterSecretStore } }
- secretKey: PAPERLESS_DBPASSWORD
remoteRef:
{
key: 05426e55-fe04-4c16-8697-8a258928257a,
property: PAPERLESS_DBPASSWORD,
}
sourceRef:
{ storeRef: { name: bitwarden-fields, kind: ClusterSecretStore } }
- secretKey: PAPERLESS_SECRET_KEY
remoteRef:
{
key: 05426e55-fe04-4c16-8697-8a258928257a,
property: PAPERLESS_SECRET_KEY,
}
sourceRef:
{ storeRef: { name: bitwarden-fields, kind: ClusterSecretStore } }
-27
View File
@@ -1,27 +0,0 @@
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata: { name: renovate-bot, namespace: cronjobs }
spec:
refreshInterval: 1h
target:
name: renovate-bot
deletionPolicy: Retain
template:
type: Opaque
data:
RENOVATE_GITHUB_COM_TOKEN: "{{ .RENOVATE_GITHUB_COM_TOKEN }}"
RENOVATE_TOKEN: "{{ .RENOVATE_TOKEN }}"
data:
- secretKey: RENOVATE_GITHUB_COM_TOKEN
remoteRef:
{
key: 25b1f5c9-0a2b-438e-a4c6-23ea1d58e2de,
property: RENOVATE_GITHUB_COM_TOKEN,
}
sourceRef:
{ storeRef: { name: bitwarden-fields, kind: ClusterSecretStore } }
- secretKey: RENOVATE_TOKEN
remoteRef:
{ key: 25b1f5c9-0a2b-438e-a4c6-23ea1d58e2de, property: RENOVATE_TOKEN }
sourceRef:
{ storeRef: { name: bitwarden-fields, kind: ClusterSecretStore } }
-30
View File
@@ -1,30 +0,0 @@
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata: { name: slink, namespace: cloud }
spec:
refreshInterval: 1h
target:
name: slink-secret
deletionPolicy: Retain
template:
type: Opaque
data:
ADMIN_USERNAME: "{{ .ADMIN_USERNAME }}"
ADMIN_PASSWORD: "{{ .ADMIN_PASSWORD }}"
ADMIN_EMAIL: "{{ .ADMIN_EMAIL }}"
data:
- secretKey: ADMIN_USERNAME
remoteRef:
{ key: 79f97033-6bc3-40cd-a28c-6060b8bd3a63, property: username }
sourceRef:
{ storeRef: { name: bitwarden-login, kind: ClusterSecretStore } }
- secretKey: ADMIN_PASSWORD
remoteRef:
{ key: 79f97033-6bc3-40cd-a28c-6060b8bd3a63, property: password }
sourceRef:
{ storeRef: { name: bitwarden-login, kind: ClusterSecretStore } }
- secretKey: ADMIN_EMAIL
remoteRef:
{ key: 79f97033-6bc3-40cd-a28c-6060b8bd3a63, property: ADMIN_EMAIL }
sourceRef:
{ storeRef: { name: bitwarden-fields, kind: ClusterSecretStore } }