24 Commits
Author SHA1 Message Date
ivanch 12b14ca9d4 adding new csi-driver-nfs 2026-09-01 20:10:29 -03:00
ivanch ad5b5c6bb1 removing old nfs-provisioner 2026-09-01 20:09:51 -03:00
ivanch 64aa2da745 swapping nginx ingress to traefik 2026-08-31 20:23:17 -03:00
ivanch b18c3175aa removing ingressClassName: nginx definition 2026-08-31 20:14:37 -03:00
ivanch 164d31efa7 alloy: fix helm values nesting — configMap/clustering/mounts/resources belong under alloy.*; chart was silently ignoring them (logs never collected) 2026-08-30 20:06:23 -03:00
ivanch 5c129570da configuring api user for argocd 2026-08-30 20:02:13 -03:00
ivanch d9016105ed improving setup 2026-08-30 19:32:37 -03:00
ivanch 04ab8f9407 adding new helms 2026-08-30 19:32:25 -03:00
ivanch 237f6d5bad changing secrets to private repo 2026-08-30 18:57:28 -03:00
ivanch 3e7605d65e Merge branch 'main' of git.ivanch.me:ivanch/haven-ops 2026-08-30 17:18:03 -03:00
ivanch b582699d21 removing qbittorrent 2026-08-30 17:17:47 -03:00
ivanch 140198f513 Merge pull request 'Update mcr.microsoft.com/playwright Docker tag to v1.62.1' (#5) from renovate/mcr.microsoft.com-playwright-1.x into main
Reviewed-on: #5
2026-08-30 19:17:17 +00:00
ivanch 66dae6b74b Merge pull request 'Update lscr.io/linuxserver/qbittorrent Docker tag to v5.2.3' (#4) from renovate/lscr.io-linuxserver-qbittorrent-5.x into main
Reviewed-on: #4
2026-08-30 19:17:05 +00:00
Renovate Bot 7b367fb8a1 Update mcr.microsoft.com/playwright Docker tag to v1.62.1 2026-08-30 15:02:35 +00:00
Renovate Bot cf61cb0816 Update lscr.io/linuxserver/qbittorrent Docker tag to v5.2.3 2026-08-30 15:02:19 +00:00
ivanch ba10ac87e0 adding renovatebot 2026-08-29 16:22:19 -03:00
ivanch 3c5d38fa58 Merge pull request 'Update ghcr.io/henrygd/beszel/beszel Docker tag to v0.18.8' (#2) from renovate/ghcr.io-henrygd-beszel-beszel-0.x into main
Reviewed-on: #2
2026-08-29 18:39:28 +00:00
ivanch a0d8ffe01e Merge pull request 'Update ghcr.io/charlesthomas/bitwarden-cli Docker tag to v2026.7.0' (#3) from renovate/ghcr.io-charlesthomas-bitwarden-cli-2026.x into main
Reviewed-on: #3
2026-08-29 18:39:15 +00:00
Renovate Bot f7bfe91ef5 Update ghcr.io/charlesthomas/bitwarden-cli Docker tag to v2026.7.0 2026-08-29 18:37:53 +00:00
Renovate Bot c78b1fe096 Update ghcr.io/henrygd/beszel/beszel Docker tag to v0.18.8 2026-08-29 18:37:51 +00:00
ivanch 2f7fa75230 renovate: enable kubernetes manager for plain YAML manifests 2026-08-29 15:36:46 -03:00
ivanch 9a5abf3067 adding secrets 2026-08-29 15:36:01 -03:00
ivanch f88a34135e Merge pull request 'Configure Renovate' (#1) from renovate/configure into main
Reviewed-on: #1
2026-08-29 18:28:08 +00:00
Renovate Bot d21c14344c Add renovate.json 2026-08-29 18:27:23 +00:00
50 changed files with 788 additions and 646 deletions
+1 -107
View File
@@ -1,19 +1,4 @@
# GitOps on Haven — Deployment Draft # Haven
> **Draft only.** Nothing below is applied to the cluster yet. Diagrams are
> [Excalidraw JSON] (import at https://excalidraw.com) — static previews included
> as PNG. Create the repo before running any commands.
## 1. Decisions
| Decision | Value | Why |
|---|---|---|
| Tool | **Argo CD** | Best UI (app dependency graph, live-vs-git diff, rollback). Flux's UI (Weave GitOps) is stalled post-Weaveworks; community alternative is Capacitor. |
| Git remote | **Gitea** `git.ivanch.me/ivanch/haven` | Repo you'll create. Gitea is a first-class Argo CD source. |
| Layout | **App-of-apps** | A single root Argo `Application` watches a folder of app manifests; each app manifests as a child `Application`. One place to add/remove apps. |
| Secrets | **No change.** Keep raw env in manifests initially, migrate to ESO/Vaultwarden later. | Argo CD can't write Secret contents itself — value must live in git or come from a controller. Never commit real secrets. |
| Access | Ingress `argocd.haven`, internal-only (nginx class, **no TLS/cert-manager**) + admin password via kubectl | Matches your internal-app convention (`notepad`, `openwebui`, etc.). |
| Repo structure | **New `gitops` repo** (clean, standalone). Your current spec folder stays untouched — migrate later if desired. | Avoids mixing with the `haven` folder used by Gitea Actions CI. |
## 2. Repo layout (`gitops/`) ## 2. Repo layout (`gitops/`)
@@ -31,94 +16,3 @@ gitops/
│ ├── <app-1>.yaml # all-in-one manifest per app │ ├── <app-1>.yaml # all-in-one manifest per app
│ └── <app-2>.yaml │ └── <app-2>.yaml
``` ```
To add a new app: simply drop `<app>.yaml` into the appropriate `apps/<namespace>/` folder. The ApplicationSet automatically generates an Argo CD Application for it.
## 3. Manual bootstrap (run once, by hand)
```bash
# Install Argo CD — declarative kustomize install (no Helm CLI, no curl pipes).
# Renders 59 resources from the official argo-cd manifests repo, pinned via ?ref=
kubectl.exe --kubeconfig=C:\Users\ivanch\.kube\config apply -k bootstrap/argocd-install
# retrieve the initial admin password
kubectl.exe --kubeconfig=C:\Users\ivanch\.kube\config -n argocd get secret argocd-initial-admin-secret \
-o jsonpath='{.data.password}' | base64 -d
# one-time: point the root app at Gitea (requires the repo to exist first)
kubectl.exe --kubeconfig=C:\Users\ivanch\.kube\config apply -f bootstrap/root-app.yaml
```
Version pinning: `?ref=stable` in `bootstrap/argocd-install/kustomization.yaml`
tracks the stable branch; pin a tag (`?ref=v3.1.0`) once settled. Component
customization goes through `patches:` in that same kustomization (example
commented in the file), not by editing rendered output.
After that, **every** change is: `git push` → Argo syncs. kubectl only for debugging.
## 4. Key manifests
**`bootstrap/root-app.yaml`**
```yaml
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
```
**`apps/root/applicationset.yaml`** — Uses the Git Files generator to discover any `apps/*/*.yaml` file and automatically generate an Argo CD `Application` pointing directly to that app file within the respective namespace.
## 5. Ingress (internal-only, per Haven convention)
```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: argocd-server
namespace: argocd
spec:
ingressClassName: nginx
rules:
- host: argocd.haven
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: argocd-server
port: { number: 80 }
```
## 6. Diagrams (Excalidraw JSON)
Two diagrams are included as `.excalidraw` files — open https://excalidraw.com
and drop the file onto the canvas to view/edit:
- `excalidraw/haven-gitops-flow.excalidraw` — the flow: git push → Gitea →
Argo CD → k3s, with Gitea Actions CI reduced to image build/push only.
- `excalidraw/haven-gitops-tree.excalidraw` — the app-of-apps tree: root app →
child Applications (notepad, openwebui, paperless, vaultwarden, argocd itself,
and infra deferred to a later phase).
## 7. Migration plan
Phase 0 (this draft) → Phase 1: install Argo CD + root app, convert 1 pilot app
(suggest `notepad` — simple, stateless-ish, single PVC) → Phase 2: onboard the
rest of `default` ns → Phase 3: infra components (ingress-nginx, cert-manager,
ESO) — do these **last**; they're the ones that can break the cluster if a sync
goes wrong → Phase 4: delete the old `haven` spec folder once Argo is the source
of truth.
+32 -6
View File
@@ -1,12 +1,22 @@
# Initial setup # Setup Instructions
```sh
# Create namespace ## Pre-installation
1. Create namespaces with
```bash
kubectl apply -f bootstrap/namespaces.yaml kubectl apply -f bootstrap/namespaces.yaml
```
# Install ArgoCD 2. Apply Vaultwarden deployment app
```bash
kubectl apply -f apps/default/vaultwarden.yaml
```
3. Configure required secrets in `secrets/` directory, each mapping to an entity in Vaultwarden.
## ArgoCD Installation
```sh
kubectl apply -k bootstrap/argocd-install kubectl apply -k bootstrap/argocd-install
# Apply root app
kubectl apply -f bootstrap/root-app.yaml kubectl apply -f bootstrap/root-app.yaml
``` ```
@@ -17,3 +27,19 @@ kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.pas
``` ```
2. Access ArgoCD and login with `admin` / password from above. 2. Access ArgoCD and login with `admin` / password from above.
## External Secrets Operator preparation
Create this Secret manually. `BW_HOST` must have no trailing slash.
```bash
kubectl -n infra create secret generic bitwarden-cli \
--from-literal=BW_HOST='[VAULTWARDEN_URL]' \
--from-literal=BW_USERNAME='[VAULTWARDEN_EMAIL]' \
--from-literal=BW_PASSWORD='[VAULTWARDEN_PASSWORD]'
```
## Apply order
1. `kubectl apply -f secrets/`
2. `kubectl apply -f apps/metalldb-system/`
3. `kubectl apply -f apps/infra/`
+3 -2
View File
@@ -19,11 +19,12 @@ spec:
targetRevision: 1.12.1 targetRevision: 1.12.1
helm: helm:
valuesObject: valuesObject:
controller:
type: daemonset
alloy:
clustering: { enabled: false } clustering: { enabled: false }
mounts: mounts:
varlog: true varlog: true
controller:
type: daemonset
resources: resources:
requests: requests:
cpu: 100m cpu: 100m
-1
View File
@@ -115,7 +115,6 @@ metadata:
labels: labels:
app: affine app: affine
spec: spec:
ingressClassName: nginx
rules: rules:
- host: affine.haven - host: affine.haven
http: http:
-2
View File
@@ -135,7 +135,6 @@ metadata:
nginx.ingress.kubernetes.io/proxy-read-timeout: "600" nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "600" nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
spec: spec:
ingressClassName: nginx
rules: rules:
- host: cloud.haven - host: cloud.haven
http: http:
@@ -158,7 +157,6 @@ metadata:
nginx.ingress.kubernetes.io/proxy-read-timeout: "600" nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "600" nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
spec: spec:
ingressClassName: nginx
rules: rules:
- host: cloud.ivanch.me - host: cloud.ivanch.me
http: http:
-1
View File
@@ -122,7 +122,6 @@ metadata:
nginx.ingress.kubernetes.io/proxy-read-timeout: "600" nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "600" nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
spec: spec:
ingressClassName: nginx
rules: rules:
- host: slink.haven - host: slink.haven
http: http:
+39
View File
@@ -0,0 +1,39 @@
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.39.3
args:
- ivanch/haven-ops
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
-1
View File
@@ -145,7 +145,6 @@ metadata:
name: archivebox-ingress name: archivebox-ingress
namespace: default namespace: default
spec: spec:
ingressClassName: nginx
rules: rules:
- host: "archive.haven" - host: "archive.haven"
http: http:
-1
View File
@@ -140,7 +140,6 @@ metadata:
labels: labels:
app.kubernetes.io/name: changedetection app.kubernetes.io/name: changedetection
spec: spec:
ingressClassName: nginx
rules: rules:
- host: change.haven - host: change.haven
http: http:
-1
View File
@@ -192,7 +192,6 @@ metadata:
labels: labels:
app.kubernetes.io/name: homepage app.kubernetes.io/name: homepage
spec: spec:
ingressClassName: nginx
rules: rules:
- host: "homepage.haven" - host: "homepage.haven"
http: http:
-1
View File
@@ -53,7 +53,6 @@ metadata:
name: it-tools-ingress name: it-tools-ingress
namespace: default namespace: default
spec: spec:
ingressClassName: nginx
rules: rules:
- host: "tools.haven" - host: "tools.haven"
http: http:
-1
View File
@@ -77,7 +77,6 @@ metadata:
name: notepad name: notepad
namespace: default namespace: default
spec: spec:
ingressClassName: nginx
rules: rules:
- host: notepad.haven - host: notepad.haven
http: http:
-1
View File
@@ -94,7 +94,6 @@ metadata:
annotations: annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "50m" nginx.ingress.kubernetes.io/proxy-body-size: "50m"
spec: spec:
ingressClassName: nginx
rules: rules:
- host: openwebui.haven - host: openwebui.haven
http: http:
-1
View File
@@ -137,7 +137,6 @@ metadata:
name: paperless name: paperless
namespace: default namespace: default
spec: spec:
ingressClassName: nginx
rules: rules:
- host: paperless.haven - host: paperless.haven
http: http:
+9 -10
View File
@@ -32,13 +32,13 @@ spec:
- playwright@1.58.0 - playwright@1.58.0
- run-server - run-server
- --port - --port
- '3000' - "3000"
- --host - --host
- 0.0.0.0 - 0.0.0.0
env: env:
- name: TZ - name: TZ
value: America/Sao_Paulo value: America/Sao_Paulo
image: mcr.microsoft.com/playwright:v1.58.0-noble image: mcr.microsoft.com/playwright:v1.62.1-noble
imagePullPolicy: Always imagePullPolicy: Always
name: playwright name: playwright
ports: ports:
@@ -46,7 +46,7 @@ spec:
protocol: TCP protocol: TCP
resources: resources:
limits: limits:
cpu: '4' cpu: "4"
memory: 4Gi memory: 4Gi
requests: requests:
cpu: 500m cpu: 500m
@@ -68,17 +68,17 @@ spec:
status: status:
availableReplicas: 1 availableReplicas: 1
conditions: conditions:
- lastTransitionTime: '2026-05-29T15:54:24Z' - lastTransitionTime: "2026-05-29T15:54:24Z"
lastUpdateTime: '2026-07-22T10:14:35Z' lastUpdateTime: "2026-07-22T10:14:35Z"
message: ReplicaSet "playwright-86c74d7c78" has successfully progressed. message: ReplicaSet "playwright-86c74d7c78" has successfully progressed.
reason: NewReplicaSetAvailable reason: NewReplicaSetAvailable
status: 'True' status: "True"
type: Progressing type: Progressing
- lastTransitionTime: '2026-08-28T06:04:14Z' - lastTransitionTime: "2026-08-28T06:04:14Z"
lastUpdateTime: '2026-08-28T06:04:14Z' lastUpdateTime: "2026-08-28T06:04:14Z"
message: Deployment has minimum availability. message: Deployment has minimum availability.
reason: MinimumReplicasAvailable reason: MinimumReplicasAvailable
status: 'True' status: "True"
type: Available type: Available
observedGeneration: 95 observedGeneration: 95
readyReplicas: 1 readyReplicas: 1
@@ -113,7 +113,6 @@ metadata:
name: playwright name: playwright
namespace: default namespace: default
spec: spec:
ingressClassName: nginx
rules: rules:
- host: playwright.haven - host: playwright.haven
http: http:
-132
View File
@@ -1,132 +0,0 @@
---
# 1) Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: qbittorrent
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: qbittorrent
template:
metadata:
labels:
app: qbittorrent
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- iris
containers:
- name: qbittorrent
image: lscr.io/linuxserver/qbittorrent:5.0.4
imagePullPolicy: Always
resources:
requests:
cpu: 200m
memory: 256Mi
limits:
cpu: 1000m
memory: 512Mi
ports:
- containerPort: 4300
name: webui-port
- containerPort: 6881
name: qbit-tcp
protocol: TCP
- containerPort: 6881
name: qbit-udp
protocol: UDP
env:
- name: PUID
value: "1000"
- name: PGID
value: "1000"
- name: TZ
value: "Etc/UTC"
- name: WEBUI_PORT
value: "4300"
- name: TORRENTING_PORT
value: "6881"
volumeMounts:
- name: qbittorrent-config
mountPath: /config
- name: nas-storage
mountPath: /nas
volumes:
- name: qbittorrent-config
persistentVolumeClaim:
claimName: qbittorrent-config
- name: nas-storage
nfs:
server: 192.168.15.99
path: /export/Storage
---
# PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: qbittorrent-config
namespace: default
annotations:
nfs.io/storage-path: "qbittorrent-config"
spec:
storageClassName: "nfs-client"
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
# 2) Service
apiVersion: v1
kind: Service
metadata:
name: qbittorrent
namespace: default
spec:
type: NodePort
selector:
app: qbittorrent
ports:
- port: 4300
targetPort: webui-port
name: webui
- port: 6881
targetPort: qbit-tcp
name: torrent-tcp
protocol: TCP
- port: 6881
targetPort: qbit-udp
name: torrent-udp
protocol: UDP
---
# 4) Ingress (Traefik)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: qbittorrent
namespace: default
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: web
spec:
ingressClassName: nginx
rules:
- host: qbittorrent.haven
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: qbittorrent
port:
number: 4300
-1
View File
@@ -80,7 +80,6 @@ metadata:
name: searxng name: searxng
namespace: default namespace: default
spec: spec:
ingressClassName: nginx
rules: rules:
- host: search.haven - host: search.haven
http: http:
-1
View File
@@ -99,7 +99,6 @@ metadata:
labels: labels:
app: stirlingpdf app: stirlingpdf
spec: spec:
ingressClassName: nginx
rules: rules:
- host: stirling.haven - host: stirling.haven
http: http:
-1
View File
@@ -93,7 +93,6 @@ metadata:
name: uptimekuma name: uptimekuma
namespace: default namespace: default
spec: spec:
ingressClassName: nginx
rules: rules:
- host: uptimekuma.haven - host: uptimekuma.haven
http: http:
-2
View File
@@ -110,7 +110,6 @@ metadata:
cert-manager.io/cluster-issuer: internal-ca cert-manager.io/cluster-issuer: internal-ca
nginx.ingress.kubernetes.io/force-ssl-redirect: "true" nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
spec: spec:
ingressClassName: nginx
tls: tls:
- hosts: - hosts:
- vault.haven - vault.haven
@@ -134,7 +133,6 @@ metadata:
name: vaultwarden-public name: vaultwarden-public
namespace: default namespace: default
spec: spec:
ingressClassName: nginx
rules: rules:
- host: vault.ivanch.me - host: vault.ivanch.me
http: http:
-1
View File
@@ -104,7 +104,6 @@ metadata:
name: adguardsync-ingress name: adguardsync-ingress
namespace: dns namespace: dns
spec: spec:
ingressClassName: nginx
rules: rules:
- host: adguardsync.haven - host: adguardsync.haven
http: http:
-2
View File
@@ -140,7 +140,6 @@ metadata:
name: adguardhome-ingress name: adguardhome-ingress
namespace: dns namespace: dns
spec: spec:
ingressClassName: nginx
rules: rules:
- host: adguard.haven - host: adguard.haven
http: http:
@@ -159,7 +158,6 @@ metadata:
name: adguardhome-install-ingress name: adguardhome-install-ingress
namespace: dns namespace: dns
spec: spec:
ingressClassName: nginx
rules: rules:
- host: install.adguard.haven - host: install.adguard.haven
http: http:
+1 -2
View File
@@ -26,7 +26,7 @@ spec:
- amd64 - amd64
containers: containers:
- name: beszel - name: beszel
image: ghcr.io/henrygd/beszel/beszel:0.18.7 image: ghcr.io/henrygd/beszel/beszel:0.18.8
imagePullPolicy: Always imagePullPolicy: Always
ports: ports:
- containerPort: 8090 - containerPort: 8090
@@ -83,7 +83,6 @@ metadata:
name: beszel name: beszel
namespace: infra namespace: infra
spec: spec:
ingressClassName: nginx
rules: rules:
- host: beszel.haven - host: beszel.haven
http: http:
+1 -1
View File
@@ -19,7 +19,7 @@ spec:
kubernetes.io/arch: amd64 kubernetes.io/arch: amd64
containers: containers:
- name: bitwarden-cli - name: bitwarden-cli
image: ghcr.io/charlesthomas/bitwarden-cli:2026.3.0 image: ghcr.io/charlesthomas/bitwarden-cli:2026.7.0
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
# Override the baked entrypoint so --disable-origin-protection is # Override the baked entrypoint so --disable-origin-protection is
# actually passed (it was commented out in the image's entrypoint.sh, # actually passed (it was commented out in the image's entrypoint.sh,
-1
View File
@@ -99,7 +99,6 @@ metadata:
name: code-config name: code-config
namespace: infra namespace: infra
spec: spec:
ingressClassName: nginx
rules: rules:
- host: code-config.haven - host: code-config.haven
http: http:
+26
View File
@@ -0,0 +1,26 @@
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
@@ -0,0 +1,11 @@
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
-1
View File
@@ -115,7 +115,6 @@ metadata:
nginx.ingress.kubernetes.io/enable-cors: "true" nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-origin: "*" nginx.ingress.kubernetes.io/cors-allow-origin: "*"
spec: spec:
ingressClassName: nginx
rules: rules:
- host: file-nginx.haven - host: file-nginx.haven
http: http:
-1
View File
@@ -72,7 +72,6 @@ metadata:
name: haven-notify name: haven-notify
namespace: infra namespace: infra
spec: spec:
ingressClassName: nginx
rules: rules:
- host: notify.haven - host: notify.haven
http: http:
-33
View File
@@ -1,33 +0,0 @@
apiVersion: helm.cattle.io/v1
kind: HelmChart
metadata:
name: ingress-nginx
namespace: kube-system
spec:
repo: https://kubernetes.github.io/ingress-nginx
chart: ingress-nginx
version: 4.x.x
targetNamespace: ingress-nginx
valuesContent: |-
controller:
replicaCount: 2
ingressClassResource:
name: nginx
enabled: true
default: true
controllerValue: "k8s.io/ingress-nginx"
ingressClass: nginx
service:
type: LoadBalancer
externalTrafficPolicy: Local
annotations:
metallb.io/ip-allocated-from-pool: default-pool
metallb.io/loadBalancerIPs: "192.168.20.204"
loadBalancerIP: 192.168.20.204
resources:
requests:
cpu: 100m
memory: 90Mi
limits:
cpu: 1000m
memory: 256Mi
+32
View File
@@ -0,0 +1,32 @@
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
-1
View File
@@ -113,7 +113,6 @@ metadata:
name: wg-easy-ingress name: wg-easy-ingress
namespace: infra namespace: infra
spec: spec:
ingressClassName: nginx
rules: rules:
- host: vpn.haven - host: vpn.haven
http: http:
+10
View File
@@ -0,0 +1,10 @@
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
-2
View File
@@ -94,7 +94,6 @@ metadata:
namespace: monitoring namespace: monitoring
name: grafana name: grafana
spec: spec:
ingressClassName: nginx
rules: rules:
- host: grafana.haven - host: grafana.haven
http: http:
@@ -113,7 +112,6 @@ metadata:
namespace: monitoring namespace: monitoring
name: grafana-public name: grafana-public
spec: spec:
ingressClassName: nginx
rules: rules:
- host: grafanah.ivanch.me - host: grafanah.ivanch.me
http: http:
@@ -0,0 +1,23 @@
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
-1
View File
@@ -4,7 +4,6 @@ metadata:
name: argocd-server name: argocd-server
namespace: argocd namespace: argocd
spec: spec:
ingressClassName: nginx
rules: rules:
- host: argocd.haven - host: argocd.haven
http: http:
@@ -9,3 +9,4 @@ resources:
patches: patches:
- path: server-insecure-patch.yaml - path: server-insecure-patch.yaml
- path: argocd-api-user.yaml
-7
View File
@@ -70,13 +70,6 @@ kind: Namespace
metadata: metadata:
name: metallb-system name: metallb-system
--- ---
apiVersion: v1
kind: Namespace
metadata:
name: nfs-provisioner
labels:
name: nfs-provisioner
---
# ============================================================================== # ==============================================================================
# Observability & Monitoring # Observability & Monitoring
# ============================================================================== # ==============================================================================
+14
View File
@@ -0,0 +1,14 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"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
@@ -0,0 +1,24 @@
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 } }
+30
View File
@@ -0,0 +1,30 @@
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 }}"
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 } }
+36
View File
@@ -0,0 +1,36 @@
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 }}"
REDIS_PASSWORD: "{{ .REDIS_PASSWORD }}"
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 } }
- secretKey: REDIS_PASSWORD
remoteRef:
{ key: 8c25cac9-e9e8-4970-bdf4-31f9aee19276, property: REDIS_PASSWORD }
sourceRef:
{ storeRef: { name: bitwarden-fields, kind: ClusterSecretStore } }
+21
View File
@@ -0,0 +1,21 @@
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
@@ -0,0 +1,21 @@
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
@@ -0,0 +1,18 @@
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
@@ -0,0 +1,27 @@
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
@@ -0,0 +1,48 @@
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
@@ -0,0 +1,27 @@
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
@@ -0,0 +1,30 @@
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 } }
-17
View File
@@ -1,17 +0,0 @@
#!/bin/bash
# Dry-run validate every app manifest in apps/default/ against live cluster
export KUBECONFIG="C:\\Users\\ivanch\\.kube\\config"
cd "C:/Users/ivanch/Desktop/gitops-draft" || exit 1
fail=0
for f in apps/default/*.yaml; do
out=$(kubectl.exe apply --dry-run=server -f "$f" 2>&1)
if echo "$out" | grep -qi "error"; then
echo "FAIL: $f"
echo "$out" | grep -i error | head -2
fail=1
else
echo "OK: $f"
fi
done
[ $fail -eq 0 ] && echo "ALL apps/default dry-runs clean"
exit $fail