├── .config.env ├── .envrc ├── .github └── lint │ ├── .markdownlint.yaml │ ├── .prettierrc.yaml │ └── .yamllint.yaml ├── .gitignore ├── .pre-commit-config.yaml ├── .prettierignore ├── .sops.yaml ├── .taskfiles ├── cluster.yaml ├── format.yaml ├── lint.yaml ├── pre-commit.yaml └── terraform.yaml ├── .vscode ├── extensions.json └── settings.json ├── README.md ├── Taskfile.yml ├── cluster ├── apps │ ├── apps.yaml │ ├── calibre-web │ │ ├── Chart.yaml │ │ └── values.yaml │ ├── calibre │ │ ├── Chart.yaml │ │ ├── templates │ │ │ └── volumes.yaml │ │ └── values.yaml │ ├── cert-manager │ │ ├── Chart.yaml │ │ ├── config.json │ │ ├── templates │ │ │ ├── issuer-prod.yaml │ │ │ └── issuer-staging.yaml │ │ └── values.yaml │ ├── cyberchef │ │ ├── deployment.yaml │ │ ├── ingress.yaml │ │ ├── kustomization.yaml │ │ └── service.yaml │ ├── ddns │ │ ├── cronjob.yaml │ │ ├── kustomization.yaml │ │ ├── secrets.yaml │ │ └── service-account.yaml │ ├── falco │ │ ├── Chart.yaml │ │ └── values.yaml │ ├── hajimari │ │ ├── Chart.yaml │ │ └── values.yaml │ ├── headscale │ │ └── deployment.yaml │ ├── ibkr-bot │ │ ├── configmap.yaml │ │ ├── deployment.yaml │ │ ├── jobs.yaml │ │ ├── kustomization.yaml │ │ ├── network-policy.yaml │ │ ├── secrets.yaml │ │ ├── service-account.yaml │ │ ├── service.yaml │ │ └── volumes.yaml │ ├── icloudpd-om │ │ ├── configmap.yaml │ │ ├── deployment.yaml │ │ ├── kustomization.yaml │ │ ├── secrets.yaml │ │ └── volumes.yaml │ ├── ingress-nginx │ │ ├── Chart.yaml │ │ ├── templates │ │ │ └── volumes.yaml │ │ └── values.yaml │ ├── it-tools │ │ ├── deployment.yaml │ │ ├── ingress.yaml │ │ ├── kustomization.yaml │ │ ├── network-policy.yaml │ │ ├── service.yaml │ │ └── serviceaccount.yaml │ ├── kanboard │ │ ├── deployment.yaml │ │ ├── ingress.yaml │ │ ├── kustomization.yaml │ │ ├── service.yaml │ │ └── volumes.yaml │ ├── karakeep │ │ ├── chrome-deployment.yaml │ │ ├── chrome-service.yaml │ │ ├── configmap.yaml │ │ ├── data-pv.yaml │ │ ├── data-pvc.yaml │ │ ├── external-secrets.yaml │ │ ├── ingress.yaml │ │ ├── kustomization.yaml │ │ ├── meilisearch-deployment.yaml │ │ ├── meilisearch-pv.yaml │ │ ├── meilisearch-pvc.yaml │ │ ├── meilisearch-service.yaml │ │ ├── web-deployment.yaml │ │ └── web-service.yaml │ ├── kolmafia │ │ ├── deployment.yaml │ │ ├── ingress.yaml │ │ ├── kustomization.yaml │ │ ├── pv.yaml │ │ ├── pvc.yaml │ │ └── service.yaml │ ├── main │ │ ├── Chart.yaml │ │ ├── templates │ │ │ ├── calibre-web.yaml │ │ │ ├── calibre.yaml │ │ │ ├── cert-manager.yaml │ │ │ ├── cyberchef.yaml │ │ │ ├── ddns.yaml │ │ │ ├── hajimari.yaml │ │ │ ├── ingress-nginx.yaml │ │ │ ├── it-tools.yaml │ │ │ ├── kanboard.yaml │ │ │ ├── karakeep.yaml │ │ │ ├── kolmafia.yaml │ │ │ ├── mariadb.yaml │ │ │ ├── mealie.yaml │ │ │ ├── metrics-prometheus.yaml │ │ │ ├── metrics-server.yaml │ │ │ ├── n8n.yaml │ │ │ ├── nginx.yaml │ │ │ ├── nocodb.yaml │ │ │ ├── oauth2-proxy.yaml │ │ │ ├── open-webui.yaml │ │ │ ├── paperless.yaml │ │ │ ├── pgbackup.yaml │ │ │ ├── plex.yaml │ │ │ ├── postgres.yaml │ │ │ ├── redis.yaml │ │ │ ├── romm.yaml │ │ │ └── whoami.yaml │ │ └── values.yaml │ ├── mariadb │ │ ├── Chart.yaml │ │ ├── templates │ │ │ ├── secret.yaml │ │ │ └── volumes.yaml │ │ └── values.yaml │ ├── mealie │ │ ├── configmap.yaml │ │ ├── deployment.yaml │ │ ├── ingress.yaml │ │ ├── kustomization.yaml │ │ ├── service.yaml │ │ └── volumes.yaml │ ├── metrics-prometheus │ │ ├── Chart.yaml │ │ ├── templates │ │ │ └── volumes.yaml │ │ └── values.yaml │ ├── metrics-server │ │ ├── Chart.yaml │ │ └── values.yaml │ ├── mlflow │ │ ├── Chart.yaml │ │ └── values.yaml │ ├── mongodb │ │ ├── Chart.yaml │ │ ├── templates │ │ │ ├── external-secret.yaml │ │ │ └── volumes.yaml │ │ └── values.yaml │ ├── n8n │ │ ├── Chart.yaml │ │ ├── templates │ │ │ ├── pv.yaml │ │ │ └── pvc.yaml │ │ └── values.yaml │ ├── nginx │ │ ├── deployments.yaml │ │ ├── ingress.yaml │ │ ├── kustomization.yaml │ │ ├── services.yaml │ │ └── volumes.yaml │ ├── nocodb │ │ ├── configmap.yaml │ │ ├── deployment.yaml │ │ ├── ingress.yaml │ │ ├── kustomization.yaml │ │ ├── service.yaml │ │ └── volumes.yaml │ ├── oauth2-proxy │ │ ├── config.json │ │ ├── deployment.yaml │ │ ├── external-secret.yaml │ │ ├── ingress.yaml │ │ ├── kustomization.yaml │ │ ├── pdb.yaml │ │ └── service.yaml │ ├── omniboard │ │ ├── deployment.yaml │ │ ├── ingress.yaml │ │ ├── kustomization.yaml │ │ └── service.yaml │ ├── open-webui │ │ ├── Chart.yaml │ │ ├── templates │ │ │ ├── pv.yaml │ │ │ └── pvc.yaml │ │ └── values.yaml │ ├── paperless │ │ ├── Chart.yaml │ │ ├── templates │ │ │ ├── secret.yaml │ │ │ └── volumes.yaml │ │ └── values.yaml │ ├── pgbackup │ │ ├── configmap.yaml │ │ ├── deployment.yaml │ │ ├── kustomization.yaml │ │ ├── network-policy.yaml │ │ ├── secrets.yaml │ │ ├── service-account.yaml │ │ └── volumes.yaml │ ├── plex │ │ ├── Chart.yaml │ │ ├── templates │ │ │ └── volumes.yaml │ │ └── values.yaml │ ├── postgres │ │ ├── Chart.yaml │ │ ├── templates │ │ │ ├── external-secret.yaml │ │ │ └── volumes.yaml │ │ └── values.yaml │ ├── qbittorrent │ │ ├── configmap.yaml │ │ ├── deployment.yaml │ │ ├── ingress.yaml │ │ ├── kustomization.yaml │ │ ├── service.yaml │ │ └── volumes.yaml │ ├── redis │ │ ├── Chart.yaml │ │ └── values.yaml │ ├── romm │ │ ├── configmap.yaml │ │ ├── deployment.yaml │ │ ├── ingress.yaml │ │ ├── kustomization.yaml │ │ ├── network-policy.yaml │ │ ├── pv.yaml │ │ ├── pvc.yaml │ │ ├── secrets.yaml │ │ ├── service.yaml │ │ └── serviceaccount.yaml │ ├── sailboats │ │ ├── deployment.yaml │ │ └── kustomization.yaml │ ├── secret-generator │ │ ├── Chart.yaml │ │ ├── config.json │ │ └── values.yaml │ ├── tailscale │ │ ├── Chart.yaml │ │ ├── templates │ │ │ └── external-secret.yaml │ │ └── values.yaml │ └── whoami │ │ ├── deployments.yaml │ │ ├── ingress.yaml │ │ ├── kustomization.yaml │ │ ├── network-policy.yaml │ │ ├── service-account.yaml │ │ └── services.yaml └── init │ ├── argocd-apps │ ├── Chart.yaml │ └── values.yaml │ ├── argocd │ ├── Chart.yaml │ └── values.yaml │ ├── external-secrets │ ├── Chart.yaml │ └── values.yaml │ ├── init.yaml │ ├── main │ ├── Chart.yaml │ ├── templates │ │ ├── argocd-apps.yaml │ │ ├── argocd.yaml │ │ ├── external-secrets.yaml │ │ ├── secrets-store.yaml │ │ ├── vault.yaml │ │ └── zfs-storage.yaml │ └── values.yaml │ ├── secrets-store │ ├── kustomization.yaml │ ├── rbac.yaml │ └── secret-store.yaml │ ├── vault │ ├── Chart.yaml │ └── values.yaml │ └── zfs-storage │ └── storage-class.yaml ├── configure.sh ├── flake.lock ├── flake.nix ├── infra ├── cloudflare │ ├── main.tf │ └── secret.sops.yaml ├── k3s-nodes │ ├── inventory.yaml │ ├── roles │ │ └── k3s_worker │ │ │ └── tasks │ │ │ ├── common.yaml │ │ │ ├── k3s.yaml │ │ │ └── main.yaml │ └── site.yaml └── vault-gcp-kms │ ├── main.tf │ ├── terraform.tfvars │ ├── variables.tf │ └── versions.tf ├── tmpl ├── .sops.yaml ├── argo │ └── values.yaml ├── cluster │ ├── cert-manager-secret.tmpl.yaml │ ├── cluster-settings.tmpl.yaml │ ├── vault-token-secret.tmpl.yaml │ └── wireguard.secrets.tmpl.yaml └── terraform │ └── secret.sops.yaml ├── topology.conf ├── topology.mmd └── topology.svg /.envrc: -------------------------------------------------------------------------------- 1 | use flake 2 | 3 | #shellcheck disable=SC2148,SC2155 4 | export GIT_REPOSITORY=https://github.com/omdv/homelab-server.git 5 | export HOMELAB_DOMAIN=kblb.io 6 | 7 | # k3s node variables 8 | export K3S_TOKEN="$(gopass show homelab/k3s-token)" 9 | export K3S_TAILSCALE_AUTH="$(gopass show homelab/k3s-tailscale-auth)" 10 | -------------------------------------------------------------------------------- /.github/lint/.markdownlint.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | default: true 3 | 4 | # MD013/line-length - Line length 5 | MD013: 6 | # Number of characters 7 | line_length: 240 8 | # Number of characters for headings 9 | heading_line_length: 80 10 | # Number of characters for code blocks 11 | code_block_line_length: 80 12 | # Include code blocks 13 | code_blocks: true 14 | # Include tables 15 | tables: true 16 | # Include headings 17 | headings: true 18 | # Include headings 19 | headers: true 20 | # Strict length checking 21 | strict: false 22 | # Stern length checking 23 | stern: false 24 | -------------------------------------------------------------------------------- /.github/lint/.prettierrc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | trailingComma: "es5" 3 | tabWidth: 2 4 | semi: false 5 | singleQuote: false 6 | -------------------------------------------------------------------------------- /.github/lint/.yamllint.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | ignore: | 3 | *.sops.* 4 | gotk-components.yaml 5 | ./cluster/apps/main/templates/*.yaml 6 | extends: default 7 | rules: 8 | indentation: 9 | spaces: 2 10 | indent-sequences: true 11 | check-multi-line-strings: false 12 | truthy: 13 | allowed-values: ["true", "false", "on"] 14 | comments: 15 | min-spaces-from-content: 1 16 | line-length: disable 17 | braces: 18 | min-spaces-inside: 0 19 | max-spaces-inside: 1 20 | brackets: 21 | min-spaces-inside: 0 22 | max-spaces-inside: 0 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Trash 2 | .DS_Store 3 | Thumbs.db 4 | 5 | # Binaries 6 | *.iso 7 | 8 | # vscode-sops 9 | .decrypted~*.yaml 10 | *.agekey 11 | 12 | # Temp folders 13 | .temp* 14 | .private/ 15 | .logs/ 16 | .task/ 17 | 18 | # Ansible 19 | xanmanning.k3s* 20 | 21 | # Terraform 22 | .terraform 23 | .terraform.lock.hcl 24 | .terraform.tfstate* 25 | terraform.tfstate* 26 | 27 | # Sops 28 | .decrypted~* 29 | *.agekey 30 | 31 | # Kubernetes 32 | kubeconfig 33 | talosconfig 34 | 35 | # Wireguard config 36 | .wireguard/* 37 | 38 | # Secrets created during bootstrap 39 | .bootstrap-secrets/* 40 | 41 | # Charts folders 42 | charts/ 43 | Chart.lock 44 | 45 | # Debug 46 | debug/data/* 47 | debug/ 48 | 49 | # direnv 50 | .direnv 51 | 52 | # pre-commit 53 | .pre-commit-config.yaml 54 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fail_fast: false 3 | repos: 4 | - repo: https://github.com/adrienverge/yamllint 5 | rev: v1.27.1 6 | hooks: 7 | - args: 8 | - --config-file 9 | - .github/lint/.yamllint.yaml 10 | id: yamllint 11 | - repo: https://github.com/pre-commit/pre-commit-hooks 12 | rev: v4.3.0 13 | hooks: 14 | - id: trailing-whitespace 15 | - id: end-of-file-fixer 16 | - id: mixed-line-ending 17 | - id: check-merge-conflict 18 | - id: check-yaml 19 | exclude: | 20 | (?x)^( 21 | cluster/apps/main/templates/.*\.yaml 22 | )$ 23 | - id: check-added-large-files 24 | - id: check-case-conflict 25 | - id: check-json 26 | - id: debug-statements 27 | - id: requirements-txt-fixer 28 | - repo: https://github.com/sirosen/fix-smartquotes 29 | rev: 0.2.0 30 | hooks: 31 | - id: fix-smartquotes 32 | - repo: https://github.com/k8s-at-home/sops-pre-commit 33 | rev: v2.1.1 34 | hooks: 35 | - id: forbid-secrets 36 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .prettierignore 2 | -------------------------------------------------------------------------------- /.sops.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | creation_rules: 3 | - path_regex: provision/.*\.sops\.ya?ml 4 | unencrypted_regex: "^(kind)$" 5 | age: >- 6 | age1k30whteuhd93qd9sgcrnj2cur0dz5dgtj7vyhsc2hjeph0u3p97s70v7lg 7 | - path_regex: cluster/.*\.ya?ml 8 | encrypted_regex: "^(data|stringData)$" 9 | age: >- 10 | age1k30whteuhd93qd9sgcrnj2cur0dz5dgtj7vyhsc2hjeph0u3p97s70v7lg 11 | -------------------------------------------------------------------------------- /.taskfiles/format.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | version: "3" 3 | 4 | tasks: 5 | all: 6 | - task: markdown 7 | - task: yaml 8 | markdown: 9 | desc: Format Markdown 10 | cmds: 11 | - >- 12 | prettier 13 | --ignore-path '.github/lint/.prettierignore' 14 | --config '.github/lint/.prettierrc.yaml' 15 | --list-different 16 | --ignore-unknown 17 | --parser=markdown 18 | --write '*.md' '**/*.md' 19 | ignore_error: true 20 | yaml: 21 | desc: Format YAML 22 | cmds: 23 | - >- 24 | prettier 25 | --ignore-path '.github/lint/.prettierignore' 26 | --config 27 | '.github/lint/.prettierrc.yaml' 28 | --list-different 29 | --ignore-unknown 30 | --parser=yaml 31 | --write '*.y*ml' 32 | '**/*.y*ml' 33 | ignore_error: true 34 | -------------------------------------------------------------------------------- /.taskfiles/lint.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | version: "3" 3 | 4 | tasks: 5 | all: 6 | - task: markdown 7 | - task: yaml 8 | - task: format 9 | 10 | markdown: 11 | desc: Lint Markdown 12 | cmds: 13 | - markdownlint -c '.github/lint/.markdownlint.yaml' *.md 14 | ignore_errors: true 15 | 16 | yaml: 17 | desc: Lint YAML 18 | cmds: 19 | - yamllint -c '.github/lint/.yamllint.yaml' . 20 | ignore_errors: true 21 | 22 | format: 23 | desc: Lint general formatting 24 | cmds: 25 | - prettier --ignore-path '.github/lint/.prettierignore' --config '.github/lint/.prettierrc.yaml' --check . 26 | ignore_errors: true 27 | -------------------------------------------------------------------------------- /.taskfiles/pre-commit.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | version: "3" 3 | 4 | tasks: 5 | init: 6 | desc: Initialize pre-commit hooks 7 | cmds: 8 | - pre-commit install-hooks 9 | run: 10 | desc: Run pre-commit 11 | cmds: 12 | - pre-commit run --all-files 13 | -------------------------------------------------------------------------------- /.taskfiles/terraform.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | version: "3" 3 | 4 | tasks: 5 | init:cloudflare: 6 | desc: Initialize terraform 7 | dir: provision/terraform/cloudflare 8 | cmds: 9 | - "terraform init" 10 | 11 | plan:cloudflare: 12 | desc: Prepare all the k8s nodes for running k3s 13 | dir: provision/terraform/cloudflare 14 | cmds: 15 | - "terraform plan" 16 | 17 | apply:cloudflare: 18 | desc: Prepare all the k8s nodes for running k3s 19 | dir: provision/terraform/cloudflare 20 | cmds: 21 | - "terraform apply" 22 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "CoenraadS.bracket-pair-colorizer-2", 4 | "HashiCorp.terraform", 5 | "britesnow.vscode-toggle-quotes", 6 | "mitchdenny.ecdc", 7 | "ms-kubernetes-tools.vscode-kubernetes-tools", 8 | "oderwat.indent-rainbow", 9 | "redhat.ansible", 10 | "signageos.signageos-vscode-sops", 11 | "usernamehw.errorlens" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ansible.ansibleLint.arguments": "-c .github/lint/.ansible-lint", 3 | "discord.enabled": true, 4 | "files.associations": { 5 | "*.json5": "jsonc", 6 | "**/ansible/**/*.yml": "ansible", 7 | "**/ansible/**/*.sops.yml": "yaml", 8 | "**/ansible/**/inventory/**/*.yml": "yaml", 9 | "**/terraform/**/*.tf": "terraform" 10 | }, 11 | "material-icon-theme.folders.associations": { 12 | ".taskfiles": "utils", 13 | "hack": "scripts" 14 | }, 15 | "prettier.configPath": ".github/lint/.prettierrc.yaml", 16 | "prettier.ignorePath": ".github/lint/.prettierignore", 17 | "yaml.schemas": { 18 | "Kubernetes": "cluster/*.yaml" 19 | }, 20 | "ansible.python.interpreterPath": "/bin/python" 21 | } 22 | -------------------------------------------------------------------------------- /Taskfile.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: "3" 3 | 4 | tasks: 5 | greet: 6 | cmds: 7 | - echo $GREETING 8 | env: 9 | GREETING: Hey, there! 10 | 11 | vars: 12 | PROJECT_DIR: 13 | sh: "git rev-parse --show-toplevel" 14 | CLUSTER_DIR: "{{.PROJECT_DIR}}/cluster" 15 | SECRETS_DIR: "{{.PROJECT_DIR}}/.bootstrap-secrets" 16 | TERRAFORM_DIR: "{{.PROJECT_DIR}}/provision/terraform" 17 | KUBECONFIG: "{{.PROJECT_DIR}}/provision/kubeconfig" 18 | 19 | env: 20 | BOOTSTRAP_ARGOCD_PASSWORD: "{{ .HOMELAB_ARGO_PASSWORD }}" 21 | 22 | includes: 23 | pre-commit: .taskfiles/pre-commit.yaml 24 | lint: .taskfiles/lint.yaml 25 | terraform: .taskfiles/terraform.yaml 26 | cluster: .taskfiles/cluster.yaml 27 | -------------------------------------------------------------------------------- /cluster/apps/apps.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: root-apps 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | spec: 10 | destination: 11 | namespace: argocd 12 | name: in-cluster 13 | project: default 14 | source: 15 | path: cluster/apps/main 16 | repoURL: https://github.com/omdv/homelab-server 17 | targetRevision: HEAD 18 | syncPolicy: 19 | automated: 20 | prune: true 21 | selfHeal: true 22 | -------------------------------------------------------------------------------- /cluster/apps/calibre-web/Chart.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v2 3 | name: helm-calibre-web 4 | type: application 5 | version: 0.2.0 6 | appVersion: "1.0" 7 | dependencies: 8 | - name: calibre-web 9 | version: 8.2.0 10 | repository: https://k8s-at-home.com/charts/ 11 | -------------------------------------------------------------------------------- /cluster/apps/calibre-web/values.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # This chart inherits from our common library chart. You can check the default values/options here: 3 | # https://github.com/k8s-at-home/library-charts/tree/main/charts/stable/common/values.yaml 4 | calibre-web: 5 | image: 6 | repository: linuxserver/calibre-web 7 | pullPolicy: IfNotPresent 8 | tag: version-0.6.12 9 | env: 10 | TZ: "America/Chicago" 11 | PUID: "1000" 12 | PGID: "1000" 13 | service: 14 | main: 15 | ports: 16 | http: 17 | port: 8083 18 | ingress: 19 | main: 20 | enabled: true 21 | ingressClassName: nginx 22 | hosts: 23 | - host: books.kblb.io 24 | paths: 25 | - path: / 26 | pathType: Prefix 27 | annotations: 28 | cert-manager.io/cluster-issuer: "letsencrypt-prod" 29 | nginx.ingress.kubernetes.io/auth-url: "https://auth.kblb.io/oauth2/auth" 30 | nginx.ingress.kubernetes.io/auth-signin: "https://auth.kblb.io/oauth2/start?rd=https://$host$uri" 31 | hajimari.io/enable: "true" 32 | hajimari.io/icon: "book-open-page-variant" 33 | tls: 34 | - hosts: 35 | - books.kblb.io 36 | secretName: my-certs-books 37 | persistence: 38 | config: 39 | enabled: true 40 | existingClaim: pvc-calibre 41 | resources: 42 | requests: 43 | memory: 16Mi 44 | cpu: 100m 45 | limits: 46 | memory: 256Mi 47 | cpu: 500m 48 | -------------------------------------------------------------------------------- /cluster/apps/calibre/Chart.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v2 3 | name: helm-calibre 4 | type: application 5 | version: 0.2.0 6 | appVersion: "1.0" 7 | dependencies: 8 | - name: calibre 9 | version: 5.2.0 10 | repository: https://k8s-at-home.com/charts/ 11 | -------------------------------------------------------------------------------- /cluster/apps/calibre/templates/volumes.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: PersistentVolume 4 | metadata: 5 | name: pv-calibre 6 | labels: 7 | app: calibre 8 | spec: 9 | nodeAffinity: 10 | required: 11 | nodeSelectorTerms: 12 | - matchExpressions: 13 | - key: node-role.kubernetes.io/control-plane 14 | operator: Exists 15 | capacity: 16 | storage: 1Ti 17 | storageClassName: local-path 18 | accessModes: 19 | - ReadWriteOnce 20 | hostPath: 21 | path: /pool/media/books 22 | 23 | --- 24 | apiVersion: v1 25 | kind: PersistentVolumeClaim 26 | metadata: 27 | name: pvc-calibre 28 | labels: 29 | app: calibre 30 | spec: 31 | storageClassName: local-path 32 | accessModes: 33 | - ReadWriteOnce 34 | resources: 35 | requests: 36 | storage: 100Gi 37 | volumeName: pv-calibre 38 | -------------------------------------------------------------------------------- /cluster/apps/calibre/values.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | calibre: 3 | image: 4 | repository: linuxserver/calibre 5 | tag: version-v5.21.0 6 | pullPolicy: IfNotPresent 7 | env: 8 | TZ: "America/Chicago" 9 | PUID: "1000" 10 | PGID: "1000" 11 | service: 12 | main: 13 | ports: 14 | http: 15 | port: 8080 16 | webserver: 17 | enabled: false 18 | type: ClusterIP 19 | ports: 20 | webserver: 21 | enabled: true 22 | port: 8081 23 | protocol: TCP 24 | targetPort: 8081 25 | ingress: 26 | main: 27 | enabled: true 28 | ingressClassName: nginx 29 | hosts: 30 | - host: calibre.kblb.io 31 | paths: 32 | - path: / 33 | pathType: Prefix 34 | annotations: 35 | cert-manager.io/cluster-issuer: "letsencrypt-prod" 36 | nginx.ingress.kubernetes.io/auth-url: "https://auth.kblb.io/oauth2/auth" 37 | nginx.ingress.kubernetes.io/auth-signin: "https://auth.kblb.io/oauth2/start?rd=https://$host$uri" 38 | hajimari.io/enable: "true" 39 | hajimari.io/icon: "book-edit" 40 | tls: 41 | - hosts: 42 | - calibre.kblb.io 43 | secretName: my-certs-calibre 44 | persistence: 45 | config: 46 | enabled: true 47 | existingClaim: pvc-calibre 48 | resources: 49 | requests: 50 | memory: 16Mi 51 | cpu: "0.01" 52 | limits: 53 | memory: 256Mi 54 | -------------------------------------------------------------------------------- /cluster/apps/cert-manager/Chart.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v2 3 | name: my-cert-manager-chart 4 | type: application 5 | version: 0.1.0 6 | appVersion: "1.0" 7 | dependencies: 8 | - name: cert-manager 9 | version: 1.6.1 10 | repository: https://charts.jetstack.io 11 | -------------------------------------------------------------------------------- /cluster/apps/cert-manager/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": { 3 | "name": "cert-manager", 4 | "path": "cluster/base/cert-manager", 5 | "namespace": "cert-manager" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /cluster/apps/cert-manager/templates/issuer-prod.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: cert-manager.io/v1 3 | kind: ClusterIssuer 4 | metadata: 5 | name: letsencrypt-prod 6 | spec: 7 | acme: 8 | server: https://acme-v02.api.letsencrypt.org/directory 9 | email: omdv.public@gmail.com 10 | privateKeySecretRef: 11 | name: letsencrypt-prod 12 | solvers: 13 | - http01: 14 | ingress: 15 | class: nginx 16 | -------------------------------------------------------------------------------- /cluster/apps/cert-manager/templates/issuer-staging.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: cert-manager.io/v1 3 | kind: ClusterIssuer 4 | metadata: 5 | name: letsencrypt-staging 6 | spec: 7 | acme: 8 | server: https://acme-staging-v02.api.letsencrypt.org/directory 9 | email: omdv.public@gmail.com 10 | privateKeySecretRef: 11 | name: letsencrypt-staging 12 | solvers: 13 | - http01: 14 | ingress: 15 | class: nginx 16 | -------------------------------------------------------------------------------- /cluster/apps/cert-manager/values.yaml: -------------------------------------------------------------------------------- 1 | cert-manager: 2 | installCRDs: true 3 | replicaCount: 1 4 | resources: 5 | requests: 6 | cpu: 10m 7 | memory: 32Mi 8 | securityContext: 9 | runAsNonRoot: true 10 | prometheus: 11 | enabled: true 12 | servicemonitor: 13 | enabled: false 14 | prometheusInstance: default 15 | targetPort: 9402 16 | path: /metrics 17 | interval: 60s 18 | scrapeTimeout: 30s 19 | labels: {} 20 | -------------------------------------------------------------------------------- /cluster/apps/cyberchef/deployment.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: Deployment 3 | apiVersion: apps/v1 4 | metadata: 5 | name: cyberchef 6 | labels: 7 | app: cyberchef 8 | 9 | spec: 10 | replicas: 1 11 | selector: 12 | matchLabels: 13 | app: cyberchef 14 | template: 15 | metadata: 16 | labels: 17 | app: cyberchef 18 | spec: 19 | containers: 20 | - name: cyberchef 21 | image: mpepping/cyberchef:latest 22 | ports: 23 | - name: pod-http-port 24 | protocol: TCP 25 | containerPort: 8000 26 | resources: 27 | requests: 28 | cpu: "200m" 29 | memory: "200Mi" 30 | limits: 31 | cpu: "1000m" 32 | memory: "800Mi" 33 | -------------------------------------------------------------------------------- /cluster/apps/cyberchef/ingress.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: networking.k8s.io/v1 3 | kind: Ingress 4 | metadata: 5 | name: cyberchef 6 | labels: 7 | app: cyberchef 8 | annotations: 9 | cert-manager.io/cluster-issuer: "letsencrypt-prod" 10 | nginx.ingress.kubernetes.io/auth-url: "https://auth.kblb.io/oauth2/auth" 11 | nginx.ingress.kubernetes.io/auth-signin: "https://auth.kblb.io/oauth2/start?rd=https://$host$uri" 12 | hajimari.io/enable: "true" 13 | hajimari.io/icon: "tools" 14 | 15 | spec: 16 | ingressClassName: nginx 17 | tls: 18 | - hosts: 19 | - cc.kblb.io 20 | secretName: my-certs-cyberchef 21 | rules: 22 | - host: cc.kblb.io 23 | http: 24 | paths: 25 | - path: / 26 | pathType: Prefix 27 | backend: 28 | service: 29 | name: cyberchef 30 | port: 31 | name: http 32 | -------------------------------------------------------------------------------- /cluster/apps/cyberchef/kustomization.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | resources: 3 | - service.yaml 4 | - deployment.yaml 5 | - ingress.yaml 6 | -------------------------------------------------------------------------------- /cluster/apps/cyberchef/service.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: cyberchef 6 | annotations: 7 | tailscale.com/expose: "true" 8 | labels: 9 | app: cyberchef 10 | 11 | spec: 12 | ports: 13 | - name: http 14 | protocol: TCP 15 | port: 80 16 | targetPort: pod-http-port 17 | selector: 18 | app: cyberchef 19 | -------------------------------------------------------------------------------- /cluster/apps/ddns/cronjob.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: batch/v1 3 | kind: CronJob 4 | metadata: 5 | name: ddns 6 | labels: 7 | app: ddns 8 | 9 | spec: 10 | schedule: "*/15 * * * *" 11 | startingDeadlineSeconds: 200 12 | jobTemplate: 13 | spec: 14 | template: 15 | spec: 16 | affinity: 17 | nodeAffinity: 18 | requiredDuringSchedulingIgnoredDuringExecution: 19 | nodeSelectorTerms: 20 | - matchExpressions: 21 | - key: node-role.kubernetes.io/control-plane 22 | operator: Exists 23 | containers: 24 | - name: cloudflare 25 | serviceAccountName: ddns-service-account 26 | image: omdv/cloudflare-ddns:202207262350133633d8 27 | resources: 28 | limits: 29 | cpu: "100m" 30 | memory: "64Mi" 31 | requests: 32 | cpu: "50m" 33 | memory: "32Mi" 34 | env: 35 | - name: API_TOKEN 36 | valueFrom: 37 | secretKeyRef: 38 | name: ddns-secret 39 | key: CLOUDFLARE_API_TOKEN 40 | - name: DOMAIN 41 | valueFrom: 42 | secretKeyRef: 43 | name: ddns-secret 44 | key: CLOUDFLARE_DOMAIN 45 | restartPolicy: Never 46 | -------------------------------------------------------------------------------- /cluster/apps/ddns/kustomization.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | resources: 3 | - secrets.yaml 4 | - cronjob.yaml 5 | - service-account.yaml 6 | -------------------------------------------------------------------------------- /cluster/apps/ddns/secrets.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: external-secrets.io/v1beta1 3 | kind: ExternalSecret 4 | metadata: 5 | name: ddns-external-secret 6 | 7 | spec: 8 | refreshInterval: "15s" 9 | secretStoreRef: 10 | name: vault-backend 11 | kind: ClusterSecretStore 12 | target: 13 | name: ddns-secret 14 | data: 15 | - secretKey: CLOUDFLARE_API_TOKEN 16 | remoteRef: 17 | key: secret/cloudflare 18 | property: VAULT_CLOUDFLARE_API_TOKEN 19 | - secretKey: CLOUDFLARE_DOMAIN 20 | remoteRef: 21 | key: secret/cloudflare 22 | property: VAULT_CLOUDFLARE_DOMAIN 23 | -------------------------------------------------------------------------------- /cluster/apps/ddns/service-account.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: ddns-service-account 5 | labels: 6 | app: ddns 7 | -------------------------------------------------------------------------------- /cluster/apps/falco/Chart.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: my-falco-chart 3 | apiVersion: v2 4 | version: 1.0.0 5 | dependencies: 6 | - name: falco 7 | version: 2.2.0 8 | repository: https://falcosecurity.github.io/charts 9 | -------------------------------------------------------------------------------- /cluster/apps/falco/values.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | falco: 3 | driver: 4 | enabled: true 5 | kind: module 6 | falcosidekick: 7 | enabled: true 8 | collectors: 9 | enabled: false 10 | controller: 11 | kind: deployment 12 | services: 13 | - name: k8saudit-webhook 14 | type: NodePort 15 | ports: 16 | - port: 9765 17 | nodePort: 30007 18 | protocol: TCP 19 | falco: 20 | rules_file: 21 | - /etc/falco/falco_rules.yaml 22 | - /etc/falco/falco_rules.local.yaml 23 | - /etc/falco/rules.d 24 | -------------------------------------------------------------------------------- /cluster/apps/hajimari/Chart.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v2 3 | name: helm-hajimari 4 | type: application 5 | version: 0.2.0 6 | appVersion: "1.0" 7 | dependencies: 8 | - name: hajimari 9 | version: 1.2.0 10 | repository: https://hajimari.io 11 | -------------------------------------------------------------------------------- /cluster/apps/hajimari/values.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | hajimari: 3 | image: 4 | repository: ghcr.io/toboshii/hajimari 5 | pullPolicy: IfNotPresent 6 | tag: v0.2.0 7 | 8 | env: 9 | TZ: America/Chicago 10 | 11 | hajimari: 12 | defaultEnable: false # show all ingresses, regardless of annotation 13 | namespaceSelector: 14 | any: true 15 | name: "omdv" 16 | groups: 17 | - name: Local 18 | links: 19 | - name: Netdata 20 | url: "http://192.168.1.24:19999" 21 | - name: Portainer 22 | url: "http://192.168.1.24:8001" 23 | - name: Dev 24 | links: 25 | - name: Codepen 26 | url: "https://codepen.io/" 27 | - name: Devdocs 28 | url: "https://devdocs.io" 29 | - name: Devhints 30 | url: "https://devhints.io" 31 | 32 | service: 33 | main: 34 | ports: 35 | http: 36 | port: 3000 37 | 38 | serviceAccount: 39 | create: true 40 | 41 | ingress: 42 | main: 43 | enabled: true 44 | ingressClassName: nginx 45 | hosts: 46 | - host: hj.kblb.io 47 | paths: 48 | - path: / 49 | pathType: Prefix 50 | annotations: 51 | cert-manager.io/cluster-issuer: "letsencrypt-prod" 52 | nginx.ingress.kubernetes.io/auth-url: "https://auth.kblb.io/oauth2/auth" 53 | nginx.ingress.kubernetes.io/auth-signin: "https://auth.kblb.io/oauth2/start?rd=https://$host$uri" 54 | tls: 55 | - hosts: 56 | - hj.kblb.io 57 | secretName: my-certs-hajimari 58 | 59 | persistence: 60 | data: 61 | enabled: false 62 | 63 | resources: 64 | requests: 65 | cpu: 6m 66 | memory: 32Mi 67 | limits: 68 | cpu: 12m 69 | memory: 64Mi 70 | -------------------------------------------------------------------------------- /cluster/apps/ibkr-bot/configmap.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: ibkr-config 6 | data: 7 | TWOFA_TIMEOUT_ACTION: "restart" 8 | GATEWAY_OR_TWS: "gateway" 9 | IBC_TradingMode: "live" 10 | IBC_ReadOnlyApi: "no" 11 | IBC_ReloginAfterSecondFactorAuthenticationTimeout: "yes" 12 | IBC_AutoRestartTime: "08:35 AM" 13 | IBC_CommandServerPort: "7462" 14 | 15 | --- 16 | apiVersion: v1 17 | kind: ConfigMap 18 | metadata: 19 | name: ibkr-app-config 20 | data: 21 | IB_GATEWAY_HOST: "ibkr-gateway.ibkr.svc.cluster.local" 22 | IB_GATEWAY_PORT: "8888" 23 | STORAGE_PATH: "/data" 24 | TRADING_MOCKED: "false" 25 | TRADING_KELLY_RATIO: "0.22" 26 | TRADING_CLOSE_FLAG: "true" 27 | TRADING_CLOSE_TARGET_PROFIT_RATIO: "0.75" 28 | TRADING_CLOSE_CHECK_INTERVAL: "60" 29 | PREDICT_START_DATE: "2018-01-01" 30 | -------------------------------------------------------------------------------- /cluster/apps/ibkr-bot/deployment.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: ibkr-gateway 6 | spec: 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: ibkr-gateway 11 | template: 12 | metadata: 13 | labels: 14 | app: ibkr-gateway 15 | spec: 16 | affinity: 17 | nodeAffinity: 18 | requiredDuringSchedulingIgnoredDuringExecution: 19 | nodeSelectorTerms: 20 | - matchExpressions: 21 | - key: node-role.kubernetes.io/control-plane 22 | operator: Exists 23 | serviceAccountName: ibkr-gateway-service-account 24 | containers: 25 | - name: ibkr-gateway 26 | image: ghcr.io/extrange/ibkr:10.30 27 | ports: 28 | - name: novnc 29 | containerPort: 6080 30 | - name: api 31 | containerPort: 8888 32 | - name: command-server 33 | containerPort: 7462 34 | livenessProbe: 35 | tcpSocket: 36 | port: api 37 | initialDelaySeconds: 60 38 | periodSeconds: 15 39 | timeoutSeconds: 5 40 | readinessProbe: 41 | tcpSocket: 42 | port: api 43 | initialDelaySeconds: 30 44 | periodSeconds: 10 45 | timeoutSeconds: 3 46 | env: 47 | - name: USERNAME 48 | valueFrom: 49 | secretKeyRef: 50 | name: ibkr-gateway-secret 51 | key: username 52 | - name: PASSWORD 53 | valueFrom: 54 | secretKeyRef: 55 | name: ibkr-gateway-secret 56 | key: password 57 | envFrom: 58 | - configMapRef: 59 | name: ibkr-config 60 | resources: 61 | requests: 62 | cpu: 500m 63 | memory: 1024Mi 64 | limits: 65 | cpu: 1000m 66 | memory: 2048Mi 67 | -------------------------------------------------------------------------------- /cluster/apps/ibkr-bot/jobs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: batch/v1 3 | kind: CronJob 4 | metadata: 5 | name: ib-trading-job 6 | spec: 7 | schedule: "0 7 * * *" # 7:10am server time 8 | jobTemplate: 9 | spec: 10 | backoffLimit: 3 11 | ttlSecondsAfterFinished: 86400 12 | template: 13 | metadata: 14 | labels: 15 | app: ib-trading-app 16 | spec: 17 | serviceAccountName: ibkr-trading-app-service-account 18 | restartPolicy: Never 19 | initContainers: 20 | - name: volume-owner 21 | image: busybox:1.37.0 22 | command: ["sh", "-c", "chown -R 1000:1000 /data"] 23 | volumeMounts: 24 | - name: data-volume 25 | mountPath: /data 26 | containers: 27 | - name: ib-trading-app 28 | image: ghcr.io/omdv/ib-trading-app:latest 29 | imagePullPolicy: Always 30 | envFrom: 31 | - configMapRef: 32 | name: ibkr-app-config 33 | - secretRef: 34 | name: ibkr-app-secret 35 | resources: 36 | requests: 37 | cpu: 500m 38 | memory: 1024Mi 39 | limits: 40 | cpu: 1000m 41 | memory: 2048Mi 42 | volumeMounts: 43 | - name: data-volume 44 | mountPath: /data 45 | volumes: 46 | - name: data-volume 47 | persistentVolumeClaim: 48 | claimName: pvc-ibkr-data 49 | imagePullSecrets: 50 | - name: ghcr-secret 51 | 52 | --- 53 | apiVersion: batch/v1 54 | kind: CronJob 55 | metadata: 56 | name: ib-prediction-job 57 | spec: 58 | schedule: "2 9 * * *" # 9:02am server time 59 | jobTemplate: 60 | spec: 61 | backoffLimit: 3 62 | ttlSecondsAfterFinished: 86400 63 | template: 64 | metadata: 65 | labels: 66 | app: ib-prediction-app 67 | spec: 68 | serviceAccountName: ibkr-prediction-app-service-account 69 | restartPolicy: Never 70 | initContainers: 71 | - name: volume-owner 72 | image: busybox:1.37.0 73 | command: ["sh", "-c", "chown -R 1000:1000 /data"] 74 | volumeMounts: 75 | - name: data-volume 76 | mountPath: /data 77 | containers: 78 | - name: ib-prediction-app 79 | image: ghcr.io/omdv/ib-trading-predictor:1.0.2 80 | imagePullPolicy: Always 81 | envFrom: 82 | - configMapRef: 83 | name: ibkr-app-config 84 | - secretRef: 85 | name: ibkr-app-secret 86 | resources: 87 | requests: 88 | cpu: 500m 89 | memory: 1024Mi 90 | limits: 91 | cpu: 1000m 92 | memory: 2048Mi 93 | volumeMounts: 94 | - name: data-volume 95 | mountPath: /data 96 | volumes: 97 | - name: data-volume 98 | persistentVolumeClaim: 99 | claimName: pvc-ibkr-data 100 | imagePullSecrets: 101 | - name: ghcr-secret 102 | -------------------------------------------------------------------------------- /cluster/apps/ibkr-bot/kustomization.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: kustomize.config.k8s.io/v1beta1 3 | kind: Kustomization 4 | resources: 5 | - service-account.yaml 6 | - network-policy.yaml 7 | - configmap.yaml 8 | - deployment.yaml 9 | - jobs.yaml 10 | - service.yaml 11 | - secrets.yaml 12 | - volumes.yaml 13 | -------------------------------------------------------------------------------- /cluster/apps/ibkr-bot/network-policy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: NetworkPolicy 3 | metadata: 4 | name: ibkr-gateway-network-policy 5 | spec: 6 | podSelector: 7 | matchLabels: 8 | app: ibkr-gateway 9 | policyTypes: 10 | - Ingress 11 | - Egress 12 | ingress: 13 | - from: 14 | - namespaceSelector: 15 | matchLabels: 16 | kubernetes.io/metadata.name: ibkr-trading 17 | - podSelector: 18 | matchLabels: 19 | app: ibkr-trading-app 20 | ports: 21 | - port: 8888 22 | protocol: TCP 23 | - port: 7462 24 | protocol: TCP 25 | egress: 26 | - to: 27 | - namespaceSelector: {} 28 | ports: 29 | - port: 53 30 | protocol: UDP 31 | - port: 53 32 | protocol: TCP 33 | # Allow connection to IBKR API endpoints 34 | - to: 35 | - ipBlock: 36 | cidr: 0.0.0.0/0 # Allow all outbound IPs since IBKR might use multiple endpoints 37 | ports: 38 | - port: 4000 39 | protocol: TCP # TWS API port 40 | - port: 4001 41 | protocol: TCP # Live Trading port 42 | - port: 4002 43 | protocol: TCP # Paper Trading port 44 | -------------------------------------------------------------------------------- /cluster/apps/ibkr-bot/secrets.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: external-secrets.io/v1beta1 3 | kind: ExternalSecret 4 | metadata: 5 | name: ibkr-gateway-secret 6 | 7 | spec: 8 | refreshInterval: "15s" 9 | secretStoreRef: 10 | name: vault-backend 11 | kind: ClusterSecretStore 12 | target: 13 | name: ibkr-gateway-secret 14 | data: 15 | - secretKey: username 16 | remoteRef: 17 | key: secret/ibkr 18 | property: VAULT_IBKR_USER_ID 19 | - secretKey: password 20 | remoteRef: 21 | key: secret/ibkr 22 | property: VAULT_IBKR_PASSWORD 23 | 24 | --- 25 | apiVersion: external-secrets.io/v1beta1 26 | kind: ExternalSecret 27 | metadata: 28 | name: ibkr-app-secret 29 | 30 | spec: 31 | refreshInterval: "15s" 32 | secretStoreRef: 33 | name: vault-backend 34 | kind: ClusterSecretStore 35 | target: 36 | name: ibkr-app-secret 37 | data: 38 | - secretKey: QUOTE_API_KEY 39 | remoteRef: 40 | key: secret/ibkr 41 | property: VAULT_IBKR_QUOTE_API_KEY 42 | - secretKey: TRADING_NTFY_TOPIC 43 | remoteRef: 44 | key: secret/ibkr 45 | property: VAULT_IBKR_TRADING_NTFY_TOPIC 46 | 47 | --- 48 | apiVersion: external-secrets.io/v1beta1 49 | kind: ExternalSecret 50 | metadata: 51 | name: ghcr-secret 52 | 53 | spec: 54 | refreshInterval: "15s" 55 | secretStoreRef: 56 | name: vault-backend 57 | kind: ClusterSecretStore 58 | target: 59 | name: ghcr-secret 60 | template: 61 | type: kubernetes.io/dockerconfigjson 62 | data: 63 | .dockerconfigjson: | 64 | { 65 | "auths": { 66 | "ghcr.io": { 67 | "auth": "{{ list .github_username .github_pat | join ":" | b64enc }}" 68 | } 69 | } 70 | } 71 | data: 72 | - secretKey: github_pat 73 | remoteRef: 74 | key: secret/ibkr 75 | property: VAULT_IBKR_GITHUB_PAT 76 | - secretKey: github_username 77 | remoteRef: 78 | key: secret/ibkr 79 | property: VAULT_IBKR_GITHUB_USER 80 | -------------------------------------------------------------------------------- /cluster/apps/ibkr-bot/service-account.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: ibkr-prediction-app-service-account 6 | labels: 7 | app: ibkr-prediction-app 8 | 9 | --- 10 | apiVersion: v1 11 | kind: ServiceAccount 12 | metadata: 13 | name: ibkr-trading-app-service-account 14 | labels: 15 | app: ibkr-trading-app 16 | 17 | --- 18 | apiVersion: v1 19 | kind: ServiceAccount 20 | metadata: 21 | name: ibkr-gateway-service-account 22 | labels: 23 | app: ibkr-gateway 24 | -------------------------------------------------------------------------------- /cluster/apps/ibkr-bot/service.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: ibkr-gateway 6 | spec: 7 | selector: 8 | app: ibkr-gateway 9 | ports: 10 | - name: novnc 11 | port: 6080 12 | targetPort: novnc 13 | - name: api 14 | port: 8888 15 | targetPort: api 16 | - name: command-server 17 | port: 7462 18 | targetPort: command-server 19 | -------------------------------------------------------------------------------- /cluster/apps/ibkr-bot/volumes.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: PersistentVolume 4 | metadata: 5 | name: pv-ibkr-data 6 | spec: 7 | nodeAffinity: 8 | required: 9 | nodeSelectorTerms: 10 | - matchExpressions: 11 | - key: node-role.kubernetes.io/control-plane 12 | operator: Exists 13 | capacity: 14 | storage: 5Gi 15 | accessModes: 16 | - ReadWriteOnce 17 | persistentVolumeReclaimPolicy: Retain 18 | storageClassName: local-path 19 | hostPath: 20 | path: "/pool/ibkr" 21 | 22 | --- 23 | apiVersion: v1 24 | kind: PersistentVolumeClaim 25 | metadata: 26 | name: pvc-ibkr-data 27 | spec: 28 | accessModes: 29 | - ReadWriteOnce 30 | resources: 31 | requests: 32 | storage: 5Gi 33 | storageClassName: local-path 34 | volumeName: pv-ibkr-data 35 | -------------------------------------------------------------------------------- /cluster/apps/icloudpd-om/configmap.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: icloudpd-om-config 6 | labels: 7 | app: icloudpd 8 | 9 | data: 10 | user: "om" 11 | user_id: "1000" 12 | group: admins 13 | group_id: "1000" 14 | download_path: /home/om/iCloud 15 | authentication_type: 2FA 16 | notification_type: Telegram 17 | telegram_token: "123654" 18 | telegram_chat_id: "456321" 19 | folder_structure: "{:%Y}" 20 | notification_days: "14" 21 | synchronisation_interval: "43200" 22 | TZ: America/Chicago 23 | -------------------------------------------------------------------------------- /cluster/apps/icloudpd-om/deployment.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: Deployment 3 | apiVersion: apps/v1 4 | metadata: 5 | name: icloudpd-om 6 | labels: 7 | app: icloudpd 8 | 9 | spec: 10 | replicas: 1 11 | selector: 12 | matchLabels: 13 | app: icloudpd 14 | template: 15 | metadata: 16 | labels: 17 | app: icloudpd 18 | spec: 19 | containers: 20 | - name: icloudpd-om 21 | image: boredazfcuk/icloudpd:latest 22 | env: 23 | - name: apple_id 24 | valueFrom: 25 | secretKeyRef: 26 | name: icloudpd-om-secret 27 | key: APPLE_USER_OM 28 | - name: telegram_token 29 | valueFrom: 30 | secretKeyRef: 31 | name: icloudpd-om-secret 32 | key: TELEGRAM_BOT_TOKEN 33 | - name: telegram_chat_id 34 | valueFrom: 35 | secretKeyRef: 36 | name: icloudpd-om-secret 37 | key: TELEGRAM_BOT_CHAT_ID 38 | envFrom: 39 | - configMapRef: 40 | name: icloudpd-om-config 41 | volumeMounts: 42 | - mountPath: /config 43 | name: config 44 | - mountPath: /home/om/iCloud 45 | name: photos 46 | resources: 47 | requests: 48 | cpu: "0.02" 49 | memory: "8Mi" 50 | limits: 51 | cpu: "0.5" 52 | memory: "64Mi" 53 | volumes: 54 | - name: photos 55 | persistentVolumeClaim: 56 | claimName: pvc-icloudpd-om-photos 57 | - name: config 58 | persistentVolumeClaim: 59 | claimName: pvc-icloudpd-om-config 60 | -------------------------------------------------------------------------------- /cluster/apps/icloudpd-om/kustomization.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | resources: 3 | - configmap.yaml 4 | - secrets.yaml 5 | - volumes.yaml 6 | - deployment.yaml 7 | -------------------------------------------------------------------------------- /cluster/apps/icloudpd-om/secrets.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: external-secrets.io/v1beta1 3 | kind: ExternalSecret 4 | metadata: 5 | name: icloudpd-om-secret 6 | spec: 7 | refreshInterval: "15s" 8 | secretStoreRef: 9 | name: vault-backend 10 | kind: ClusterSecretStore 11 | target: 12 | name: icloudpd-om-secret 13 | data: 14 | - secretKey: APPLE_USER_OM 15 | remoteRef: 16 | key: secret/icloudpd 17 | property: VAULT_ICLOUDPD_USER_OM 18 | - secretKey: TELEGRAM_BOT_TOKEN 19 | remoteRef: 20 | key: secret/icloudpd 21 | property: VAULT_ICLOUDPD_TELEGRAM_TOKEN 22 | - secretKey: TELEGRAM_BOT_CHAT_ID 23 | remoteRef: 24 | key: secret/icloudpd 25 | property: VAULT_ICLOUDPD_TELEGRAM_CHAT_ID 26 | -------------------------------------------------------------------------------- /cluster/apps/icloudpd-om/volumes.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: PersistentVolume 4 | metadata: 5 | name: pv-icloudpd-om-photos 6 | labels: 7 | app: icloudpd 8 | 9 | spec: 10 | nodeAffinity: 11 | required: 12 | nodeSelectorTerms: 13 | - matchExpressions: 14 | - key: node-role.kubernetes.io/control-plane 15 | operator: Exists 16 | capacity: 17 | storage: 1000Gi 18 | storageClassName: local-path 19 | accessModes: 20 | - ReadWriteOnce 21 | hostPath: 22 | path: /pool/photos/icloud-backup-om 23 | 24 | --- 25 | apiVersion: v1 26 | kind: PersistentVolumeClaim 27 | metadata: 28 | name: pvc-icloudpd-om-photos 29 | labels: 30 | app: icloudpd 31 | 32 | spec: 33 | storageClassName: local-path 34 | accessModes: 35 | - ReadWriteOnce 36 | resources: 37 | requests: 38 | storage: 1000Gi 39 | volumeName: pv-icloudpd-om-photos 40 | 41 | --- 42 | apiVersion: v1 43 | kind: PersistentVolume 44 | metadata: 45 | name: pv-icloudpd-om-config 46 | labels: 47 | app: icloudpd 48 | 49 | spec: 50 | nodeAffinity: 51 | required: 52 | nodeSelectorTerms: 53 | - matchExpressions: 54 | - key: node-role.kubernetes.io/control-plane 55 | operator: Exists 56 | capacity: 57 | storage: 1Gi 58 | storageClassName: local-path 59 | accessModes: 60 | - ReadWriteOnce 61 | hostPath: 62 | path: /pool/config/icloud-om 63 | 64 | --- 65 | apiVersion: v1 66 | kind: PersistentVolumeClaim 67 | metadata: 68 | name: pvc-icloudpd-om-config 69 | labels: 70 | app: icloudpd 71 | 72 | spec: 73 | storageClassName: local-path 74 | accessModes: 75 | - ReadWriteOnce 76 | resources: 77 | requests: 78 | storage: 1Gi 79 | volumeName: pv-icloudpd-om-config 80 | -------------------------------------------------------------------------------- /cluster/apps/ingress-nginx/Chart.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v2 3 | name: my-ingress-nginx-chart 4 | type: application 5 | version: 0.1.0 6 | appVersion: "1.0" 7 | dependencies: 8 | - name: ingress-nginx 9 | version: 4.12.0 10 | repository: https://kubernetes.github.io/ingress-nginx 11 | -------------------------------------------------------------------------------- /cluster/apps/ingress-nginx/templates/volumes.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: PersistentVolume 4 | metadata: 5 | name: pv-ingress-nginx-access-log 6 | labels: 7 | app: ingress-nginx 8 | spec: 9 | nodeAffinity: 10 | required: 11 | nodeSelectorTerms: 12 | - matchExpressions: 13 | - key: node-role.kubernetes.io/control-plane 14 | operator: Exists 15 | capacity: 16 | storage: 100Gi 17 | storageClassName: local-path 18 | accessModes: 19 | - ReadWriteOnce 20 | hostPath: 21 | path: /pool/config/ingress-nginx/logs 22 | 23 | --- 24 | apiVersion: v1 25 | kind: PersistentVolumeClaim 26 | metadata: 27 | name: pvc-ingress-nginx-access-log 28 | labels: 29 | app: ingress-nginx 30 | spec: 31 | storageClassName: local-path 32 | accessModes: 33 | - ReadWriteOnce 34 | resources: 35 | requests: 36 | storage: 100Gi 37 | volumeName: pv-ingress-nginx-access-log 38 | 39 | --- 40 | apiVersion: v1 41 | kind: PersistentVolume 42 | metadata: 43 | name: pv-ingress-nginx-ssl-certs 44 | labels: 45 | app: ingress-nginx 46 | spec: 47 | nodeAffinity: 48 | required: 49 | nodeSelectorTerms: 50 | - matchExpressions: 51 | - key: node-role.kubernetes.io/control-plane 52 | operator: Exists 53 | capacity: 54 | storage: 100Gi 55 | storageClassName: local-path 56 | accessModes: 57 | - ReadWriteOnce 58 | hostPath: 59 | path: /pool/config/ingress-nginx/certs 60 | 61 | --- 62 | apiVersion: v1 63 | kind: PersistentVolumeClaim 64 | metadata: 65 | name: pvc-ingress-nginx-ssl-certs 66 | labels: 67 | app: ingress-nginx 68 | spec: 69 | storageClassName: local-path 70 | accessModes: 71 | - ReadWriteOnce 72 | resources: 73 | requests: 74 | storage: 100Gi 75 | volumeName: pv-ingress-nginx-ssl-certs 76 | -------------------------------------------------------------------------------- /cluster/apps/ingress-nginx/values.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ref: https://github.com/kubernetes/ingress-nginx/blob/main/charts/ingress-nginx/values.yaml 3 | ingress-nginx: 4 | controller: 5 | image: 6 | image: ingress-nginx/controller 7 | tag: "v1.12.0" 8 | runAsNonRoot: true 9 | runAsUser: 101 10 | replicaCount: 1 11 | config: 12 | access-log-path: "/var/log/nginx/myaccess.log" 13 | metrics: 14 | enabled: true 15 | serviceMonitor: 16 | enabled: true 17 | additionalLabels: 18 | release: "prometheus" 19 | containerSecurityContext: 20 | allowPrivilegeEscalation: false 21 | capabilities: 22 | drop: 23 | - ALL 24 | add: 25 | - NET_BIND_SERVICE 26 | runAsUser: 101 27 | runAsNonRoot: true 28 | extraVolumes: 29 | - name: access-log-volume 30 | persistentVolumeClaim: 31 | claimName: pvc-ingress-nginx-access-log 32 | - name: ssl-certs-volume 33 | persistentVolumeClaim: 34 | claimName: pvc-ingress-nginx-ssl-certs 35 | extraVolumeMounts: 36 | - name: access-log-volume 37 | mountPath: /var/log/nginx 38 | - name: ssl-certs-volume 39 | mountPath: /etc/ingress-controller/ssl 40 | extraInitContainers: 41 | - name: update-volume-permission 42 | image: busybox:1.37.0 43 | command: ["sh", "-c", "chown -R 101:101 /logs /certs"] 44 | volumeMounts: 45 | - name: access-log-volume 46 | mountPath: /logs 47 | - name: ssl-certs-volume 48 | mountPath: /certs 49 | securityContext: 50 | runAsUser: 0 51 | resources: 52 | limits: 53 | cpu: 100m 54 | memory: 256Mi 55 | requests: 56 | cpu: 10m 57 | memory: 64Mi 58 | livenessProbe: 59 | httpGet: 60 | path: "/healthz" 61 | port: 10254 62 | scheme: HTTP 63 | initialDelaySeconds: 10 64 | periodSeconds: 10 65 | timeoutSeconds: 1 66 | successThreshold: 1 67 | failureThreshold: 5 68 | readinessProbe: 69 | httpGet: 70 | path: "/healthz" 71 | port: 10254 72 | scheme: HTTP 73 | initialDelaySeconds: 10 74 | periodSeconds: 10 75 | timeoutSeconds: 1 76 | successThreshold: 1 77 | failureThreshold: 3 78 | admissionWebhooks: 79 | enabled: true 80 | resources: 81 | limits: 82 | cpu: 10m 83 | memory: 20Mi 84 | requests: 85 | cpu: 10m 86 | memory: 20Mi 87 | -------------------------------------------------------------------------------- /cluster/apps/it-tools/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: it-tools 5 | labels: 6 | app: it-tools 7 | spec: 8 | replicas: 2 9 | selector: 10 | matchLabels: 11 | app: it-tools 12 | template: 13 | metadata: 14 | labels: 15 | app: it-tools 16 | spec: 17 | serviceAccountName: it-tools-service-account 18 | affinity: 19 | nodeAffinity: 20 | preferredDuringSchedulingIgnoredDuringExecution: 21 | - weight: 1 22 | preference: 23 | matchExpressions: 24 | - key: node.kubernetes.io/role 25 | operator: In 26 | values: 27 | - worker 28 | initContainers: 29 | - name: init-nginx-temp 30 | image: busybox:1.37.0 31 | command: ["/bin/sh", "-c"] 32 | args: 33 | - | 34 | mkdir -p /var/cache/nginx/client_temp /var/cache/nginx/proxy_temp /var/cache/nginx/fastcgi_temp /var/cache/nginx/uwsgi_temp /var/cache/nginx/scgi_temp; 35 | chmod 777 /var/cache/nginx/client_temp /var/cache/nginx/proxy_temp /var/cache/nginx/fastcgi_temp /var/cache/nginx/uwsgi_temp /var/cache/nginx/scgi_temp; 36 | mkdir -p /var/run; 37 | chmod 777 /var/run; 38 | volumeMounts: 39 | - name: nginx-temp 40 | mountPath: /var/cache/nginx 41 | - name: nginx-run 42 | mountPath: /var/run 43 | resources: 44 | requests: 45 | cpu: 10m 46 | memory: 16Mi 47 | limits: 48 | cpu: 50m 49 | memory: 32Mi 50 | containers: 51 | - name: it-tools 52 | image: ghcr.io/corentinth/it-tools:2024.10.22-7ca5933 53 | securityContext: 54 | allowPrivilegeEscalation: false 55 | runAsNonRoot: true 56 | runAsUser: 1000 57 | runAsGroup: 1000 58 | capabilities: 59 | drop: 60 | - ALL 61 | ports: 62 | - name: web 63 | containerPort: 80 64 | protocol: TCP 65 | livenessProbe: 66 | tcpSocket: 67 | port: 80 68 | initialDelaySeconds: 30 69 | periodSeconds: 10 70 | timeoutSeconds: 5 71 | failureThreshold: 3 72 | readinessProbe: 73 | tcpSocket: 74 | port: 80 75 | initialDelaySeconds: 10 76 | periodSeconds: 10 77 | timeoutSeconds: 5 78 | failureThreshold: 3 79 | resources: 80 | requests: 81 | cpu: 10m 82 | memory: 128Mi 83 | limits: 84 | cpu: 100m 85 | memory: 128Mi 86 | volumeMounts: 87 | - name: nginx-temp 88 | mountPath: /var/cache/nginx 89 | - name: nginx-run 90 | mountPath: /var/run 91 | 92 | volumes: 93 | - name: nginx-temp 94 | emptyDir: {} 95 | - name: nginx-run 96 | emptyDir: {} 97 | -------------------------------------------------------------------------------- /cluster/apps/it-tools/ingress.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: networking.k8s.io/v1 3 | kind: Ingress 4 | metadata: 5 | name: it-tools 6 | labels: 7 | app: it-tools 8 | annotations: 9 | cert-manager.io/cluster-issuer: "letsencrypt-prod" 10 | nginx.ingress.kubernetes.io/auth-url: "https://auth.kblb.io/oauth2/auth" 11 | nginx.ingress.kubernetes.io/auth-signin: "https://auth.kblb.io/oauth2/start?rd=https://$host$uri" 12 | hajimari.io/enable: "true" 13 | hajimari.io/icon: "tools" 14 | 15 | spec: 16 | ingressClassName: nginx 17 | tls: 18 | - hosts: 19 | - it.kblb.io 20 | secretName: my-certs-it-tools 21 | rules: 22 | - host: it.kblb.io 23 | http: 24 | paths: 25 | - path: / 26 | pathType: Prefix 27 | backend: 28 | service: 29 | name: it-tools 30 | port: 31 | name: web 32 | -------------------------------------------------------------------------------- /cluster/apps/it-tools/kustomization.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | resources: 3 | - serviceaccount.yaml 4 | - network-policy.yaml 5 | - deployment.yaml 6 | - service.yaml 7 | - ingress.yaml 8 | -------------------------------------------------------------------------------- /cluster/apps/it-tools/network-policy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: NetworkPolicy 3 | metadata: 4 | name: it-tools-network-policy 5 | spec: 6 | podSelector: 7 | matchLabels: 8 | app: it-tools 9 | policyTypes: 10 | - Ingress 11 | - Egress 12 | ingress: 13 | - ports: 14 | - port: 80 15 | protocol: TCP 16 | egress: 17 | - {} 18 | -------------------------------------------------------------------------------- /cluster/apps/it-tools/service.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: it-tools 6 | labels: 7 | app: it-tools 8 | 9 | spec: 10 | ports: 11 | - port: 80 12 | name: web 13 | protocol: TCP 14 | targetPort: web 15 | selector: 16 | app: it-tools 17 | -------------------------------------------------------------------------------- /cluster/apps/it-tools/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: it-tools-service-account 5 | labels: 6 | app: it-tools 7 | -------------------------------------------------------------------------------- /cluster/apps/kanboard/deployment.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: Deployment 3 | apiVersion: apps/v1 4 | metadata: 5 | name: kanboard 6 | labels: 7 | app: kanboard 8 | 9 | spec: 10 | replicas: 1 11 | selector: 12 | matchLabels: 13 | app: kanboard 14 | template: 15 | metadata: 16 | labels: 17 | app: kanboard 18 | spec: 19 | containers: 20 | - name: kanboard 21 | image: kanboard/kanboard:latest 22 | ports: 23 | - name: http 24 | containerPort: 80 25 | protocol: TCP 26 | volumeMounts: 27 | - mountPath: /var/www/app/data 28 | name: data-volume 29 | - mountPath: /var/www/app/plugins 30 | name: plugins-volume 31 | resources: 32 | limits: 33 | cpu: "1" 34 | memory: 512Mi 35 | requests: 36 | cpu: "0.2" 37 | memory: 256Mi 38 | volumes: 39 | - name: data-volume 40 | persistentVolumeClaim: 41 | claimName: pvc-kanboard-data 42 | - name: plugins-volume 43 | persistentVolumeClaim: 44 | claimName: pvc-kanboard-plugins 45 | -------------------------------------------------------------------------------- /cluster/apps/kanboard/ingress.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: networking.k8s.io/v1 3 | kind: Ingress 4 | metadata: 5 | name: kanboard 6 | labels: 7 | app: kanboard 8 | gethomepage.dev/enabled: "true" 9 | annotations: 10 | cert-manager.io/cluster-issuer: "letsencrypt-prod" 11 | nginx.ingress.kubernetes.io/auth-url: "https://auth.kblb.io/oauth2/auth" 12 | nginx.ingress.kubernetes.io/auth-signin: "https://auth.kblb.io/oauth2/start?rd=https://$host$uri" 13 | hajimari.io/enable: "true" 14 | spec: 15 | ingressClassName: nginx 16 | tls: 17 | - hosts: 18 | - kanboard.kblb.io 19 | secretName: my-certs-kanboard 20 | rules: 21 | - host: kanboard.kblb.io 22 | http: 23 | paths: 24 | - path: / 25 | pathType: Prefix 26 | backend: 27 | service: 28 | name: kanboard 29 | port: 30 | name: http 31 | -------------------------------------------------------------------------------- /cluster/apps/kanboard/kustomization.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | resources: 3 | - volumes.yaml 4 | - service.yaml 5 | - deployment.yaml 6 | - ingress.yaml 7 | -------------------------------------------------------------------------------- /cluster/apps/kanboard/service.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: kanboard 6 | labels: 7 | app: kanboard 8 | 9 | spec: 10 | ports: 11 | - name: http 12 | protocol: TCP 13 | port: 80 14 | targetPort: http 15 | selector: 16 | app: kanboard 17 | -------------------------------------------------------------------------------- /cluster/apps/kanboard/volumes.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: PersistentVolume 4 | metadata: 5 | name: pv-kanboard-plugins 6 | labels: 7 | app: kanboard 8 | spec: 9 | nodeAffinity: 10 | required: 11 | nodeSelectorTerms: 12 | - matchExpressions: 13 | - key: node-role.kubernetes.io/control-plane 14 | operator: Exists 15 | capacity: 16 | storage: 1Gi 17 | storageClassName: local-path 18 | accessModes: 19 | - ReadWriteOnce 20 | hostPath: 21 | path: /pool/config/kanboard/plugins 22 | 23 | --- 24 | apiVersion: v1 25 | kind: PersistentVolumeClaim 26 | metadata: 27 | name: pvc-kanboard-plugins 28 | labels: 29 | app: kanboard 30 | spec: 31 | storageClassName: local-path 32 | accessModes: 33 | - ReadWriteOnce 34 | resources: 35 | requests: 36 | storage: 1Gi 37 | volumeName: pv-kanboard-plugins 38 | 39 | --- 40 | apiVersion: v1 41 | kind: PersistentVolume 42 | metadata: 43 | name: pv-kanboard-data 44 | labels: 45 | app: kanboard 46 | spec: 47 | nodeAffinity: 48 | required: 49 | nodeSelectorTerms: 50 | - matchExpressions: 51 | - key: node-role.kubernetes.io/control-plane 52 | operator: Exists 53 | capacity: 54 | storage: 100Gi 55 | storageClassName: local-path 56 | accessModes: 57 | - ReadWriteOnce 58 | hostPath: 59 | path: /pool/config/kanboard/data 60 | 61 | --- 62 | apiVersion: v1 63 | kind: PersistentVolumeClaim 64 | metadata: 65 | name: pvc-kanboard-data 66 | labels: 67 | app: kanboard 68 | spec: 69 | storageClassName: local-path 70 | accessModes: 71 | - ReadWriteOnce 72 | resources: 73 | requests: 74 | storage: 1Gi 75 | volumeName: pv-kanboard-data 76 | -------------------------------------------------------------------------------- /cluster/apps/karakeep/chrome-deployment.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: karakeep-chrome 6 | spec: 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: karakeep-chrome 11 | template: 12 | metadata: 13 | labels: 14 | app: karakeep-chrome 15 | spec: 16 | containers: 17 | - name: karakeep-chrome 18 | image: gcr.io/zenika-hub/alpine-chrome:123 19 | command: 20 | - chromium-browser 21 | - --headless 22 | - --no-sandbox 23 | - --disable-gpu 24 | - --disable-dev-shm-usage 25 | - --remote-debugging-address=0.0.0.0 26 | - --remote-debugging-port=9222 27 | - --hide-scrollbars 28 | ports: 29 | - containerPort: 9222 30 | resources: 31 | requests: 32 | cpu: 200m 33 | memory: 256Mi 34 | limits: 35 | cpu: 400m 36 | memory: 512Mi 37 | -------------------------------------------------------------------------------- /cluster/apps/karakeep/chrome-service.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: karakeep-chrome 6 | spec: 7 | selector: 8 | app: karakeep-chrome 9 | ports: 10 | - protocol: TCP 11 | port: 9222 12 | targetPort: 9222 13 | type: ClusterIP 14 | -------------------------------------------------------------------------------- /cluster/apps/karakeep/configmap.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: karakeep-config 6 | data: 7 | NEXTAUTH_URL: "https://karakeep.kblb.io" 8 | KARAKEEP_VERSION: "release" 9 | DISABLE_SIGNUPS: "true" 10 | -------------------------------------------------------------------------------- /cluster/apps/karakeep/data-pv.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: PersistentVolume 4 | metadata: 5 | name: pv-karakeep-data 6 | 7 | spec: 8 | capacity: 9 | storage: 100Gi 10 | storageClassName: local-path 11 | accessModes: 12 | - ReadWriteOnce 13 | hostPath: 14 | path: /pool/karakeep/data 15 | -------------------------------------------------------------------------------- /cluster/apps/karakeep/data-pvc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: PersistentVolumeClaim 4 | metadata: 5 | name: pvc-karakeep-data 6 | spec: 7 | accessModes: 8 | - ReadWriteOnce 9 | resources: 10 | requests: 11 | storage: 100Gi 12 | storageClassName: local-path 13 | volumeName: pv-karakeep-data 14 | -------------------------------------------------------------------------------- /cluster/apps/karakeep/external-secrets.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: external-secrets.io/v1beta1 3 | kind: ExternalSecret 4 | metadata: 5 | name: karakeep-external-secret 6 | 7 | spec: 8 | refreshInterval: "15s" 9 | secretStoreRef: 10 | name: vault-backend 11 | kind: ClusterSecretStore 12 | target: 13 | name: karakeep-secrets 14 | data: 15 | - secretKey: OPENAI_API_KEY 16 | remoteRef: 17 | key: secret/karakeep 18 | property: VAULT_KARAKEEP_OPENAI_API_KEY 19 | - secretKey: NEXTAUTH_SECRET 20 | remoteRef: 21 | key: secret/karakeep 22 | property: VAULT_KARAKEEP_NEXTAUTH_SECRET 23 | - secretKey: MEILI_MASTER_KEY 24 | remoteRef: 25 | key: secret/karakeep 26 | property: VAULT_KARAKEEP_MEILI_MASTER_KEY 27 | - secretKey: NEXT_PUBLIC_SECRET 28 | remoteRef: 29 | key: secret/karakeep 30 | property: VAULT_KARAKEEP_NEXT_PUBLIC_SECRET 31 | -------------------------------------------------------------------------------- /cluster/apps/karakeep/ingress.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: networking.k8s.io/v1 3 | kind: Ingress 4 | metadata: 5 | name: karakeep-web 6 | labels: 7 | app: karakeep-web 8 | annotations: 9 | cert-manager.io/cluster-issuer: "letsencrypt-prod" 10 | hajimari.io/enable: "true" 11 | hajimari.io/appName: "karakeep" 12 | hajimari.io/icon: "archive-star" 13 | 14 | spec: 15 | ingressClassName: nginx 16 | tls: 17 | - hosts: 18 | - karakeep.kblb.io 19 | secretName: my-certs-karakeep 20 | rules: 21 | - host: karakeep.kblb.io 22 | http: 23 | paths: 24 | - path: / 25 | pathType: Prefix 26 | backend: 27 | service: 28 | name: karakeep-web 29 | port: 30 | number: 3000 31 | -------------------------------------------------------------------------------- /cluster/apps/karakeep/kustomization.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: kustomize.config.k8s.io/v1beta1 3 | kind: Kustomization 4 | 5 | resources: 6 | - configmap.yaml 7 | - external-secrets.yaml 8 | - web-deployment.yaml 9 | - web-service.yaml 10 | - chrome-deployment.yaml 11 | - chrome-service.yaml 12 | - meilisearch-deployment.yaml 13 | - meilisearch-service.yaml 14 | - meilisearch-pvc.yaml 15 | - meilisearch-pv.yaml 16 | - data-pvc.yaml 17 | - data-pv.yaml 18 | - ingress.yaml 19 | -------------------------------------------------------------------------------- /cluster/apps/karakeep/meilisearch-deployment.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: karakeep-meilisearch 6 | spec: 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: karakeep-meilisearch 11 | template: 12 | metadata: 13 | labels: 14 | app: karakeep-meilisearch 15 | spec: 16 | containers: 17 | - name: karakeep-meilisearch 18 | image: getmeili/meilisearch:v1.11.1 19 | env: 20 | - name: MEILI_NO_ANALYTICS 21 | value: "true" 22 | volumeMounts: 23 | - mountPath: /meili_data 24 | name: karakeep-meilisearch 25 | envFrom: 26 | - secretRef: 27 | name: karakeep-secrets 28 | - configMapRef: 29 | name: karakeep-config 30 | resources: 31 | requests: 32 | cpu: 100m 33 | memory: 64Mi 34 | limits: 35 | cpu: 200m 36 | memory: 128Mi 37 | volumes: 38 | - name: karakeep-meilisearch 39 | persistentVolumeClaim: 40 | claimName: pvc-karakeep-meilisearch 41 | -------------------------------------------------------------------------------- /cluster/apps/karakeep/meilisearch-pv.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: PersistentVolume 4 | metadata: 5 | name: pv-karakeep-meilisearch 6 | 7 | spec: 8 | capacity: 9 | storage: 100Gi 10 | storageClassName: local-path 11 | accessModes: 12 | - ReadWriteOnce 13 | hostPath: 14 | path: /pool/karakeep/meilisearch 15 | -------------------------------------------------------------------------------- /cluster/apps/karakeep/meilisearch-pvc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: PersistentVolumeClaim 4 | metadata: 5 | name: pvc-karakeep-meilisearch 6 | spec: 7 | accessModes: 8 | - ReadWriteOnce 9 | resources: 10 | requests: 11 | storage: 100Gi 12 | storageClassName: local-path 13 | volumeName: pv-karakeep-meilisearch 14 | -------------------------------------------------------------------------------- /cluster/apps/karakeep/meilisearch-service.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: karakeep-meilisearch 6 | spec: 7 | selector: 8 | app: karakeep-meilisearch 9 | ports: 10 | - protocol: TCP 11 | port: 7700 12 | targetPort: 7700 13 | type: ClusterIP 14 | -------------------------------------------------------------------------------- /cluster/apps/karakeep/web-deployment.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: karakeep-web 6 | spec: 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: karakeep-web 11 | template: 12 | metadata: 13 | labels: 14 | app: karakeep-web 15 | spec: 16 | containers: 17 | - name: karakeep-web 18 | image: ghcr.io/karakeep-app/karakeep 19 | imagePullPolicy: Always 20 | ports: 21 | - containerPort: 3000 22 | env: 23 | - name: MEILI_ADDR 24 | value: http://karakeep-meilisearch.apps.svc.cluster.local:7700 25 | - name: BROWSER_WEB_URL 26 | value: http://karakeep-chrome.apps.svc.cluster.local:9222 27 | - name: DATA_DIR 28 | value: /data 29 | volumeMounts: 30 | - mountPath: /data 31 | name: karakeep-data 32 | envFrom: 33 | - secretRef: 34 | name: karakeep-secrets 35 | - configMapRef: 36 | name: karakeep-config 37 | resources: 38 | requests: 39 | cpu: 250m 40 | memory: 1024Mi 41 | limits: 42 | cpu: 500m 43 | memory: 2048Mi 44 | volumes: 45 | - name: karakeep-data 46 | persistentVolumeClaim: 47 | claimName: pvc-karakeep-data 48 | -------------------------------------------------------------------------------- /cluster/apps/karakeep/web-service.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: karakeep-web 6 | spec: 7 | selector: 8 | app: karakeep-web 9 | ports: 10 | - protocol: TCP 11 | port: 3000 12 | targetPort: 3000 13 | type: ClusterIP 14 | -------------------------------------------------------------------------------- /cluster/apps/kolmafia/deployment.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: Deployment 3 | apiVersion: apps/v1 4 | metadata: 5 | name: kolmafia 6 | labels: 7 | app: kolmafia 8 | 9 | spec: 10 | replicas: 1 11 | selector: 12 | matchLabels: 13 | app: kolmafia 14 | template: 15 | metadata: 16 | labels: 17 | app: kolmafia 18 | spec: 19 | initContainers: 20 | - name: volume-owner 21 | image: busybox:1.37.0 22 | command: ["sh", "-c", "chown -R 1000:1000 /headless/.kolmafia"] 23 | volumeMounts: 24 | - name: kolmafia-data 25 | mountPath: /headless/.kolmafia 26 | containers: 27 | - name: kolmafia 28 | image: ghcr.io/omdv/kolmafia-docker/kolmafia:latest 29 | ports: 30 | - name: http 31 | protocol: TCP 32 | containerPort: 6901 33 | env: 34 | - name: VNC_PASSWORDLESS 35 | value: "true" 36 | - name: VNC_RESOLUTION 37 | value: "1280x720" 38 | volumeMounts: 39 | - name: kolmafia-data 40 | mountPath: /headless/.kolmafia 41 | volumes: 42 | - name: kolmafia-data 43 | persistentVolumeClaim: 44 | claimName: pvc-kolmafia 45 | -------------------------------------------------------------------------------- /cluster/apps/kolmafia/ingress.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: networking.k8s.io/v1 3 | kind: Ingress 4 | metadata: 5 | name: kolmafia 6 | labels: 7 | app: kolmafia 8 | annotations: 9 | cert-manager.io/cluster-issuer: "letsencrypt-prod" 10 | nginx.ingress.kubernetes.io/auth-url: "https://auth.kblb.io/oauth2/auth" 11 | nginx.ingress.kubernetes.io/auth-signin: "https://auth.kblb.io/oauth2/start?rd=https://$host$uri" 12 | hajimari.io/enable: "true" 13 | hajimari.io/icon: "desktop-classic" 14 | 15 | 16 | spec: 17 | ingressClassName: nginx 18 | tls: 19 | - hosts: 20 | - kol.kblb.io 21 | secretName: my-certs-kolmafia 22 | rules: 23 | - host: kol.kblb.io 24 | http: 25 | paths: 26 | - path: / 27 | pathType: Prefix 28 | backend: 29 | service: 30 | name: kolmafia 31 | port: 32 | name: http 33 | -------------------------------------------------------------------------------- /cluster/apps/kolmafia/kustomization.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | resources: 3 | - deployment.yaml 4 | - service.yaml 5 | - ingress.yaml 6 | - pv.yaml 7 | - pvc.yaml 8 | -------------------------------------------------------------------------------- /cluster/apps/kolmafia/pv.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: PersistentVolume 4 | metadata: 5 | name: pv-kolmafia 6 | spec: 7 | capacity: 8 | storage: 100Mi 9 | storageClassName: local-path 10 | accessModes: 11 | - ReadWriteOnce 12 | hostPath: 13 | path: /pool/config/kolmafia 14 | -------------------------------------------------------------------------------- /cluster/apps/kolmafia/pvc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: PersistentVolumeClaim 4 | metadata: 5 | name: pvc-kolmafia 6 | spec: 7 | storageClassName: local-path 8 | accessModes: 9 | - ReadWriteOnce 10 | resources: 11 | requests: 12 | storage: 100Mi 13 | volumeName: pv-kolmafia 14 | -------------------------------------------------------------------------------- /cluster/apps/kolmafia/service.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: kolmafia 6 | labels: 7 | app: kolmafia 8 | 9 | spec: 10 | ports: 11 | - name: http 12 | protocol: TCP 13 | port: 6901 14 | targetPort: http 15 | selector: 16 | app: kolmafia 17 | -------------------------------------------------------------------------------- /cluster/apps/main/Chart.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v2 3 | name: apps-chart 4 | description: Applications 5 | type: application 6 | version: 0.1.0 7 | appVersion: "1.0" 8 | -------------------------------------------------------------------------------- /cluster/apps/main/templates/calibre-web.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: calibre-web 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | annotations: 10 | argocd.argoproj.io/sync-wave: "5" 11 | spec: 12 | destination: 13 | namespace: apps 14 | server: {{ .Values.spec.destination.server }} 15 | project: default 16 | source: 17 | path: cluster/apps/calibre-web 18 | repoURL: {{ .Values.spec.source.repoURL }} 19 | targetRevision: {{ .Values.spec.source.targetRevision }} 20 | syncPolicy: 21 | automated: 22 | prune: true 23 | selfHeal: true 24 | syncOptions: 25 | - CreateNamespace=true 26 | -------------------------------------------------------------------------------- /cluster/apps/main/templates/calibre.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: calibre 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | annotations: 10 | argocd.argoproj.io/sync-wave: "5" 11 | spec: 12 | destination: 13 | namespace: apps 14 | server: {{ .Values.spec.destination.server }} 15 | project: default 16 | source: 17 | path: cluster/apps/calibre 18 | repoURL: {{ .Values.spec.source.repoURL }} 19 | targetRevision: {{ .Values.spec.source.targetRevision }} 20 | syncPolicy: 21 | automated: 22 | prune: true 23 | selfHeal: true 24 | syncOptions: 25 | - CreateNamespace=true 26 | -------------------------------------------------------------------------------- /cluster/apps/main/templates/cert-manager.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: cert-manager 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | annotations: 10 | argocd.argoproj.io/sync-wave: "-5" 11 | spec: 12 | destination: 13 | namespace: cert-manager 14 | server: {{ .Values.spec.destination.server }} 15 | project: default 16 | source: 17 | path: cluster/apps/cert-manager 18 | repoURL: {{ .Values.spec.source.repoURL }} 19 | targetRevision: {{ .Values.spec.source.targetRevision }} 20 | syncPolicy: 21 | automated: 22 | prune: true 23 | selfHeal: true 24 | syncOptions: 25 | - CreateNamespace=true 26 | - RespectSyncWave=true 27 | retry: 28 | limit: 5 29 | backoff: 30 | duration: 5s 31 | factor: 2 32 | maxDuration: 3m 33 | -------------------------------------------------------------------------------- /cluster/apps/main/templates/cyberchef.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: cyberchef 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | annotations: 10 | argocd.argoproj.io/sync-wave: "5" 11 | spec: 12 | destination: 13 | namespace: apps 14 | server: {{ .Values.spec.destination.server }} 15 | project: default 16 | source: 17 | path: cluster/apps/cyberchef 18 | repoURL: {{ .Values.spec.source.repoURL }} 19 | targetRevision: {{ .Values.spec.source.targetRevision }} 20 | syncPolicy: 21 | automated: 22 | prune: true 23 | selfHeal: true 24 | syncOptions: 25 | - CreateNamespace=true 26 | -------------------------------------------------------------------------------- /cluster/apps/main/templates/ddns.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: ddns 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | annotations: 10 | argocd.argoproj.io/sync-wave: "5" 11 | spec: 12 | destination: 13 | namespace: networking 14 | server: {{ .Values.spec.destination.server }} 15 | project: default 16 | source: 17 | path: cluster/apps/ddns 18 | repoURL: {{ .Values.spec.source.repoURL }} 19 | targetRevision: {{ .Values.spec.source.targetRevision }} 20 | syncPolicy: 21 | automated: 22 | prune: true 23 | selfHeal: true 24 | syncOptions: 25 | - CreateNamespace=true 26 | -------------------------------------------------------------------------------- /cluster/apps/main/templates/hajimari.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: hajimari 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | annotations: 10 | argocd.argoproj.io/sync-wave: "5" 11 | spec: 12 | destination: 13 | namespace: apps 14 | server: {{ .Values.spec.destination.server }} 15 | project: default 16 | source: 17 | path: cluster/apps/hajimari 18 | repoURL: {{ .Values.spec.source.repoURL }} 19 | targetRevision: {{ .Values.spec.source.targetRevision }} 20 | syncPolicy: 21 | automated: 22 | prune: true 23 | selfHeal: true 24 | syncOptions: 25 | - CreateNamespace=true 26 | -------------------------------------------------------------------------------- /cluster/apps/main/templates/ingress-nginx.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: ingress-nginx 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | annotations: 10 | argocd.argoproj.io/sync-wave: "-5" 11 | spec: 12 | destination: 13 | namespace: networking 14 | server: {{ .Values.spec.destination.server }} 15 | project: default 16 | source: 17 | path: cluster/apps/ingress-nginx 18 | repoURL: {{ .Values.spec.source.repoURL }} 19 | targetRevision: {{ .Values.spec.source.targetRevision }} 20 | syncPolicy: 21 | automated: 22 | prune: true 23 | selfHeal: true 24 | syncOptions: 25 | - CreateNamespace=true 26 | - RespectSyncWave=true 27 | retry: 28 | limit: 5 29 | backoff: 30 | duration: 5s 31 | factor: 2 32 | maxDuration: 3m 33 | -------------------------------------------------------------------------------- /cluster/apps/main/templates/it-tools.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: it-tools 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | annotations: 10 | argocd.argoproj.io/sync-wave: "5" 11 | spec: 12 | destination: 13 | namespace: apps 14 | server: {{ .Values.spec.destination.server }} 15 | project: default 16 | source: 17 | path: cluster/apps/it-tools 18 | repoURL: {{ .Values.spec.source.repoURL }} 19 | targetRevision: {{ .Values.spec.source.targetRevision }} 20 | syncPolicy: 21 | automated: 22 | prune: true 23 | selfHeal: true 24 | syncOptions: 25 | - CreateNamespace=true 26 | -------------------------------------------------------------------------------- /cluster/apps/main/templates/kanboard.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: kanboard 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | annotations: 10 | argocd.argoproj.io/sync-wave: "5" 11 | spec: 12 | destination: 13 | namespace: apps 14 | server: {{ .Values.spec.destination.server }} 15 | project: default 16 | source: 17 | path: cluster/apps/kanboard 18 | repoURL: {{ .Values.spec.source.repoURL }} 19 | targetRevision: {{ .Values.spec.source.targetRevision }} 20 | syncPolicy: 21 | automated: 22 | prune: true 23 | selfHeal: true 24 | syncOptions: 25 | - CreateNamespace=true 26 | -------------------------------------------------------------------------------- /cluster/apps/main/templates/karakeep.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: karakeep 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | annotations: 10 | argocd.argoproj.io/sync-wave: "5" 11 | spec: 12 | destination: 13 | namespace: apps 14 | server: {{ .Values.spec.destination.server }} 15 | project: default 16 | source: 17 | path: cluster/apps/karakeep 18 | repoURL: {{ .Values.spec.source.repoURL }} 19 | targetRevision: {{ .Values.spec.source.targetRevision }} 20 | syncPolicy: 21 | automated: 22 | prune: true 23 | selfHeal: true 24 | syncOptions: 25 | - CreateNamespace=true 26 | -------------------------------------------------------------------------------- /cluster/apps/main/templates/kolmafia.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: kolmafia 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | annotations: 10 | argocd.argoproj.io/sync-wave: "5" 11 | spec: 12 | destination: 13 | namespace: apps 14 | server: {{ .Values.spec.destination.server }} 15 | project: default 16 | source: 17 | path: cluster/apps/kolmafia 18 | repoURL: {{ .Values.spec.source.repoURL }} 19 | targetRevision: {{ .Values.spec.source.targetRevision }} 20 | syncPolicy: 21 | automated: 22 | prune: true 23 | selfHeal: true 24 | syncOptions: 25 | - CreateNamespace=true 26 | -------------------------------------------------------------------------------- /cluster/apps/main/templates/mariadb.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: mariadb 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | annotations: 10 | argocd.argoproj.io/sync-wave: "1" 11 | spec: 12 | destination: 13 | namespace: databases 14 | server: {{ .Values.spec.destination.server }} 15 | project: default 16 | source: 17 | path: cluster/apps/mariadb 18 | repoURL: {{ .Values.spec.source.repoURL }} 19 | targetRevision: {{ .Values.spec.source.targetRevision }} 20 | syncPolicy: 21 | automated: 22 | prune: true 23 | selfHeal: true 24 | syncOptions: 25 | - CreateNamespace=true 26 | -------------------------------------------------------------------------------- /cluster/apps/main/templates/mealie.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: mealie 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | annotations: 10 | argocd.argoproj.io/sync-wave: "5" 11 | spec: 12 | destination: 13 | namespace: apps 14 | server: {{ .Values.spec.destination.server }} 15 | project: default 16 | source: 17 | path: cluster/apps/mealie 18 | repoURL: {{ .Values.spec.source.repoURL }} 19 | targetRevision: {{ .Values.spec.source.targetRevision }} 20 | syncPolicy: 21 | automated: 22 | prune: true 23 | selfHeal: true 24 | syncOptions: 25 | - CreateNamespace=true 26 | -------------------------------------------------------------------------------- /cluster/apps/main/templates/metrics-prometheus.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: metrics-prometheus 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | annotations: 10 | argocd.argoproj.io/sync-wave: "-6" 11 | spec: 12 | destination: 13 | namespace: metrics 14 | server: {{ .Values.spec.destination.server }} 15 | project: default 16 | source: 17 | path: cluster/apps/metrics-prometheus 18 | repoURL: {{ .Values.spec.source.repoURL }} 19 | targetRevision: {{ .Values.spec.source.targetRevision }} 20 | syncPolicy: 21 | automated: 22 | prune: true 23 | selfHeal: true 24 | syncOptions: 25 | - CreateNamespace=true 26 | - ServerSideApply=true 27 | -------------------------------------------------------------------------------- /cluster/apps/main/templates/metrics-server.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: metrics-server 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | annotations: 10 | argocd.argoproj.io/sync-wave: "-6" 11 | spec: 12 | destination: 13 | namespace: metrics-server 14 | server: {{ .Values.spec.destination.server }} 15 | project: default 16 | source: 17 | path: cluster/apps/metrics-server 18 | repoURL: {{ .Values.spec.source.repoURL }} 19 | targetRevision: {{ .Values.spec.source.targetRevision }} 20 | syncPolicy: 21 | automated: 22 | prune: true 23 | selfHeal: true 24 | syncOptions: 25 | - CreateNamespace=true 26 | -------------------------------------------------------------------------------- /cluster/apps/main/templates/n8n.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: n8n 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | annotations: 10 | argocd.argoproj.io/sync-wave: "5" 11 | spec: 12 | destination: 13 | namespace: apps 14 | server: {{ .Values.spec.destination.server }} 15 | project: default 16 | source: 17 | path: cluster/apps/n8n 18 | repoURL: {{ .Values.spec.source.repoURL }} 19 | targetRevision: {{ .Values.spec.source.targetRevision }} 20 | syncPolicy: 21 | automated: 22 | prune: true 23 | selfHeal: true 24 | syncOptions: 25 | - CreateNamespace=true 26 | -------------------------------------------------------------------------------- /cluster/apps/main/templates/nginx.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: nginx 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | annotations: 10 | argocd.argoproj.io/sync-wave: "1" 11 | spec: 12 | destination: 13 | namespace: apps 14 | server: {{ .Values.spec.destination.server }} 15 | project: default 16 | source: 17 | path: cluster/apps/nginx 18 | repoURL: {{ .Values.spec.source.repoURL }} 19 | targetRevision: {{ .Values.spec.source.targetRevision }} 20 | syncPolicy: 21 | automated: 22 | prune: true 23 | selfHeal: true 24 | syncOptions: 25 | - CreateNamespace=true 26 | -------------------------------------------------------------------------------- /cluster/apps/main/templates/nocodb.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: nocodb 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | annotations: 10 | argocd.argoproj.io/sync-wave: "5" 11 | spec: 12 | destination: 13 | namespace: apps 14 | server: {{ .Values.spec.destination.server }} 15 | project: default 16 | source: 17 | path: cluster/apps/nocodb 18 | repoURL: {{ .Values.spec.source.repoURL }} 19 | targetRevision: {{ .Values.spec.source.targetRevision }} 20 | syncPolicy: 21 | automated: 22 | prune: true 23 | selfHeal: true 24 | syncOptions: 25 | - CreateNamespace=true 26 | -------------------------------------------------------------------------------- /cluster/apps/main/templates/oauth2-proxy.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: oauth2-proxy 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | annotations: 10 | argocd.argoproj.io/sync-wave: "1" 11 | spec: 12 | destination: 13 | namespace: networking 14 | server: {{ .Values.spec.destination.server }} 15 | project: default 16 | source: 17 | path: cluster/apps/oauth2-proxy 18 | repoURL: {{ .Values.spec.source.repoURL }} 19 | targetRevision: {{ .Values.spec.source.targetRevision }} 20 | syncPolicy: 21 | automated: 22 | prune: true 23 | selfHeal: true 24 | syncOptions: 25 | - CreateNamespace=true 26 | -------------------------------------------------------------------------------- /cluster/apps/main/templates/open-webui.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: open-webui 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | annotations: 10 | argocd.argoproj.io/sync-wave: "5" 11 | spec: 12 | destination: 13 | namespace: apps 14 | server: {{ .Values.spec.destination.server }} 15 | project: default 16 | source: 17 | path: cluster/apps/open-webui 18 | repoURL: {{ .Values.spec.source.repoURL }} 19 | targetRevision: {{ .Values.spec.source.targetRevision }} 20 | syncPolicy: 21 | automated: 22 | prune: true 23 | selfHeal: true 24 | syncOptions: 25 | - CreateNamespace=true 26 | -------------------------------------------------------------------------------- /cluster/apps/main/templates/paperless.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: paperless 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | annotations: 10 | argocd.argoproj.io/sync-wave: "5" 11 | spec: 12 | destination: 13 | namespace: apps 14 | server: {{ .Values.spec.destination.server }} 15 | project: default 16 | source: 17 | path: cluster/apps/paperless 18 | repoURL: {{ .Values.spec.source.repoURL }} 19 | targetRevision: {{ .Values.spec.source.targetRevision }} 20 | syncPolicy: 21 | automated: 22 | prune: true 23 | selfHeal: true 24 | syncOptions: 25 | - CreateNamespace=true 26 | -------------------------------------------------------------------------------- /cluster/apps/main/templates/pgbackup.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: pgbackup 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | annotations: 10 | argocd.argoproj.io/sync-wave: "1" 11 | spec: 12 | destination: 13 | namespace: databases 14 | server: {{ .Values.spec.destination.server }} 15 | project: default 16 | source: 17 | path: cluster/apps/pgbackup 18 | repoURL: {{ .Values.spec.source.repoURL }} 19 | targetRevision: {{ .Values.spec.source.targetRevision }} 20 | syncPolicy: 21 | automated: 22 | prune: true 23 | selfHeal: true 24 | syncOptions: 25 | - CreateNamespace=true 26 | -------------------------------------------------------------------------------- /cluster/apps/main/templates/plex.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: plex 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | annotations: 10 | argocd.argoproj.io/sync-wave: "5" 11 | spec: 12 | destination: 13 | namespace: apps 14 | server: {{ .Values.spec.destination.server }} 15 | project: default 16 | source: 17 | path: cluster/apps/plex 18 | repoURL: {{ .Values.spec.source.repoURL }} 19 | targetRevision: {{ .Values.spec.source.targetRevision }} 20 | syncPolicy: 21 | automated: 22 | prune: true 23 | selfHeal: true 24 | syncOptions: 25 | - CreateNamespace=true 26 | -------------------------------------------------------------------------------- /cluster/apps/main/templates/postgres.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: postgres 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | annotations: 10 | argocd.argoproj.io/sync-wave: "1" 11 | spec: 12 | destination: 13 | namespace: databases 14 | server: {{ .Values.spec.destination.server }} 15 | project: default 16 | source: 17 | path: cluster/apps/postgres 18 | repoURL: {{ .Values.spec.source.repoURL }} 19 | targetRevision: {{ .Values.spec.source.targetRevision }} 20 | syncPolicy: 21 | automated: 22 | prune: true 23 | selfHeal: true 24 | syncOptions: 25 | - CreateNamespace=true 26 | - RespectSyncWave=true 27 | retry: 28 | limit: 5 29 | backoff: 30 | duration: 5s 31 | factor: 2 32 | maxDuration: 3m 33 | -------------------------------------------------------------------------------- /cluster/apps/main/templates/redis.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: redis 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | annotations: 10 | argocd.argoproj.io/sync-wave: "1" 11 | spec: 12 | destination: 13 | namespace: databases 14 | server: {{ .Values.spec.destination.server }} 15 | project: default 16 | source: 17 | path: cluster/apps/redis 18 | repoURL: {{ .Values.spec.source.repoURL }} 19 | targetRevision: {{ .Values.spec.source.targetRevision }} 20 | syncPolicy: 21 | automated: 22 | prune: true 23 | selfHeal: true 24 | syncOptions: 25 | - CreateNamespace=true 26 | -------------------------------------------------------------------------------- /cluster/apps/main/templates/romm.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: romm 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | annotations: 10 | argocd.argoproj.io/sync-wave: "5" 11 | spec: 12 | destination: 13 | namespace: apps 14 | server: {{ .Values.spec.destination.server }} 15 | project: default 16 | source: 17 | path: cluster/apps/romm 18 | repoURL: {{ .Values.spec.source.repoURL }} 19 | targetRevision: {{ .Values.spec.source.targetRevision }} 20 | syncPolicy: 21 | automated: 22 | prune: true 23 | selfHeal: true 24 | syncOptions: 25 | - CreateNamespace=true 26 | -------------------------------------------------------------------------------- /cluster/apps/main/templates/whoami.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: whoami 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | annotations: 10 | argocd.argoproj.io/sync-wave: "5" 11 | spec: 12 | destination: 13 | namespace: apps 14 | server: {{ .Values.spec.destination.server }} 15 | project: default 16 | source: 17 | path: cluster/apps/whoami 18 | repoURL: {{ .Values.spec.source.repoURL }} 19 | targetRevision: {{ .Values.spec.source.targetRevision }} 20 | syncPolicy: 21 | automated: 22 | prune: true 23 | selfHeal: true 24 | syncOptions: 25 | - CreateNamespace=true 26 | -------------------------------------------------------------------------------- /cluster/apps/main/values.yaml: -------------------------------------------------------------------------------- 1 | spec: 2 | destination: 3 | server: https://kubernetes.default.svc 4 | source: 5 | repoURL: https://github.com/omdv/homelab-server 6 | targetRevision: HEAD 7 | -------------------------------------------------------------------------------- /cluster/apps/mariadb/Chart.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v2 3 | name: my-mariadb-chart 4 | type: application 5 | version: 0.1.0 6 | appVersion: "1.0" 7 | dependencies: 8 | - name: mariadb 9 | version: 20.2.1 10 | repository: https://charts.bitnami.com/bitnami 11 | -------------------------------------------------------------------------------- /cluster/apps/mariadb/templates/secret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: external-secrets.io/v1beta1 3 | kind: ExternalSecret 4 | metadata: 5 | name: mariadb-external-secret 6 | spec: 7 | refreshInterval: "15s" 8 | secretStoreRef: 9 | name: vault-backend 10 | kind: ClusterSecretStore 11 | target: 12 | name: mariadb-secret 13 | data: 14 | - secretKey: mariadb-root-password 15 | remoteRef: 16 | key: secret/mariadb 17 | property: VAULT_MARIADB_PASSWORD 18 | -------------------------------------------------------------------------------- /cluster/apps/mariadb/templates/volumes.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: PersistentVolume 4 | metadata: 5 | name: pv-mariadb 6 | 7 | spec: 8 | nodeAffinity: 9 | required: 10 | nodeSelectorTerms: 11 | - matchExpressions: 12 | - key: node-role.kubernetes.io/control-plane 13 | operator: Exists 14 | capacity: 15 | storage: 1Ti 16 | storageClassName: local-path 17 | accessModes: 18 | - ReadWriteOnce 19 | hostPath: 20 | path: /pool/databases/mariadb 21 | 22 | --- 23 | apiVersion: v1 24 | kind: PersistentVolumeClaim 25 | metadata: 26 | name: pvc-mariadb 27 | 28 | spec: 29 | storageClassName: local-path 30 | accessModes: 31 | - ReadWriteOnce 32 | resources: 33 | requests: 34 | storage: 1Ti 35 | volumeName: pv-mariadb 36 | -------------------------------------------------------------------------------- /cluster/apps/mariadb/values.yaml: -------------------------------------------------------------------------------- 1 | # https://github.com/bitnami/charts/blob/main/bitnami/mariadb/values.yaml 2 | mariadb: 3 | image: 4 | registry: docker.io 5 | repository: bitnami/mariadb 6 | tag: 11.4.5 7 | digest: "" 8 | pullPolicy: IfNotPresent 9 | 10 | architecture: standalone 11 | auth: 12 | existingSecret: mariadb-secret 13 | 14 | primary: 15 | configuration: |- 16 | [mysqld] 17 | skip-name-resolve 18 | explicit_defaults_for_timestamp 19 | basedir=/opt/bitnami/mariadb 20 | datadir=/bitnami/mariadb/data 21 | plugin_dir=/opt/bitnami/mariadb/plugin 22 | port={{ .Values.primary.containerPorts.mysql }} 23 | socket=/opt/bitnami/mariadb/tmp/mysql.sock 24 | tmpdir=/opt/bitnami/mariadb/tmp 25 | max_allowed_packet=16M 26 | bind-address=* 27 | pid-file=/opt/bitnami/mariadb/tmp/mysqld.pid 28 | log-error=/opt/bitnami/mariadb/logs/mysqld.log 29 | character-set-server=UTF8 30 | collation-server=utf8_general_ci 31 | slow_query_log=0 32 | long_query_time=10.0 33 | binlog_expire_logs_seconds=2592000 34 | {{- if .Values.tls.enabled }} 35 | ssl_cert=/opt/bitnami/mariadb/certs/{{ .Values.tls.certFilename }} 36 | ssl_key=/opt/bitnami/mariadb/certs/{{ .Values.tls.certKeyFilename }} 37 | {{- if (include "mariadb.tlsCACert" .) }} 38 | ssl_ca={{ include "mariadb.tlsCACert" . }} 39 | {{- end }} 40 | {{- end }} 41 | 42 | podSecurityContext: 43 | runAsUser: 1000 44 | runAsGroup: 1000 45 | fsGroup: 1000 46 | 47 | resources: 48 | requests: 49 | cpu: 2 50 | memory: 512Mi 51 | limits: 52 | cpu: 3 53 | memory: 1024Mi 54 | 55 | livenessProbe: 56 | enabled: true 57 | initialDelaySeconds: 120 58 | periodSeconds: 10 59 | timeoutSeconds: 1 60 | failureThreshold: 3 61 | successThreshold: 1 62 | 63 | readinessProbe: 64 | enabled: true 65 | initialDelaySeconds: 30 66 | periodSeconds: 10 67 | timeoutSeconds: 1 68 | failureThreshold: 3 69 | successThreshold: 1 70 | 71 | persistence: 72 | enabled: true 73 | existingClaim: pvc-mariadb 74 | 75 | service: 76 | type: ClusterIP 77 | ports: 78 | mysql: 3306 79 | metrics: 9104 80 | nodePorts: 81 | mysql: "" 82 | clusterIP: "" 83 | 84 | volumePermissions: 85 | enabled: true 86 | image: 87 | registry: docker.io 88 | repository: bitnami/os-shell 89 | tag: 12-debian-12-r34 90 | digest: "" 91 | pullPolicy: IfNotPresent 92 | resourcesPreset: "nano" 93 | 94 | metrics: 95 | enabled: true 96 | image: 97 | registry: docker.io 98 | repository: bitnami/mysqld-exporter 99 | tag: 0.16.0-debian-12-r3 100 | digest: "" 101 | pullPolicy: IfNotPresent 102 | 103 | annotations: 104 | prometheus.io/scrape: "true" 105 | prometheus.io/port: "9104" 106 | -------------------------------------------------------------------------------- /cluster/apps/mealie/configmap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: mealie-config 5 | labels: 6 | app: mealie 7 | data: 8 | ALLOW_SIGNUP: "true" 9 | PUID: "1000" 10 | PGID: "1000" 11 | TZ: "America/Chicago" 12 | MAX_WORKERS: "1" 13 | WEB_CONCURRENCY: "1" 14 | BASE_URL: "https://recipes.kblb.io" 15 | -------------------------------------------------------------------------------- /cluster/apps/mealie/deployment.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: Deployment 3 | apiVersion: apps/v1 4 | metadata: 5 | name: mealie 6 | labels: 7 | app: mealie 8 | 9 | spec: 10 | replicas: 1 11 | selector: 12 | matchLabels: 13 | app: mealie 14 | template: 15 | metadata: 16 | labels: 17 | app: mealie 18 | spec: 19 | containers: 20 | - name: mealie 21 | image: ghcr.io/mealie-recipes/mealie:v3.1.1 22 | envFrom: 23 | - configMapRef: 24 | name: mealie-config 25 | ports: 26 | - containerPort: 9000 27 | protocol: TCP 28 | name: http 29 | volumeMounts: 30 | - mountPath: /app/data 31 | name: data-volume 32 | resources: 33 | requests: 34 | cpu: "250m" 35 | memory: "256Mi" 36 | limits: 37 | cpu: "500m" 38 | memory: "512Mi" 39 | 40 | volumes: 41 | - name: data-volume 42 | persistentVolumeClaim: 43 | claimName: pvc-mealie 44 | -------------------------------------------------------------------------------- /cluster/apps/mealie/ingress.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: networking.k8s.io/v1 3 | kind: Ingress 4 | metadata: 5 | name: mealie 6 | labels: 7 | app: mealie 8 | annotations: 9 | cert-manager.io/cluster-issuer: "letsencrypt-prod" 10 | nginx.ingress.kubernetes.io/auth-url: "https://auth.kblb.io/oauth2/auth" 11 | nginx.ingress.kubernetes.io/auth-signin: "https://auth.kblb.io/oauth2/start?rd=https://$host$uri" 12 | hajimari.io/enable: "true" 13 | hajimari.io/icon: "chef-hat" 14 | 15 | spec: 16 | ingressClassName: nginx 17 | tls: 18 | - hosts: 19 | - recipes.kblb.io 20 | secretName: my-certs-mealie 21 | rules: 22 | - host: recipes.kblb.io 23 | http: 24 | paths: 25 | - path: / 26 | pathType: Prefix 27 | backend: 28 | service: 29 | name: mealie 30 | port: 31 | name: http 32 | -------------------------------------------------------------------------------- /cluster/apps/mealie/kustomization.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | resources: 3 | - volumes.yaml 4 | - configmap.yaml 5 | - service.yaml 6 | - deployment.yaml 7 | - ingress.yaml 8 | -------------------------------------------------------------------------------- /cluster/apps/mealie/service.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: mealie 6 | labels: 7 | app: mealie 8 | 9 | spec: 10 | ports: 11 | - name: http 12 | protocol: TCP 13 | port: 9000 14 | targetPort: http 15 | selector: 16 | app: mealie 17 | -------------------------------------------------------------------------------- /cluster/apps/mealie/volumes.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: PersistentVolume 4 | metadata: 5 | name: pv-mealie 6 | labels: 7 | app: mealie 8 | 9 | spec: 10 | nodeAffinity: 11 | required: 12 | nodeSelectorTerms: 13 | - matchExpressions: 14 | - key: node-role.kubernetes.io/control-plane 15 | operator: Exists 16 | capacity: 17 | storage: 1Gi 18 | storageClassName: local-path 19 | accessModes: 20 | - ReadWriteOnce 21 | hostPath: 22 | path: /pool/config/mealie 23 | 24 | --- 25 | apiVersion: v1 26 | kind: PersistentVolumeClaim 27 | metadata: 28 | name: pvc-mealie 29 | labels: 30 | app: mealie 31 | 32 | spec: 33 | storageClassName: local-path 34 | accessModes: 35 | - ReadWriteOnce 36 | resources: 37 | requests: 38 | storage: 1Gi 39 | volumeName: pv-mealie 40 | -------------------------------------------------------------------------------- /cluster/apps/metrics-prometheus/Chart.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v2 3 | name: my-metrics-prometheus 4 | type: application 5 | version: 0.1.0 6 | appVersion: "1.0" 7 | dependencies: 8 | - name: kube-prometheus-stack 9 | version: 69.3.1 10 | repository: https://prometheus-community.github.io/helm-charts 11 | -------------------------------------------------------------------------------- /cluster/apps/metrics-prometheus/templates/volumes.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: PersistentVolume 4 | metadata: 5 | name: pv-metrics-grafana 6 | 7 | spec: 8 | nodeAffinity: 9 | required: 10 | nodeSelectorTerms: 11 | - matchExpressions: 12 | - key: node-role.kubernetes.io/control-plane 13 | operator: Exists 14 | capacity: 15 | storage: 1Gi 16 | storageClassName: local-path 17 | accessModes: 18 | - ReadWriteOnce 19 | hostPath: 20 | path: /pool/config/metrics-grafana 21 | 22 | --- 23 | apiVersion: v1 24 | kind: PersistentVolumeClaim 25 | metadata: 26 | name: pvc-metrics-grafana 27 | 28 | spec: 29 | storageClassName: local-path 30 | accessModes: 31 | - ReadWriteOnce 32 | resources: 33 | requests: 34 | storage: 1Gi 35 | volumeName: pv-metrics-grafana 36 | -------------------------------------------------------------------------------- /cluster/apps/metrics-prometheus/values.yaml: -------------------------------------------------------------------------------- 1 | # https://github.com/prometheus-community/helm-charts/blob/main/charts/kube-prometheus-stack/values.yaml 2 | --- 3 | kube-prometheus-stack: 4 | fullnameOverride: prom 5 | prometheus: 6 | ingress: 7 | enabled: true 8 | ingressClassName: nginx 9 | annotations: 10 | cert-manager.io/cluster-issuer: "letsencrypt-prod" 11 | nginx.ingress.kubernetes.io/auth-url: "https://auth.kblb.io/oauth2/auth" 12 | nginx.ingress.kubernetes.io/auth-signin: "https://auth.kblb.io/oauth2/start?rd=https://$host$uri" 13 | hajimari.io/enable: "true" 14 | hajimari.io/appName: "prometheus" 15 | hajimari.io/icon: "chart-histogram" 16 | hosts: 17 | - prometheus.kblb.io 18 | paths: 19 | - / 20 | tls: 21 | - secretName: my-certs-prometheus 22 | hosts: 23 | - prometheus.kblb.io 24 | prometheusSpec: 25 | podMonitorSelectorNilUsesHelmValues: false 26 | serviceMonitorSelectorNilUsesHelmValues: false 27 | kubeStateMetrics: 28 | enabled: true 29 | prometheus-node-exporter: 30 | enabled: true 31 | kubeControllerManager: 32 | enabled: false 33 | kubeScheduler: 34 | enabled: false 35 | kubeProxy: 36 | enabled: false 37 | # https://github.com/grafana/helm-charts/blob/main/charts/grafana/values.yaml 38 | grafana: 39 | enabled: true 40 | adminPassword: password 41 | dashboardProviders: 42 | dashboardproviders.yaml: 43 | apiVersion: 1 44 | providers: 45 | - name: my-provider 46 | orgId: 1 47 | folder: '' 48 | type: file 49 | disableDeletion: true 50 | editable: true 51 | options: 52 | path: /var/lib/grafana/dashboards/my-provider 53 | ingress: 54 | enabled: true 55 | ingressClassName: nginx 56 | path: / 57 | hosts: 58 | - metrics.kblb.io 59 | annotations: 60 | cert-manager.io/cluster-issuer: "letsencrypt-prod" 61 | nginx.ingress.kubernetes.io/auth-url: "https://auth.kblb.io/oauth2/auth" 62 | nginx.ingress.kubernetes.io/auth-signin: "https://auth.kblb.io/oauth2/start?rd=https://$host$uri" 63 | hajimari.io/enable: "true" 64 | hajimari.io/appName: "metrics" 65 | hajimari.io/icon: "chart-box" 66 | tls: 67 | - hosts: 68 | - metrics.kblb.io 69 | secretName: my-certs-metrics 70 | persistence: 71 | enabled: true 72 | existingClaim: pvc-metrics-grafana 73 | resources: 74 | limits: 75 | cpu: 200m 76 | memory: 1024Mi 77 | requests: 78 | cpu: 100m 79 | memory: 512Mi 80 | alertmanager: 81 | enabled: false 82 | kubeEtcd: 83 | enabled: false 84 | -------------------------------------------------------------------------------- /cluster/apps/metrics-server/Chart.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v2 3 | name: my-metrics-server 4 | type: application 5 | version: 0.1.0 6 | appVersion: "1.0" 7 | dependencies: 8 | - name: metrics-server 9 | version: 3.8.2 10 | repository: https://kubernetes-sigs.github.io/metrics-server/ 11 | -------------------------------------------------------------------------------- /cluster/apps/metrics-server/values.yaml: -------------------------------------------------------------------------------- 1 | # https://raw.githubusercontent.com/kubernetes-sigs/metrics-server/master/charts/metrics-server/values.yaml 2 | --- 3 | metrics-server: 4 | image: 5 | repository: k8s.gcr.io/metrics-server/metrics-server 6 | pullPolicy: IfNotPresent 7 | 8 | fullnameOverride: "metrics" 9 | 10 | serviceAccount: 11 | create: true 12 | annotations: {} 13 | name: "" 14 | 15 | rbac: 16 | create: true 17 | pspEnabled: false 18 | 19 | apiService: 20 | create: true 21 | 22 | podSecurityContext: {} 23 | securityContext: 24 | allowPrivilegeEscalation: false 25 | readOnlyRootFilesystem: true 26 | runAsNonRoot: true 27 | runAsUser: 1000 28 | 29 | defaultArgs: 30 | - --cert-dir=/tmp 31 | - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname 32 | - --kubelet-use-node-status-port 33 | - --metric-resolution=15s 34 | - --kubelet-insecure-tls 35 | 36 | # livenessProbe: 37 | # httpGet: 38 | # path: /livez 39 | # port: https 40 | # scheme: HTTPS 41 | # initialDelaySeconds: 120 42 | # periodSeconds: 10 43 | # failureThreshold: 3 44 | 45 | # readinessProbe: 46 | # httpGet: 47 | # path: /readyz 48 | # port: https 49 | # scheme: HTTPS 50 | # initialDelaySeconds: 120 51 | # periodSeconds: 10 52 | # failureThreshold: 3 53 | 54 | service: 55 | type: ClusterIP 56 | port: 443 57 | annotations: {} 58 | labels: {} 59 | 60 | metrics: 61 | enabled: false 62 | 63 | serviceMonitor: 64 | enabled: false 65 | additionalLabels: {} 66 | interval: 1m 67 | scrapeTimeout: 10s 68 | 69 | resources: 70 | requests: 71 | cpu: 100m 72 | memory: 32Mi 73 | limits: 74 | cpu: 500m 75 | memory: 256Mi 76 | -------------------------------------------------------------------------------- /cluster/apps/mlflow/Chart.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v2 3 | name: my-mlflow-chart 4 | type: application 5 | version: 0.1.0 6 | appVersion: "1.0" 7 | dependencies: 8 | - name: mlflow 9 | version: 0.7.0 10 | repository: https://charts.bitnami.com/bitnami 11 | -------------------------------------------------------------------------------- /cluster/apps/mongodb/Chart.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v2 3 | name: my-mongodb-chart 4 | type: application 5 | version: 0.1.0 6 | appVersion: "1.0" 7 | dependencies: 8 | - name: mongodb 9 | version: 13.6.0 10 | repository: https://charts.bitnami.com/bitnami 11 | -------------------------------------------------------------------------------- /cluster/apps/mongodb/templates/external-secret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: external-secrets.io/v1beta1 3 | kind: ExternalSecret 4 | metadata: 5 | name: mongodb-external-secret 6 | spec: 7 | refreshInterval: "15s" 8 | secretStoreRef: 9 | name: vault-backend 10 | kind: ClusterSecretStore 11 | target: 12 | name: mongodb-secret 13 | data: 14 | - secretKey: mongodb-root-password 15 | remoteRef: 16 | key: secret/mongodb 17 | property: VAULT_MONGODB_PASSWORD 18 | -------------------------------------------------------------------------------- /cluster/apps/mongodb/templates/volumes.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: PersistentVolume 4 | metadata: 5 | name: pv-mongodb 6 | 7 | spec: 8 | nodeAffinity: 9 | required: 10 | nodeSelectorTerms: 11 | - matchExpressions: 12 | - key: node-role.kubernetes.io/control-plane 13 | operator: Exists 14 | capacity: 15 | storage: 100Gi 16 | storageClassName: local-path 17 | accessModes: 18 | - ReadWriteOnce 19 | hostPath: 20 | path: /pool/databases/mongodb 21 | 22 | --- 23 | apiVersion: v1 24 | kind: PersistentVolumeClaim 25 | metadata: 26 | name: pvc-mongodb 27 | 28 | spec: 29 | storageClassName: local-path 30 | accessModes: 31 | - ReadWriteOnce 32 | resources: 33 | requests: 34 | storage: 100Gi 35 | volumeName: pv-mongodb 36 | -------------------------------------------------------------------------------- /cluster/apps/mongodb/values.yaml: -------------------------------------------------------------------------------- 1 | # https://github.com/bitnami/charts/blob/main/bitnami/mongodb/values.yaml 2 | --- 3 | mongodb: 4 | image: 5 | registry: docker.io 6 | repository: bitnami/mongodb 7 | tag: 4.4.15-debian-10-r8 8 | digest: "" 9 | 10 | auth: 11 | enabled: true 12 | rootUser: root 13 | existingSecret: mongodb-secret 14 | 15 | resources: 16 | requests: 17 | memory: 256Mi 18 | cpu: 250m 19 | 20 | persistence: 21 | enabled: true 22 | existingClaim: "pvc-mongodb" 23 | mountPath: "/bitnami/mongodb" 24 | 25 | service: 26 | externalIPs: 27 | - 192.168.1.24 28 | 29 | volumePermissions: 30 | enabled: true 31 | image: 32 | registry: docker.io 33 | repository: bitnami/bitnami-shell 34 | tag: 11-debian-11-r61 35 | pullPolicy: IfNotPresent 36 | pullSecrets: [] 37 | resources: 38 | requests: 39 | memory: 8Mi 40 | cpu: 10m 41 | limits: 42 | memory: 16Mi 43 | cpu: 20m 44 | securityContext: 45 | runAsUser: 0 46 | 47 | # Snippet to create user and database 48 | # use sacred 49 | # db.createUser( 50 | # { 51 | # user: "sacred", 52 | # pwd: "sacred", // or cleartext password 53 | # roles: [ { role: "readWrite", db: "sacred" } ] 54 | # } 55 | # ) 56 | -------------------------------------------------------------------------------- /cluster/apps/n8n/Chart.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v2 3 | name: helm-n8n 4 | type: application 5 | version: 0.2.0 6 | appVersion: "1.0" 7 | dependencies: 8 | - name: n8n 9 | version: 1.0.15 10 | repository: oci://8gears.container-registry.com/library 11 | -------------------------------------------------------------------------------- /cluster/apps/n8n/templates/pv.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: PersistentVolume 4 | metadata: 5 | name: pv-n8n 6 | spec: 7 | nodeAffinity: 8 | required: 9 | nodeSelectorTerms: 10 | - matchExpressions: 11 | - key: node-role.kubernetes.io/control-plane 12 | operator: Exists 13 | capacity: 14 | storage: 100Gi 15 | storageClassName: local-path 16 | accessModes: 17 | - ReadWriteOnce 18 | hostPath: 19 | path: /pool/config/n8n 20 | -------------------------------------------------------------------------------- /cluster/apps/n8n/templates/pvc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: PersistentVolumeClaim 4 | metadata: 5 | name: pvc-n8n 6 | spec: 7 | storageClassName: local-path 8 | accessModes: 9 | - ReadWriteOnce 10 | resources: 11 | requests: 12 | storage: 100Gi 13 | volumeName: pv-n8n 14 | -------------------------------------------------------------------------------- /cluster/apps/nginx/deployments.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: Deployment 3 | apiVersion: apps/v1 4 | metadata: 5 | name: nginx 6 | labels: 7 | app: nginx 8 | 9 | spec: 10 | replicas: 2 11 | selector: 12 | matchLabels: 13 | app: nginx 14 | template: 15 | metadata: 16 | labels: 17 | app: nginx 18 | spec: 19 | containers: 20 | - name: nginx 21 | image: nginx:stable-alpine 22 | ports: 23 | - name: pod-http-port 24 | protocol: TCP 25 | containerPort: 80 26 | volumeMounts: 27 | - mountPath: /usr/share/nginx/html 28 | name: storage-volume 29 | resources: 30 | requests: 31 | cpu: "10m" 32 | memory: "10Mi" 33 | limits: 34 | cpu: "20m" 35 | memory: "20Mi" 36 | volumes: 37 | - name: storage-volume 38 | persistentVolumeClaim: 39 | claimName: pvc-nginx 40 | -------------------------------------------------------------------------------- /cluster/apps/nginx/ingress.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: networking.k8s.io/v1 3 | kind: Ingress 4 | metadata: 5 | name: nginx 6 | labels: 7 | app: nginx 8 | annotations: 9 | cert-manager.io/cluster-issuer: "letsencrypt-prod" 10 | 11 | spec: 12 | ingressClassName: nginx 13 | tls: 14 | - hosts: 15 | - kblb.io 16 | secretName: my-certs-main 17 | rules: 18 | - host: kblb.io 19 | http: 20 | paths: 21 | - path: / 22 | pathType: Prefix 23 | backend: 24 | service: 25 | name: nginx 26 | port: 27 | name: http 28 | -------------------------------------------------------------------------------- /cluster/apps/nginx/kustomization.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | resources: 3 | - volumes.yaml 4 | - services.yaml 5 | - deployments.yaml 6 | - ingress.yaml 7 | -------------------------------------------------------------------------------- /cluster/apps/nginx/services.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: nginx 6 | labels: 7 | app: nginx 8 | 9 | spec: 10 | ports: 11 | - name: http 12 | protocol: TCP 13 | port: 80 14 | targetPort: pod-http-port 15 | selector: 16 | app: nginx 17 | -------------------------------------------------------------------------------- /cluster/apps/nginx/volumes.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: PersistentVolume 4 | metadata: 5 | name: pv-nginx 6 | labels: 7 | app: nginx 8 | 9 | spec: 10 | nodeAffinity: 11 | required: 12 | nodeSelectorTerms: 13 | - matchExpressions: 14 | - key: node-role.kubernetes.io/control-plane 15 | operator: Exists 16 | capacity: 17 | storage: 10Mi 18 | storageClassName: local-path 19 | accessModes: 20 | - ReadWriteOnce 21 | hostPath: 22 | path: /pool/config/nginx 23 | 24 | --- 25 | apiVersion: v1 26 | kind: PersistentVolumeClaim 27 | metadata: 28 | name: pvc-nginx 29 | labels: 30 | app: nginx 31 | 32 | spec: 33 | storageClassName: local-path 34 | accessModes: 35 | - ReadWriteOnce 36 | resources: 37 | requests: 38 | storage: 10Mi 39 | volumeName: pv-nginx 40 | -------------------------------------------------------------------------------- /cluster/apps/nocodb/configmap.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: nocodb-config 6 | labels: 7 | app: nocodb 8 | 9 | data: 10 | TZ: "America/Chicago" 11 | NC_PUBLIC_URL: "https://nocodb.kblb.io" 12 | NC_DB: "pg://postgresql.databases.svc.cluster.local:5432?u=nocodb&p=nocodb&d=nocodb" 13 | NC_DISABLE_TELE: "true" 14 | -------------------------------------------------------------------------------- /cluster/apps/nocodb/deployment.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: Deployment 3 | apiVersion: apps/v1 4 | metadata: 5 | name: nocodb 6 | labels: 7 | app: nocodb 8 | 9 | spec: 10 | replicas: 1 11 | selector: 12 | matchLabels: 13 | app: nocodb 14 | template: 15 | metadata: 16 | labels: 17 | app: nocodb 18 | spec: 19 | containers: 20 | - name: nocodb 21 | image: nocodb/nocodb:latest 22 | ports: 23 | - name: http 24 | protocol: TCP 25 | containerPort: 8080 26 | envFrom: 27 | - configMapRef: 28 | name: nocodb-config 29 | volumeMounts: 30 | - mountPath: /usr/app/data 31 | name: data 32 | resources: 33 | requests: 34 | cpu: 200m 35 | memory: 128Mi 36 | limits: 37 | cpu: 1000m 38 | memory: 512Mi 39 | volumes: 40 | - name: data 41 | persistentVolumeClaim: 42 | claimName: pvc-nocodb 43 | -------------------------------------------------------------------------------- /cluster/apps/nocodb/ingress.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: networking.k8s.io/v1 3 | kind: Ingress 4 | metadata: 5 | name: nocodb 6 | labels: 7 | app: nocodb 8 | annotations: 9 | cert-manager.io/cluster-issuer: "letsencrypt-prod" 10 | nginx.ingress.kubernetes.io/auth-url: "https://auth.kblb.io/oauth2/auth" 11 | nginx.ingress.kubernetes.io/auth-signin: "https://auth.kblb.io/oauth2/start?rd=https://$host$uri" 12 | hajimari.io/enable: "true" 13 | hajimari.io/icon: "google-spreadsheet" 14 | 15 | spec: 16 | ingressClassName: nginx 17 | tls: 18 | - hosts: 19 | - nocodb.kblb.io 20 | secretName: my-certs-nocodb 21 | rules: 22 | - host: nocodb.kblb.io 23 | http: 24 | paths: 25 | - path: / 26 | pathType: Prefix 27 | backend: 28 | service: 29 | name: nocodb 30 | port: 31 | name: http 32 | -------------------------------------------------------------------------------- /cluster/apps/nocodb/kustomization.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | resources: 3 | - configmap.yaml 4 | - volumes.yaml 5 | - deployment.yaml 6 | - service.yaml 7 | - ingress.yaml 8 | -------------------------------------------------------------------------------- /cluster/apps/nocodb/service.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: nocodb 6 | labels: 7 | app: nocodb 8 | 9 | spec: 10 | ports: 11 | - name: http 12 | protocol: TCP 13 | port: 8080 14 | targetPort: http 15 | selector: 16 | app: nocodb 17 | -------------------------------------------------------------------------------- /cluster/apps/nocodb/volumes.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: PersistentVolume 4 | metadata: 5 | name: pv-nocodb 6 | labels: 7 | app: nocodb 8 | 9 | spec: 10 | nodeAffinity: 11 | required: 12 | nodeSelectorTerms: 13 | - matchExpressions: 14 | - key: node-role.kubernetes.io/control-plane 15 | operator: Exists 16 | capacity: 17 | storage: 100Gi 18 | storageClassName: local-path 19 | accessModes: 20 | - ReadWriteOnce 21 | hostPath: 22 | path: /pool/config/nocodb 23 | 24 | --- 25 | apiVersion: v1 26 | kind: PersistentVolumeClaim 27 | metadata: 28 | name: pvc-nocodb 29 | labels: 30 | app: nocodb 31 | 32 | spec: 33 | storageClassName: local-path 34 | accessModes: 35 | - ReadWriteOnce 36 | resources: 37 | requests: 38 | storage: 100Gi 39 | volumeName: pv-nocodb 40 | -------------------------------------------------------------------------------- /cluster/apps/oauth2-proxy/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": { 3 | "name": "oauth2-proxy", 4 | "path": "cluster/base/oauth2-proxy", 5 | "namespace": "networking" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /cluster/apps/oauth2-proxy/deployment.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | labels: 6 | app: oauth2-proxy 7 | name: oauth2-proxy 8 | spec: 9 | replicas: 1 10 | selector: 11 | matchLabels: 12 | app: oauth2-proxy 13 | template: 14 | metadata: 15 | labels: 16 | app: oauth2-proxy 17 | spec: 18 | containers: 19 | - args: 20 | - --provider=google 21 | - --upstream=file:///dev/null 22 | - --http-address=0.0.0.0:4180 23 | - --cookie-domain=.kblb.io 24 | - --whitelist-domain=.kblb.io 25 | - --authenticated-emails-file=/volume/emails 26 | envFrom: 27 | - secretRef: 28 | name: oauth2-secret 29 | image: quay.io/oauth2-proxy/oauth2-proxy:v7.7.1 30 | imagePullPolicy: Always 31 | name: oauth2-proxy 32 | ports: 33 | - name: http-pod-port 34 | containerPort: 4180 35 | protocol: TCP 36 | volumeMounts: 37 | - mountPath: /volume 38 | name: oauth2-emails 39 | resources: 40 | requests: 41 | cpu: "20m" 42 | memory: "32Mi" 43 | limits: 44 | cpu: "40m" 45 | memory: "64Mi" 46 | volumes: 47 | - name: oauth2-emails 48 | secret: 49 | secretName: oauth2-secret 50 | items: 51 | - key: EMAIL_WHITELIST 52 | path: emails 53 | -------------------------------------------------------------------------------- /cluster/apps/oauth2-proxy/external-secret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: external-secrets.io/v1beta1 3 | kind: ExternalSecret 4 | metadata: 5 | name: oauth-external-secret 6 | spec: 7 | refreshInterval: "15s" 8 | secretStoreRef: 9 | name: vault-backend 10 | kind: ClusterSecretStore 11 | target: 12 | name: oauth2-secret 13 | data: 14 | - secretKey: OAUTH2_PROXY_CLIENT_ID 15 | remoteRef: 16 | key: secret/oauth2 17 | property: VAULT_OAUTH2_CLIENT_ID 18 | - secretKey: OAUTH2_PROXY_CLIENT_SECRET 19 | remoteRef: 20 | key: secret/oauth2 21 | property: VAULT_OAUTH2_CLIENT_SECRET 22 | - secretKey: OAUTH2_PROXY_COOKIE_SECRET 23 | remoteRef: 24 | key: secret/oauth2 25 | property: VAULT_OAUTH2_COOKIE_SECRET 26 | - secretKey: EMAIL_WHITELIST 27 | remoteRef: 28 | key: secret/oauth2 29 | property: VAULT_OAUTH2_EMAIL_WHITELIST 30 | -------------------------------------------------------------------------------- /cluster/apps/oauth2-proxy/ingress.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: networking.k8s.io/v1 3 | kind: Ingress 4 | metadata: 5 | name: oauth2-proxy 6 | labels: 7 | app: oauth2-proxy 8 | annotations: 9 | cert-manager.io/cluster-issuer: "letsencrypt-prod" 10 | 11 | spec: 12 | ingressClassName: nginx 13 | tls: 14 | - hosts: 15 | - auth.kblb.io 16 | secretName: my-certs-oauth2-proxy 17 | rules: 18 | - host: auth.kblb.io 19 | http: 20 | paths: 21 | - path: /oauth2 22 | pathType: Prefix 23 | backend: 24 | service: 25 | name: oauth2-proxy 26 | port: 27 | name: http 28 | -------------------------------------------------------------------------------- /cluster/apps/oauth2-proxy/kustomization.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | resources: 3 | - external-secret.yaml 4 | - deployment.yaml 5 | - service.yaml 6 | - ingress.yaml 7 | - pdb.yaml 8 | -------------------------------------------------------------------------------- /cluster/apps/oauth2-proxy/pdb.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: policy/v1 3 | kind: PodDisruptionBudget 4 | metadata: 5 | name: oauth2-proxy-pdb 6 | spec: 7 | maxUnavailable: 0 8 | selector: 9 | matchLabels: 10 | app: oauth2-proxy 11 | -------------------------------------------------------------------------------- /cluster/apps/oauth2-proxy/service.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | labels: 6 | app: oauth2-proxy 7 | name: oauth2-proxy 8 | spec: 9 | ports: 10 | - name: http 11 | port: 4180 12 | protocol: TCP 13 | targetPort: http-pod-port 14 | selector: 15 | app: oauth2-proxy 16 | -------------------------------------------------------------------------------- /cluster/apps/omniboard/deployment.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: Deployment 3 | apiVersion: apps/v1 4 | metadata: 5 | name: omniboard 6 | labels: 7 | app: omniboard 8 | 9 | spec: 10 | replicas: 1 11 | selector: 12 | matchLabels: 13 | app: omniboard 14 | template: 15 | metadata: 16 | labels: 17 | app: omniboard 18 | spec: 19 | containers: 20 | - name: omniboard 21 | image: vivekratnavel/omniboard:latest 22 | ports: 23 | - name: http 24 | containerPort: 9000 25 | protocol: TCP 26 | env: 27 | - name: "MONGO_URI" 28 | value: "mongodb://sacred:sacred@mongodb.mongodb.svc.cluster.local:27017/sacred" 29 | resources: 30 | requests: 31 | cpu: 5m 32 | memory: 64Mi 33 | limits: 34 | cpu: 20m 35 | memory: 256Mi 36 | -------------------------------------------------------------------------------- /cluster/apps/omniboard/ingress.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: networking.k8s.io/v1 3 | kind: Ingress 4 | metadata: 5 | name: omniboard 6 | labels: 7 | app: omniboard 8 | annotations: 9 | cert-manager.io/cluster-issuer: "letsencrypt-prod" 10 | nginx.ingress.kubernetes.io/auth-url: "https://auth.kblb.io/oauth2/auth" 11 | nginx.ingress.kubernetes.io/auth-signin: "https://auth.kblb.io/oauth2/start?rd=https://$host$uri" 12 | hajimari.io/enable: "true" 13 | 14 | spec: 15 | ingressClassName: nginx 16 | tls: 17 | - hosts: 18 | - omniboard.kblb.io 19 | secretName: my-certs-omniboard 20 | rules: 21 | - host: omniboard.kblb.io 22 | http: 23 | paths: 24 | - path: / 25 | pathType: Prefix 26 | backend: 27 | service: 28 | name: omniboard 29 | port: 30 | name: http 31 | -------------------------------------------------------------------------------- /cluster/apps/omniboard/kustomization.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | resources: 3 | - deployment.yaml 4 | - service.yaml 5 | - ingress.yaml 6 | -------------------------------------------------------------------------------- /cluster/apps/omniboard/service.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: omniboard 6 | labels: 7 | app: omniboard 8 | 9 | spec: 10 | ports: 11 | - name: http 12 | protocol: TCP 13 | port: 9000 14 | targetPort: http 15 | selector: 16 | app: omniboard 17 | -------------------------------------------------------------------------------- /cluster/apps/open-webui/Chart.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v2 3 | name: helm-openwebui 4 | type: application 5 | version: 0.1.0 6 | appVersion: "1.0" 7 | dependencies: 8 | - name: open-webui 9 | version: 8.9.0 10 | repository: https://open-webui.github.io/helm-charts 11 | -------------------------------------------------------------------------------- /cluster/apps/open-webui/templates/pv.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: PersistentVolume 4 | metadata: 5 | name: pv-open-webui 6 | labels: 7 | app: open-webui 8 | spec: 9 | nodeAffinity: 10 | required: 11 | nodeSelectorTerms: 12 | - matchExpressions: 13 | - key: node-role.kubernetes.io/control-plane 14 | operator: Exists 15 | capacity: 16 | storage: 100Gi 17 | storageClassName: local-path 18 | accessModes: 19 | - ReadWriteOnce 20 | hostPath: 21 | path: /pool/config/open-webui 22 | -------------------------------------------------------------------------------- /cluster/apps/open-webui/templates/pvc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: PersistentVolumeClaim 4 | metadata: 5 | name: pvc-open-webui 6 | labels: 7 | app: open-webui 8 | spec: 9 | storageClassName: local-path 10 | accessModes: 11 | - ReadWriteOnce 12 | resources: 13 | requests: 14 | storage: 100Gi 15 | volumeName: pv-open-webui 16 | -------------------------------------------------------------------------------- /cluster/apps/open-webui/values.yaml: -------------------------------------------------------------------------------- 1 | # https://github.com/open-webui/helm-charts/blob/main/charts/open-webui/values.yaml 2 | open-webui: 3 | ollama: 4 | enabled: false 5 | 6 | pipelines: 7 | enabled: false 8 | 9 | tika: 10 | enabled: false 11 | 12 | websocket: 13 | enabled: true 14 | manager: redis 15 | url: redis://redis-master.databases.svc.cluster.local:6379/0 16 | redis: 17 | enabled: false 18 | 19 | resources: {} 20 | 21 | ingress: 22 | enabled: true 23 | class: "nginx" 24 | annotations: 25 | cert-manager.io/cluster-issuer: "letsencrypt-prod" 26 | nginx.ingress.kubernetes.io/auth-url: "https://auth.kblb.io/oauth2/auth" 27 | nginx.ingress.kubernetes.io/auth-signin: "https://auth.kblb.io/oauth2/start?rd=https://$host$uri" 28 | hajimari.io/enable: "true" 29 | hajimari.io/icon: "assistant" 30 | hajimari.io/title: "LLM Chat" 31 | host: "chat.kblb.io" 32 | tls: true 33 | 34 | persistence: 35 | enabled: true 36 | existingClaim: "pvc-open-webui" 37 | 38 | enableOpenaiApi: true 39 | openaiBaseApiUrl: "https://openrouter.ai/api/v1" 40 | -------------------------------------------------------------------------------- /cluster/apps/paperless/Chart.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v2 3 | name: helm-paperless 4 | type: application 5 | version: 0.2.0 6 | appVersion: "1.0" 7 | dependencies: 8 | - name: paperless 9 | version: 9.1.3 10 | repository: https://k8s-at-home.com/charts/ 11 | -------------------------------------------------------------------------------- /cluster/apps/paperless/templates/secret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: paperless-secret 6 | labels: 7 | app: paperless 8 | type: Opaque 9 | data: 10 | PAPERLESS_SECRET_KEY: {{ randAlphaNum 16 | b64enc | quote }} 11 | -------------------------------------------------------------------------------- /cluster/apps/paperless/templates/volumes.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: PersistentVolume 4 | metadata: 5 | name: pv-paperless-data 6 | labels: 7 | app: paperless 8 | 9 | spec: 10 | nodeAffinity: 11 | required: 12 | nodeSelectorTerms: 13 | - matchExpressions: 14 | - key: node-role.kubernetes.io/control-plane 15 | operator: Exists 16 | capacity: 17 | storage: 100Gi 18 | storageClassName: local-path 19 | accessModes: 20 | - ReadWriteOnce 21 | hostPath: 22 | path: /pool/documents/paperless/data 23 | 24 | --- 25 | apiVersion: v1 26 | kind: PersistentVolumeClaim 27 | metadata: 28 | name: pvc-paperless-data 29 | labels: 30 | app: paperless 31 | 32 | spec: 33 | storageClassName: local-path 34 | accessModes: 35 | - ReadWriteOnce 36 | resources: 37 | requests: 38 | storage: 100Gi 39 | volumeName: pv-paperless-data 40 | 41 | --- 42 | apiVersion: v1 43 | kind: PersistentVolume 44 | metadata: 45 | name: pv-paperless-media 46 | labels: 47 | app: paperless 48 | 49 | spec: 50 | nodeAffinity: 51 | required: 52 | nodeSelectorTerms: 53 | - matchExpressions: 54 | - key: node-role.kubernetes.io/control-plane 55 | operator: Exists 56 | capacity: 57 | storage: 100Gi 58 | storageClassName: local-path 59 | accessModes: 60 | - ReadWriteOnce 61 | hostPath: 62 | path: /pool/documents/paperless/media 63 | 64 | --- 65 | apiVersion: v1 66 | kind: PersistentVolumeClaim 67 | metadata: 68 | name: pvc-paperless-media 69 | labels: 70 | app: paperless 71 | 72 | spec: 73 | storageClassName: local-path 74 | accessModes: 75 | - ReadWriteOnce 76 | resources: 77 | requests: 78 | storage: 100Gi 79 | volumeName: pv-paperless-media 80 | 81 | --- 82 | apiVersion: v1 83 | kind: PersistentVolume 84 | metadata: 85 | name: pv-paperless-consume 86 | labels: 87 | app: paperless 88 | 89 | spec: 90 | nodeAffinity: 91 | required: 92 | nodeSelectorTerms: 93 | - matchExpressions: 94 | - key: node-role.kubernetes.io/control-plane 95 | operator: Exists 96 | capacity: 97 | storage: 10Gi 98 | storageClassName: local-path 99 | accessModes: 100 | - ReadWriteOnce 101 | hostPath: 102 | path: /pool/documents/scanned_files 103 | 104 | --- 105 | apiVersion: v1 106 | kind: PersistentVolumeClaim 107 | metadata: 108 | name: pvc-paperless-consume 109 | labels: 110 | app: paperless 111 | 112 | spec: 113 | storageClassName: local-path 114 | accessModes: 115 | - ReadWriteOnce 116 | resources: 117 | requests: 118 | storage: 10Gi 119 | volumeName: pv-paperless-consume 120 | -------------------------------------------------------------------------------- /cluster/apps/paperless/values.yaml: -------------------------------------------------------------------------------- 1 | #common: https://github.com/k8s-at-home/library-charts/tree/main/charts/stable/common 2 | --- 3 | paperless: 4 | image: 5 | repository: ghcr.io/paperless-ngx/paperless-ngx 6 | tag: 2.12.0@sha256:7a1d34bfaba5243aa4398d3b8abadc7234b6aa844837b329d598bed5ca17a0a9 7 | pullPolicy: IfNotPresent 8 | 9 | envFrom: 10 | - secretRef: 11 | name: paperless-secret 12 | env: 13 | PAPERLESS_REDIS: "redis://redis-master.databases.svc.cluster.local:6379" 14 | PAPERLESS_DBHOST: "postgresql.databases.svc.cluster.local" 15 | PAPERLESS_DBPORT: 5432 16 | PAPERLESS_TIME_ZONE: "America/Chicago" 17 | PAPERLESS_URL: "https://paperless.kblb.io" 18 | PAPERLESS_ALLOWED_HOSTS: "https://paperless.kblb.io" 19 | PAPERLESS_CORS_ALLOWED_HOSTS: "https://paperless.kblb.io" 20 | PAPERLESS_OCR_LANGUAGES: "eng" 21 | PAPERLESS_PORT: 8000 22 | 23 | service: 24 | main: 25 | annotations: 26 | tailscale.com/expose: "true" 27 | ports: 28 | http: 29 | port: 80 30 | targetPort: 8000 31 | 32 | ingress: 33 | main: 34 | enabled: true 35 | ingressClassName: nginx 36 | hosts: 37 | - host: paperless.kblb.io 38 | paths: 39 | - path: / 40 | pathType: Prefix 41 | annotations: 42 | cert-manager.io/cluster-issuer: "letsencrypt-prod" 43 | nginx.ingress.kubernetes.io/auth-url: "https://auth.kblb.io/oauth2/auth" 44 | nginx.ingress.kubernetes.io/auth-signin: "https://auth.kblb.io/oauth2/start?rd=https://$host$uri" 45 | hajimari.io/enable: "true" 46 | hajimari.io/icon: "text-box-search" 47 | tls: 48 | - hosts: 49 | - paperless.kblb.io 50 | secretName: my-certs-paperless 51 | 52 | persistence: 53 | data: 54 | enabled: true 55 | existingClaim: pvc-paperless-data 56 | media: 57 | enabled: true 58 | existingClaim: pvc-paperless-media 59 | consume: 60 | enabled: true 61 | existingClaim: pvc-paperless-consume 62 | 63 | resources: 64 | requests: 65 | cpu: "500m" 66 | memory: "512Mi" 67 | limits: 68 | cpu: "2000m" 69 | memory: "2048Mi" 70 | -------------------------------------------------------------------------------- /cluster/apps/pgbackup/configmap.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: pgbackup-config 6 | labels: 7 | app: pgbackup 8 | 9 | data: 10 | POSTGRES_HOST: "postgresql.databases.svc.cluster.local" 11 | POSTGRES_PORT: "5432" 12 | POSTGRES_DB: "paperless,sailboats,options" 13 | POSTGRES_USER: "postgres" 14 | POSTGRES_EXTRA_OPTS: "-Z9 --schema=public --blobs" 15 | SCHEDULE: "@every 0h30m00s" 16 | BACKUP_KEEP_DAYS: "7" 17 | BACKUP_KEEP_WEEKS: "4" 18 | BACKUP_KEEP_MONTHS: "6" 19 | -------------------------------------------------------------------------------- /cluster/apps/pgbackup/deployment.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: Deployment 3 | apiVersion: apps/v1 4 | metadata: 5 | name: pgbackup 6 | labels: 7 | app: pgbackup 8 | 9 | spec: 10 | replicas: 1 11 | selector: 12 | matchLabels: 13 | app: pgbackup 14 | template: 15 | metadata: 16 | labels: 17 | app: pgbackup 18 | spec: 19 | serviceAccountName: pgbackup 20 | affinity: 21 | nodeAffinity: 22 | requiredDuringSchedulingIgnoredDuringExecution: 23 | nodeSelectorTerms: 24 | - matchExpressions: 25 | - key: node-role.kubernetes.io/control-plane 26 | operator: Exists 27 | securityContext: 28 | fsGroup: 1000 29 | runAsUser: 1000 30 | runAsGroup: 1000 31 | runAsNonRoot: true 32 | initContainers: 33 | - name: volume-permissions 34 | image: busybox:1.37.0 35 | command: ["sh", "-c", "chown -R 1000:1000 /backups && chmod -R 755 /backups"] 36 | volumeMounts: 37 | - mountPath: /backups 38 | name: volume 39 | resources: 40 | requests: 41 | cpu: 10m 42 | memory: 10Mi 43 | limits: 44 | cpu: 100m 45 | memory: 100Mi 46 | containers: 47 | - name: pgbackup 48 | image: prodrigestivill/postgres-backup-local:17 49 | env: 50 | - name: POSTGRES_PASSWORD 51 | valueFrom: 52 | secretKeyRef: 53 | name: pgbackup-secret 54 | key: POSTGRES_PASSWORD 55 | envFrom: 56 | - configMapRef: 57 | name: pgbackup-config 58 | volumeMounts: 59 | - mountPath: /backups 60 | name: volume 61 | resources: 62 | requests: 63 | cpu: 50m 64 | memory: 16Mi 65 | limits: 66 | cpu: 100m 67 | memory: 64Mi 68 | securityContext: 69 | allowPrivilegeEscalation: false 70 | capabilities: 71 | drop: 72 | - ALL 73 | readOnlyRootFilesystem: true 74 | volumes: 75 | - name: volume 76 | persistentVolumeClaim: 77 | claimName: pvc-pgbackup 78 | -------------------------------------------------------------------------------- /cluster/apps/pgbackup/kustomization.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | resources: 3 | - configmap.yaml 4 | - secrets.yaml 5 | - volumes.yaml 6 | - deployment.yaml 7 | - service-account.yaml 8 | - network-policy.yaml 9 | -------------------------------------------------------------------------------- /cluster/apps/pgbackup/network-policy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: NetworkPolicy 3 | metadata: 4 | name: pgbackup-network-policy 5 | spec: 6 | podSelector: 7 | matchLabels: 8 | app: pgbackup 9 | policyTypes: 10 | - Egress 11 | egress: 12 | - to: 13 | - namespaceSelector: 14 | matchLabels: 15 | kubernetes.io/metadata.name: databases 16 | ports: 17 | - port: 5432 18 | protocol: TCP 19 | # Allow DNS resolution 20 | - to: 21 | - namespaceSelector: 22 | matchLabels: 23 | kubernetes.io/metadata.name: kube-system 24 | ports: 25 | - port: 53 26 | protocol: UDP 27 | - port: 53 28 | protocol: TCP 29 | -------------------------------------------------------------------------------- /cluster/apps/pgbackup/secrets.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: external-secrets.io/v1beta1 3 | kind: ExternalSecret 4 | metadata: 5 | name: pgbackup-external-secret 6 | spec: 7 | refreshInterval: "15s" 8 | secretStoreRef: 9 | name: vault-backend 10 | kind: ClusterSecretStore 11 | target: 12 | name: pgbackup-secret 13 | data: 14 | - secretKey: POSTGRES_PASSWORD 15 | remoteRef: 16 | key: secret/postgres 17 | property: VAULT_POSTGRES_PASSWORD 18 | -------------------------------------------------------------------------------- /cluster/apps/pgbackup/service-account.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: pgbackup 5 | labels: 6 | app: pgbackup 7 | -------------------------------------------------------------------------------- /cluster/apps/pgbackup/volumes.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: PersistentVolume 4 | metadata: 5 | name: pv-pgbackup 6 | labels: 7 | app: pgbackup 8 | 9 | spec: 10 | nodeAffinity: 11 | required: 12 | nodeSelectorTerms: 13 | - matchExpressions: 14 | - key: node-role.kubernetes.io/control-plane 15 | operator: Exists 16 | capacity: 17 | storage: 100Gi 18 | storageClassName: local-path 19 | accessModes: 20 | - ReadWriteOnce 21 | hostPath: 22 | path: /pool/databases/postgres-backup 23 | 24 | --- 25 | apiVersion: v1 26 | kind: PersistentVolumeClaim 27 | metadata: 28 | name: pvc-pgbackup 29 | labels: 30 | app: pgbackup 31 | 32 | spec: 33 | storageClassName: local-path 34 | accessModes: 35 | - ReadWriteOnce 36 | resources: 37 | requests: 38 | storage: 100Gi 39 | volumeName: pv-pgbackup 40 | -------------------------------------------------------------------------------- /cluster/apps/plex/Chart.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v2 3 | name: helm-plex 4 | type: application 5 | version: 0.2.0 6 | appVersion: "1.0" 7 | dependencies: 8 | - name: plex 9 | version: 6.3.3 10 | repository: https://k8s-at-home.com/charts/ 11 | -------------------------------------------------------------------------------- /cluster/apps/plex/templates/volumes.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: PersistentVolume 4 | metadata: 5 | name: pv-plex-config 6 | labels: 7 | app: plex 8 | 9 | spec: 10 | nodeAffinity: 11 | required: 12 | nodeSelectorTerms: 13 | - matchExpressions: 14 | - key: node-role.kubernetes.io/control-plane 15 | operator: Exists 16 | capacity: 17 | storage: 10Gi 18 | storageClassName: local-path 19 | accessModes: 20 | - ReadWriteOnce 21 | hostPath: 22 | path: /pool/config/plex/config 23 | 24 | --- 25 | apiVersion: v1 26 | kind: PersistentVolumeClaim 27 | metadata: 28 | name: pvc-plex-config 29 | labels: 30 | app: plex 31 | 32 | spec: 33 | storageClassName: local-path 34 | accessModes: 35 | - ReadWriteOnce 36 | resources: 37 | requests: 38 | storage: 10Gi 39 | volumeName: pv-plex-config 40 | 41 | --- 42 | apiVersion: v1 43 | kind: PersistentVolume 44 | metadata: 45 | name: pv-plex-transcode 46 | labels: 47 | app: plex 48 | 49 | spec: 50 | nodeAffinity: 51 | required: 52 | nodeSelectorTerms: 53 | - matchExpressions: 54 | - key: node-role.kubernetes.io/control-plane 55 | operator: Exists 56 | capacity: 57 | storage: 10Gi 58 | storageClassName: local-path 59 | accessModes: 60 | - ReadWriteOnce 61 | hostPath: 62 | path: /pool/config/plex/transcode 63 | 64 | --- 65 | apiVersion: v1 66 | kind: PersistentVolumeClaim 67 | metadata: 68 | name: pvc-plex-transcode 69 | labels: 70 | app: plex 71 | 72 | spec: 73 | storageClassName: local-path 74 | accessModes: 75 | - ReadWriteOnce 76 | resources: 77 | requests: 78 | storage: 10Gi 79 | volumeName: pv-plex-transcode 80 | 81 | --- 82 | apiVersion: v1 83 | kind: PersistentVolume 84 | metadata: 85 | name: pv-plex-media 86 | labels: 87 | app: plex 88 | 89 | spec: 90 | nodeAffinity: 91 | required: 92 | nodeSelectorTerms: 93 | - matchExpressions: 94 | - key: node-role.kubernetes.io/control-plane 95 | operator: Exists 96 | capacity: 97 | storage: 1Ti 98 | storageClassName: local-path 99 | accessModes: 100 | - ReadWriteOnce 101 | hostPath: 102 | path: /pool/media 103 | 104 | --- 105 | apiVersion: v1 106 | kind: PersistentVolumeClaim 107 | metadata: 108 | name: pvc-plex-media 109 | labels: 110 | app: plex 111 | 112 | spec: 113 | storageClassName: local-path 114 | accessModes: 115 | - ReadWriteOnce 116 | resources: 117 | requests: 118 | storage: 1Ti 119 | volumeName: pv-plex-media 120 | -------------------------------------------------------------------------------- /cluster/apps/plex/values.yaml: -------------------------------------------------------------------------------- 1 | # https://github.com/k8s-at-home/charts/blob/master/charts/stable/plex/values.yaml 2 | --- 3 | plex: 4 | 5 | image: 6 | repository: ghcr.io/onedr0p/plex 7 | pullPolicy: IfNotPresent 8 | tag: 1.40.1.8227-c0dd5a73e@sha256:c8d74539a40530fa9770c6d67f37aef8f3a7b3f30ee353c2cb5685b84ed5b04c 9 | 10 | env: 11 | TZ: "America/Chicago" 12 | ADVERTISE_IP: "192.168.1.24" 13 | 14 | service: 15 | main: 16 | primary: true 17 | ports: 18 | http: 19 | port: 32400 20 | dnla-tcp: 21 | enabled: false 22 | dnla-udp: 23 | enabled: false 24 | 25 | affinity: 26 | nodeAffinity: 27 | required: 28 | nodeSelectorTerms: 29 | - matchExpressions: 30 | - key: node-role.kubernetes.io/control-plane 31 | operator: Exists 32 | 33 | ingress: 34 | main: 35 | enabled: false 36 | 37 | hostNetwork: true 38 | 39 | persistence: 40 | config: 41 | enabled: true 42 | existingClaim: pvc-plex-config 43 | transcode: 44 | enabled: true 45 | existingClaim: pvc-plex-transcode 46 | media: 47 | enabled: true 48 | existingClaim: pvc-plex-media 49 | 50 | podSecurityContext: 51 | runAsUser: 1000 52 | runAsGroup: 998 53 | fsGroup: 998 54 | 55 | resources: 56 | requests: 57 | cpu: 500m 58 | memory: 128Mi 59 | limits: 60 | cpu: 3000m 61 | memory: 512Mi 62 | -------------------------------------------------------------------------------- /cluster/apps/postgres/Chart.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v2 3 | name: my-postgresql-chart 4 | type: application 5 | version: 0.1.0 6 | appVersion: "1.0" 7 | dependencies: 8 | - name: postgresql 9 | version: 11.6.20 10 | repository: https://charts.bitnami.com/bitnami 11 | -------------------------------------------------------------------------------- /cluster/apps/postgres/templates/external-secret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: external-secrets.io/v1beta1 3 | kind: ExternalSecret 4 | metadata: 5 | name: postgres-external-secret 6 | spec: 7 | refreshInterval: "15s" 8 | secretStoreRef: 9 | name: vault-backend 10 | kind: ClusterSecretStore 11 | target: 12 | name: postgres-secret 13 | data: 14 | - secretKey: postgres-password 15 | remoteRef: 16 | key: secret/postgres 17 | property: VAULT_POSTGRES_PASSWORD 18 | -------------------------------------------------------------------------------- /cluster/apps/postgres/templates/volumes.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: PersistentVolume 4 | metadata: 5 | name: pv-postgres 6 | 7 | spec: 8 | nodeAffinity: 9 | required: 10 | nodeSelectorTerms: 11 | - matchExpressions: 12 | - key: node-role.kubernetes.io/control-plane 13 | operator: Exists 14 | capacity: 15 | storage: 100Gi 16 | storageClassName: local-path 17 | accessModes: 18 | - ReadWriteOnce 19 | hostPath: 20 | path: /pool/databases/postgres 21 | 22 | --- 23 | apiVersion: v1 24 | kind: PersistentVolumeClaim 25 | metadata: 26 | name: pvc-postgres 27 | 28 | spec: 29 | storageClassName: local-path 30 | accessModes: 31 | - ReadWriteOnce 32 | resources: 33 | requests: 34 | storage: 100Gi 35 | volumeName: pv-postgres 36 | -------------------------------------------------------------------------------- /cluster/apps/postgres/values.yaml: -------------------------------------------------------------------------------- 1 | # https://github.com/bitnami/charts/blob/master/bitnami/postgresql/values.yaml 2 | --- 3 | postgresql: 4 | global: 5 | postgresql: 6 | auth: 7 | username: postgres 8 | existingSecret: "postgres-secret" 9 | 10 | fullnameOverride: "postgresql" 11 | image: 12 | registry: docker.io 13 | repository: bitnami/postgresql 14 | tag: "13.7.0" 15 | pullPolicy: IfNotPresent 16 | pullSecrets: [] 17 | debug: false 18 | 19 | architecture: "standalone" 20 | 21 | primary: 22 | service: 23 | type: "ClusterIP" 24 | ports: 25 | postgresql: 5432 26 | resources: 27 | limits: 28 | memory: 256Mi 29 | cpu: 500m 30 | requests: 31 | memory: 256Mi 32 | cpu: 250m 33 | persistence: 34 | enabled: true 35 | existingClaim: "pvc-postgres" 36 | mountPath: "/bitnami/postgresql" 37 | startupProbe: 38 | enabled: false 39 | initialDelaySeconds: 30 40 | periodSeconds: 15 41 | timeoutSeconds: 5 42 | failureThreshold: 10 43 | successThreshold: 1 44 | livenessProbe: 45 | enabled: false 46 | initialDelaySeconds: 30 47 | periodSeconds: 10 48 | timeoutSeconds: 5 49 | failureThreshold: 6 50 | successThreshold: 1 51 | readinessProbe: 52 | enabled: false 53 | initialDelaySeconds: 5 54 | periodSeconds: 10 55 | timeoutSeconds: 5 56 | failureThreshold: 6 57 | successThreshold: 1 58 | podSecurityContext: 59 | enabled: true 60 | fsGroup: 1000 61 | containerSecurityContext: 62 | enabled: true 63 | runAsUser: 1000 64 | 65 | volumePermissions: 66 | enabled: true 67 | image: 68 | registry: docker.io 69 | repository: bitnami/bitnami-shell 70 | tag: 10-debian-10-r305 71 | pullPolicy: IfNotPresent 72 | pullSecrets: [] 73 | resources: 74 | requests: 75 | memory: 8Mi 76 | cpu: 10m 77 | limits: 78 | memory: 16Mi 79 | cpu: 20m 80 | securityContext: 81 | runAsUser: 0 82 | -------------------------------------------------------------------------------- /cluster/apps/qbittorrent/configmap.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: qbittorrent-config 6 | data: 7 | PUID: "1000" 8 | PGID: "1000" 9 | TZ: "America/Chicago" 10 | WEBUI_PORT: "8080" 11 | TORRENTING_PORT: "18289" 12 | -------------------------------------------------------------------------------- /cluster/apps/qbittorrent/deployment.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: qbittorrent 6 | labels: 7 | app: qbittorrent 8 | spec: 9 | replicas: 1 10 | selector: 11 | matchLabels: 12 | app: qbittorrent 13 | template: 14 | metadata: 15 | labels: 16 | app: qbittorrent 17 | annotations: 18 | setGateway: "true" 19 | spec: 20 | initContainers: 21 | - name: update-volume-permission 22 | image: busybox:1.37.0 23 | imagePullPolicy: IfNotPresent 24 | resources: 25 | requests: 26 | memory: "64Mi" 27 | cpu: "50m" 28 | limits: 29 | memory: "128Mi" 30 | cpu: "100m" 31 | command: ["sh", "-c", "chown -R 1000:1000 /config", "chown -R 1000:1000 /downloads"] 32 | volumeMounts: 33 | - name: config 34 | mountPath: /config 35 | - name: downloads 36 | mountPath: /downloads 37 | envFrom: 38 | - configMapRef: 39 | name: qbittorrent-config 40 | securityContext: 41 | runAsUser: 0 42 | containers: 43 | - name: qbittorrent 44 | image: lscr.io/linuxserver/qbittorrent:4.6.7 45 | imagePullPolicy: IfNotPresent 46 | resources: 47 | requests: 48 | memory: "128Mi" 49 | cpu: "250m" 50 | limits: 51 | memory: "512Mi" 52 | cpu: "1000m" 53 | envFrom: 54 | - configMapRef: 55 | name: qbittorrent-config 56 | ports: 57 | - containerPort: 8080 58 | name: webui 59 | - containerPort: 18289 60 | name: torrent-tcp 61 | - containerPort: 18289 62 | protocol: UDP 63 | name: torrent-udp 64 | volumeMounts: 65 | - name: config 66 | mountPath: /config 67 | - name: downloads 68 | mountPath: /downloads 69 | volumes: 70 | - name: config 71 | persistentVolumeClaim: 72 | claimName: pvc-qbittorrent-config 73 | - name: downloads 74 | persistentVolumeClaim: 75 | claimName: pvc-qbittorrent-downloads 76 | -------------------------------------------------------------------------------- /cluster/apps/qbittorrent/ingress.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ingress for qbittorrent 3 | apiVersion: networking.k8s.io/v1 4 | kind: Ingress 5 | metadata: 6 | name: qbittorrent 7 | annotations: 8 | cert-manager.io/cluster-issuer: "letsencrypt-prod" 9 | nginx.ingress.kubernetes.io/auth-url: "https://auth.kblb.io/oauth2/auth" 10 | nginx.ingress.kubernetes.io/auth-signin: "https://auth.kblb.io/oauth2/start?rd=https://$host$uri" 11 | hajimari.io/enable: "true" 12 | hajimari.io/icon: "download-box" 13 | spec: 14 | ingressClassName: nginx 15 | tls: 16 | - hosts: 17 | - qb.kblb.io 18 | secretName: my-certs-qbittorrent 19 | rules: 20 | - host: qb.kblb.io 21 | http: 22 | paths: 23 | - path: / 24 | pathType: Prefix 25 | backend: 26 | service: 27 | name: qbittorrent 28 | port: 29 | number: 8080 30 | -------------------------------------------------------------------------------- /cluster/apps/qbittorrent/kustomization.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | resources: 3 | - configmap.yaml 4 | - service.yaml 5 | - ingress.yaml 6 | - volumes.yaml 7 | - deployment.yaml 8 | -------------------------------------------------------------------------------- /cluster/apps/qbittorrent/service.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: qbittorrent 6 | spec: 7 | selector: 8 | app: qbittorrent 9 | ports: 10 | - name: webui 11 | port: 8080 12 | targetPort: 8080 13 | - name: torrent-tcp 14 | port: 18289 15 | targetPort: 18289 16 | - name: torrent-udp 17 | port: 18289 18 | protocol: UDP 19 | targetPort: 18289 20 | type: ClusterIP 21 | -------------------------------------------------------------------------------- /cluster/apps/qbittorrent/volumes.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: PersistentVolume 4 | metadata: 5 | name: pv-qbittorrent-downloads 6 | labels: 7 | app: qbittorrent 8 | 9 | spec: 10 | nodeAffinity: 11 | required: 12 | nodeSelectorTerms: 13 | - matchExpressions: 14 | - key: node-role.kubernetes.io/control-plane 15 | operator: Exists 16 | capacity: 17 | storage: 1000Gi 18 | storageClassName: local-path 19 | accessModes: 20 | - ReadWriteOnce 21 | hostPath: 22 | path: /pool/downloads 23 | 24 | --- 25 | apiVersion: v1 26 | kind: PersistentVolumeClaim 27 | metadata: 28 | name: pvc-qbittorrent-downloads 29 | labels: 30 | app: qbittorrent 31 | 32 | spec: 33 | storageClassName: local-path 34 | accessModes: 35 | - ReadWriteOnce 36 | resources: 37 | requests: 38 | storage: 1000Gi 39 | volumeName: pv-qbittorrent-downloads 40 | 41 | --- 42 | apiVersion: v1 43 | kind: PersistentVolume 44 | metadata: 45 | name: pv-qbittorrent-config 46 | labels: 47 | app: qbittorrent 48 | 49 | spec: 50 | nodeAffinity: 51 | required: 52 | nodeSelectorTerms: 53 | - matchExpressions: 54 | - key: node-role.kubernetes.io/control-plane 55 | operator: Exists 56 | capacity: 57 | storage: 1000Gi 58 | storageClassName: local-path 59 | accessModes: 60 | - ReadWriteOnce 61 | hostPath: 62 | path: /pool/config/qbittorrent 63 | 64 | --- 65 | apiVersion: v1 66 | kind: PersistentVolumeClaim 67 | metadata: 68 | name: pvc-qbittorrent-config 69 | labels: 70 | app: qbittorrent 71 | 72 | spec: 73 | storageClassName: local-path 74 | accessModes: 75 | - ReadWriteOnce 76 | resources: 77 | requests: 78 | storage: 1000Gi 79 | volumeName: pv-qbittorrent-config 80 | -------------------------------------------------------------------------------- /cluster/apps/redis/Chart.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v2 3 | name: my-redis-chart 4 | type: application 5 | version: 0.1.0 6 | appVersion: "1.0" 7 | dependencies: 8 | - name: redis 9 | version: 16.13.2 10 | repository: https://charts.bitnami.com/bitnami 11 | -------------------------------------------------------------------------------- /cluster/apps/redis/values.yaml: -------------------------------------------------------------------------------- 1 | # https://github.com/bitnami/charts/blob/main/bitnami/redis/values.yaml 2 | --- 3 | redis: 4 | architecture: standalone 5 | auth: 6 | enabled: false 7 | master: 8 | resources: 9 | requests: 10 | cpu: 50m 11 | memory: 16Mi 12 | limits: 13 | cpu: 200m 14 | memory: 64Mi 15 | persistence: 16 | enabled: false 17 | automountServiceAccountToken: false 18 | service: 19 | type: ClusterIP 20 | ports: 21 | redis: 6379 22 | replica: 23 | replicaCount: 2 24 | resources: 25 | requests: 26 | cpu: 50m 27 | memory: 16Mi 28 | limits: 29 | cpu: 200m 30 | memory: 64Mi 31 | networkPolicy: 32 | enabled: true 33 | -------------------------------------------------------------------------------- /cluster/apps/romm/configmap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: romm-config 5 | data: 6 | DB_HOST: mariadb.databases.svc.cluster.local 7 | DB_NAME: romm 8 | DB_USER: romm 9 | DB_PASSWD: romm 10 | REDIS_HOST: redis-master.databases.svc.cluster.local 11 | ENABLE_RESCAN_ON_FILESYSTEM_CHANGE: "false" 12 | -------------------------------------------------------------------------------- /cluster/apps/romm/ingress.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: networking.k8s.io/v1 3 | kind: Ingress 4 | metadata: 5 | name: romm 6 | labels: 7 | app: romm 8 | annotations: 9 | cert-manager.io/cluster-issuer: "letsencrypt-prod" 10 | nginx.ingress.kubernetes.io/auth-url: "https://auth.kblb.io/oauth2/auth" 11 | nginx.ingress.kubernetes.io/auth-signin: "https://auth.kblb.io/oauth2/start?rd=https://$host$uri" 12 | hajimari.io/enable: "true" 13 | hajimari.io/icon: "nintendo-game-boy" 14 | 15 | spec: 16 | ingressClassName: nginx 17 | tls: 18 | - hosts: 19 | - romm.kblb.io 20 | secretName: my-certs-romm 21 | rules: 22 | - host: romm.kblb.io 23 | http: 24 | paths: 25 | - path: / 26 | pathType: Prefix 27 | backend: 28 | service: 29 | name: romm 30 | port: 31 | name: web 32 | -------------------------------------------------------------------------------- /cluster/apps/romm/kustomization.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | resources: 3 | - serviceaccount.yaml 4 | - network-policy.yaml 5 | - configmap.yaml 6 | - secrets.yaml 7 | - pv.yaml 8 | - pvc.yaml 9 | - deployment.yaml 10 | - service.yaml 11 | - ingress.yaml 12 | -------------------------------------------------------------------------------- /cluster/apps/romm/network-policy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: NetworkPolicy 3 | metadata: 4 | name: romm-network-policy 5 | spec: 6 | podSelector: 7 | matchLabels: 8 | app: romm 9 | policyTypes: 10 | - Ingress 11 | - Egress 12 | ingress: 13 | - ports: 14 | - port: 8080 15 | protocol: TCP 16 | egress: 17 | # Allow connection to databases namespace 18 | - to: 19 | - namespaceSelector: 20 | matchLabels: 21 | kubernetes.io/metadata.name: databases 22 | ports: 23 | - port: 6379 # redis 24 | protocol: TCP 25 | - port: 3306 # mariadb 26 | protocol: TCP 27 | # Allow DNS lookups 28 | - to: 29 | - namespaceSelector: {} 30 | podSelector: 31 | matchLabels: 32 | k8s-app: kube-dns 33 | ports: 34 | - port: 53 35 | protocol: UDP 36 | - port: 53 37 | protocol: TCP 38 | # Deny others 39 | - {} 40 | -------------------------------------------------------------------------------- /cluster/apps/romm/pv.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: PersistentVolume 4 | metadata: 5 | name: pv-romm-resources 6 | 7 | spec: 8 | nodeAffinity: 9 | required: 10 | nodeSelectorTerms: 11 | - matchExpressions: 12 | - key: node-role.kubernetes.io/control-plane 13 | operator: Exists 14 | capacity: 15 | storage: 100Gi 16 | storageClassName: local-path 17 | accessModes: 18 | - ReadWriteOnce 19 | hostPath: 20 | path: /pool/romm/resources 21 | 22 | --- 23 | apiVersion: v1 24 | kind: PersistentVolume 25 | metadata: 26 | name: pv-romm-cached-data 27 | 28 | spec: 29 | nodeAffinity: 30 | required: 31 | nodeSelectorTerms: 32 | - matchExpressions: 33 | - key: node-role.kubernetes.io/control-plane 34 | operator: Exists 35 | capacity: 36 | storage: 100Gi 37 | storageClassName: local-path 38 | accessModes: 39 | - ReadWriteOnce 40 | hostPath: 41 | path: /pool/romm/cached-data 42 | 43 | --- 44 | apiVersion: v1 45 | kind: PersistentVolume 46 | metadata: 47 | name: pv-romm-library 48 | 49 | spec: 50 | nodeAffinity: 51 | required: 52 | nodeSelectorTerms: 53 | - matchExpressions: 54 | - key: node-role.kubernetes.io/control-plane 55 | operator: Exists 56 | capacity: 57 | storage: 1Ti 58 | storageClassName: local-path 59 | accessModes: 60 | - ReadWriteOnce 61 | hostPath: 62 | path: /pool/romm/library 63 | 64 | --- 65 | apiVersion: v1 66 | kind: PersistentVolume 67 | metadata: 68 | name: pv-romm-assets 69 | 70 | spec: 71 | nodeAffinity: 72 | required: 73 | nodeSelectorTerms: 74 | - matchExpressions: 75 | - key: node-role.kubernetes.io/control-plane 76 | operator: Exists 77 | capacity: 78 | storage: 100Gi 79 | storageClassName: local-path 80 | accessModes: 81 | - ReadWriteOnce 82 | hostPath: 83 | path: /pool/romm/assets 84 | 85 | --- 86 | apiVersion: v1 87 | kind: PersistentVolume 88 | metadata: 89 | name: pv-romm-config 90 | 91 | spec: 92 | nodeAffinity: 93 | required: 94 | nodeSelectorTerms: 95 | - matchExpressions: 96 | - key: node-role.kubernetes.io/control-plane 97 | operator: Exists 98 | capacity: 99 | storage: 10Gi 100 | storageClassName: local-path 101 | accessModes: 102 | - ReadWriteOnce 103 | hostPath: 104 | path: /pool/romm/config 105 | -------------------------------------------------------------------------------- /cluster/apps/romm/pvc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: PersistentVolumeClaim 4 | metadata: 5 | name: pvc-romm-resources 6 | labels: 7 | app: romm 8 | 9 | spec: 10 | storageClassName: local-path 11 | accessModes: 12 | - ReadWriteOnce 13 | resources: 14 | requests: 15 | storage: 100Gi 16 | volumeName: pv-romm-resources 17 | 18 | --- 19 | apiVersion: v1 20 | kind: PersistentVolumeClaim 21 | metadata: 22 | name: pvc-romm-cached-data 23 | labels: 24 | app: romm 25 | 26 | spec: 27 | storageClassName: local-path 28 | accessModes: 29 | - ReadWriteOnce 30 | resources: 31 | requests: 32 | storage: 100Gi 33 | volumeName: pv-romm-cached-data 34 | 35 | --- 36 | apiVersion: v1 37 | kind: PersistentVolumeClaim 38 | metadata: 39 | name: pvc-romm-library 40 | labels: 41 | app: romm 42 | 43 | spec: 44 | storageClassName: local-path 45 | accessModes: 46 | - ReadWriteOnce 47 | resources: 48 | requests: 49 | storage: 1Ti 50 | volumeName: pv-romm-library 51 | 52 | --- 53 | apiVersion: v1 54 | kind: PersistentVolumeClaim 55 | metadata: 56 | name: pvc-romm-assets 57 | labels: 58 | app: romm 59 | 60 | spec: 61 | storageClassName: local-path 62 | accessModes: 63 | - ReadWriteOnce 64 | resources: 65 | requests: 66 | storage: 100Gi 67 | volumeName: pv-romm-assets 68 | 69 | --- 70 | apiVersion: v1 71 | kind: PersistentVolumeClaim 72 | metadata: 73 | name: pvc-romm-config 74 | labels: 75 | app: romm 76 | 77 | spec: 78 | storageClassName: local-path 79 | accessModes: 80 | - ReadWriteOnce 81 | resources: 82 | requests: 83 | storage: 10Gi 84 | volumeName: pv-romm-config 85 | -------------------------------------------------------------------------------- /cluster/apps/romm/secrets.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: external-secrets.io/v1beta1 3 | kind: ExternalSecret 4 | metadata: 5 | name: romm-external-secret 6 | spec: 7 | refreshInterval: "15s" 8 | secretStoreRef: 9 | name: vault-backend 10 | kind: ClusterSecretStore 11 | target: 12 | name: romm-secret 13 | data: 14 | - secretKey: ROMM_AUTH_SECRET_KEY 15 | remoteRef: 16 | key: secret/romm 17 | property: VAULT_ROMM_SECRET_KEY 18 | - secretKey: IGDB_CLIENT_ID 19 | remoteRef: 20 | key: secret/romm 21 | property: VAULT_ROMM_IGDB_CLIENT_ID 22 | - secretKey: IGDB_CLIENT_SECRET 23 | remoteRef: 24 | key: secret/romm 25 | property: VAULT_ROMM_IGDB_CLIENT_SECRET 26 | -------------------------------------------------------------------------------- /cluster/apps/romm/service.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: romm 6 | labels: 7 | app: romm 8 | 9 | spec: 10 | ports: 11 | - port: 8080 12 | name: web 13 | protocol: TCP 14 | targetPort: web 15 | selector: 16 | app: romm 17 | -------------------------------------------------------------------------------- /cluster/apps/romm/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: romm-service-account 5 | labels: 6 | app: romm 7 | -------------------------------------------------------------------------------- /cluster/apps/sailboats/deployment.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: scrapper 6 | labels: 7 | app: scrapper 8 | spec: 9 | replicas: 1 10 | selector: 11 | matchLabels: 12 | app: scrapper 13 | template: 14 | metadata: 15 | labels: 16 | app: scrapper 17 | spec: 18 | containers: 19 | - name: scrapper 20 | image: ghcr.io/omdv/sailboats-scrapper:latest 21 | imagePullPolicy: Always 22 | env: 23 | - name: PG_HOST 24 | value: postgresql.databases.svc.cluster.local 25 | resources: 26 | requests: 27 | cpu: "40m" 28 | memory: "32Mi" 29 | limits: 30 | cpu: "200m" 31 | memory: "256Mi" 32 | imagePullSecrets: 33 | - name: dockerconfigjson-github-com 34 | -------------------------------------------------------------------------------- /cluster/apps/sailboats/kustomization.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | resources: 3 | - deployment.yaml 4 | -------------------------------------------------------------------------------- /cluster/apps/secret-generator/Chart.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: my-secrets-chart 3 | apiVersion: v2 4 | version: 1.0.0 5 | dependencies: 6 | - name: kubernetes-secret-generator 7 | version: 3.3.4 8 | repository: https://helm.mittwald.de 9 | -------------------------------------------------------------------------------- /cluster/apps/secret-generator/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": { 3 | "name": "secret-generator", 4 | "path": "cluster/base/secret-generator", 5 | "namespace": "kube-system" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /cluster/apps/secret-generator/values.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kubernetes-secret-generator: 3 | imagePullSecrets: [] 4 | nameOverride: "" 5 | fullnameOverride: "" 6 | deploymentStrategy: "Recreate" 7 | 8 | securityContext: 9 | capabilities: 10 | drop: 11 | - ALL 12 | readOnlyRootFilesystem: true 13 | runAsNonRoot: true 14 | runAsUser: 1000 15 | 16 | resources: 17 | limits: 18 | cpu: 100m 19 | memory: 128Mi 20 | requests: 21 | cpu: 100m 22 | memory: 128Mi 23 | 24 | secretLength: 40 25 | watchNamespace: "" 26 | useMetricsService: false 27 | 28 | rbac: 29 | create: true 30 | clusterRole: true 31 | -------------------------------------------------------------------------------- /cluster/apps/tailscale/Chart.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v2 3 | name: my-tailscale-chart 4 | type: application 5 | version: 0.1.0 6 | appVersion: "1.0" 7 | dependencies: 8 | - name: tailscale-operator 9 | version: 1.56.1 10 | repository: https://pkgs.tailscale.com/helmcharts 11 | -------------------------------------------------------------------------------- /cluster/apps/tailscale/templates/external-secret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: external-secrets.io/v1beta1 3 | kind: ExternalSecret 4 | metadata: 5 | name: tailscale-op-external-secret 6 | spec: 7 | refreshInterval: "15s" 8 | secretStoreRef: 9 | name: vault-backend 10 | kind: ClusterSecretStore 11 | target: 12 | name: operator-oauth 13 | data: 14 | - secretKey: client_id 15 | remoteRef: 16 | key: secret/tailscale 17 | property: VAULT_TAILSCALE_K8S_CLIENT_ID 18 | - secretKey: client_secret 19 | remoteRef: 20 | key: secret/tailscale 21 | property: VAULT_TAILSCALE_K8S_CLIENT_SECRET 22 | -------------------------------------------------------------------------------- /cluster/apps/tailscale/values.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) Tailscale Inc & AUTHORS 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | # Operator oauth credentials. If set a Kubernetes Secret with the provided 5 | # values will be created in the operator namespace. If unset a Secret named 6 | # operator-oauth must be precreated. 7 | oauth: {} 8 | # clientId: "" 9 | # clientSecret: "" 10 | 11 | # installCRDs determines whether tailscale.com CRDs should be installed as part 12 | # of chart installation. We do not use Helm's CRD installation mechanism as that 13 | # does not allow for upgrading CRDs. 14 | # https://helm.sh/docs/chart_best_practices/custom_resource_definitions/ 15 | installCRDs: "true" 16 | 17 | operatorConfig: 18 | # ACL tag that operator will be tagged with. Operator must be made owner of 19 | # these tags 20 | # https://tailscale.com/kb/1236/kubernetes-operator/?q=operator#setting-up-the-kubernetes-operator 21 | # Multiple tags are defined as array items and passed to the operator as a comma-separated string 22 | defaultTags: 23 | - "tag:k8s-operator" 24 | 25 | image: 26 | repo: tailscale/k8s-operator 27 | # Digest will be prioritized over tag. If neither are set appVersion will be 28 | # used. 29 | tag: "" 30 | digest: "" 31 | pullPolicy: Always 32 | logging: "info" # info, debug, dev 33 | hostname: "tailscale-operator" 34 | nodeSelector: 35 | kubernetes.io/os: linux 36 | 37 | resources: {} 38 | 39 | podAnnotations: {} 40 | 41 | tolerations: [] 42 | 43 | affinity: {} 44 | 45 | podSecurityContext: {} 46 | 47 | securityContext: {} 48 | 49 | # proxyConfig contains configuraton that will be applied to any ingress/egress 50 | # proxies created by the operator. 51 | # https://tailscale.com/kb/1236/kubernetes-operator/#cluster-ingress 52 | # https://tailscale.com/kb/1236/kubernetes-operator/#cluster-egress 53 | proxyConfig: 54 | image: 55 | repo: tailscale/tailscale 56 | # Digest will be prioritized over tag. If neither are set appVersion will be 57 | # used. 58 | tag: "" 59 | digest: "" 60 | # ACL tag that operator will tag proxies with. Operator must be made owner of 61 | # these tags 62 | # https://tailscale.com/kb/1236/kubernetes-operator/?q=operator#setting-up-the-kubernetes-operator 63 | # Multiple tags can be passed as a comma-separated string i.e 'tag:k8s-proxies,tag:prod'. 64 | # Note that if you pass multiple tags to this field via `--set` flag to helm upgrade/install commands you must escape the comma (for example, "tag:k8s-proxies\,tag:prod"). See https://github.com/helm/helm/issues/1556 65 | defaultTags: "tag:k8s" 66 | firewallMode: auto 67 | 68 | # apiServerProxyConfig allows to configure whether the operator should expose 69 | # Kubernetes API server. 70 | # https://tailscale.com/kb/1236/kubernetes-operator/#accessing-the-kubernetes-control-plane-using-an-api-server-proxy 71 | apiServerProxyConfig: 72 | mode: "false" # "true", "false", "noauth" 73 | 74 | imagePullSecrets: [] 75 | -------------------------------------------------------------------------------- /cluster/apps/whoami/deployments.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: Deployment 3 | apiVersion: apps/v1 4 | metadata: 5 | name: whoami 6 | labels: 7 | app: whoami 8 | 9 | spec: 10 | replicas: 2 11 | selector: 12 | matchLabels: 13 | app: whoami 14 | template: 15 | metadata: 16 | labels: 17 | app: whoami 18 | spec: 19 | serviceAccountName: whoami 20 | securityContext: 21 | runAsNonRoot: true 22 | runAsUser: 65534 23 | runAsGroup: 65534 24 | fsGroup: 65534 25 | affinity: 26 | nodeAffinity: 27 | preferredDuringSchedulingIgnoredDuringExecution: 28 | - weight: 1 29 | preference: 30 | matchExpressions: 31 | - key: node.kubernetes.io/role 32 | operator: In 33 | values: 34 | - worker 35 | containers: 36 | - name: whoami 37 | securityContext: 38 | allowPrivilegeEscalation: false 39 | capabilities: 40 | drop: 41 | - ALL 42 | readOnlyRootFilesystem: true 43 | image: ghcr.io/traefik/whoami:v1.10 44 | ports: 45 | - name: web 46 | protocol: TCP 47 | containerPort: 80 48 | livenessProbe: 49 | httpGet: 50 | path: / 51 | port: web 52 | initialDelaySeconds: 5 53 | periodSeconds: 10 54 | timeoutSeconds: 2 55 | readinessProbe: 56 | httpGet: 57 | path: / 58 | port: web 59 | initialDelaySeconds: 5 60 | periodSeconds: 10 61 | timeoutSeconds: 2 62 | resources: 63 | requests: 64 | cpu: "10m" 65 | memory: "10Mi" 66 | limits: 67 | cpu: "20m" 68 | memory: "20Mi" 69 | -------------------------------------------------------------------------------- /cluster/apps/whoami/ingress.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: networking.k8s.io/v1 3 | kind: Ingress 4 | metadata: 5 | name: hidden 6 | labels: 7 | app: whoami 8 | annotations: 9 | cert-manager.io/cluster-issuer: "letsencrypt-prod" 10 | nginx.ingress.kubernetes.io/auth-url: "https://auth.kblb.io/oauth2/auth" 11 | nginx.ingress.kubernetes.io/auth-signin: "https://auth.kblb.io/oauth2/start?rd=https://$host$uri" 12 | 13 | spec: 14 | ingressClassName: nginx 15 | tls: 16 | - hosts: 17 | - hidden.kblb.io 18 | secretName: my-certs-hidden 19 | rules: 20 | - host: hidden.kblb.io 21 | http: 22 | paths: 23 | - path: / 24 | pathType: Prefix 25 | backend: 26 | service: 27 | name: whoami 28 | port: 29 | name: web 30 | 31 | --- 32 | apiVersion: networking.k8s.io/v1 33 | kind: Ingress 34 | metadata: 35 | name: whoami 36 | labels: 37 | app: whoami 38 | annotations: 39 | cert-manager.io/cluster-issuer: "letsencrypt-prod" 40 | 41 | spec: 42 | ingressClassName: nginx 43 | tls: 44 | - hosts: 45 | - whoami.kblb.io 46 | secretName: my-certs-whoami 47 | rules: 48 | - host: whoami.kblb.io 49 | http: 50 | paths: 51 | - path: / 52 | pathType: Prefix 53 | backend: 54 | service: 55 | name: whoami 56 | port: 57 | name: web 58 | -------------------------------------------------------------------------------- /cluster/apps/whoami/kustomization.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | resources: 3 | - services.yaml 4 | - deployments.yaml 5 | - ingress.yaml 6 | - network-policy.yaml 7 | - service-account.yaml 8 | -------------------------------------------------------------------------------- /cluster/apps/whoami/network-policy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: NetworkPolicy 3 | metadata: 4 | name: whoami-network-policy 5 | spec: 6 | podSelector: 7 | matchLabels: 8 | app: whoami 9 | policyTypes: 10 | - Ingress 11 | - Egress 12 | ingress: 13 | - from: 14 | - namespaceSelector: {} 15 | ports: 16 | - port: 80 17 | protocol: TCP 18 | - port: 443 19 | protocol: TCP 20 | egress: 21 | - to: 22 | - namespaceSelector: {} 23 | ports: 24 | - port: 53 25 | protocol: UDP 26 | - port: 53 27 | protocol: TCP 28 | -------------------------------------------------------------------------------- /cluster/apps/whoami/service-account.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: whoami 5 | labels: 6 | app: whoami 7 | -------------------------------------------------------------------------------- /cluster/apps/whoami/services.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: whoami 6 | labels: 7 | app: whoami 8 | 9 | spec: 10 | ports: 11 | - name: web 12 | protocol: TCP 13 | port: 80 14 | targetPort: web 15 | selector: 16 | app: whoami 17 | -------------------------------------------------------------------------------- /cluster/init/argocd-apps/Chart.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v2 3 | name: my-argocd-apps-chart 4 | type: application 5 | version: 0.1.0 6 | appVersion: "1.0" 7 | dependencies: 8 | - name: argocd-apps 9 | version: 2.0.0 10 | repository: https://argoproj.github.io/argo-helm 11 | -------------------------------------------------------------------------------- /cluster/init/argocd-apps/values.yaml: -------------------------------------------------------------------------------- 1 | # https://github.com/argoproj/argo-helm/blob/main/charts/argocd-apps/values.yaml 2 | argocd-apps: 3 | applications: 4 | apps: 5 | project: default 6 | source: 7 | repoURL: https://github.com/omdv/homelab-server 8 | targetRevision: HEAD 9 | path: cluster/apps/ 10 | destination: 11 | server: https://kubernetes.default.svc 12 | syncPolicy: 13 | automated: 14 | prune: true 15 | selfHeal: true 16 | -------------------------------------------------------------------------------- /cluster/init/argocd/Chart.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v2 3 | name: my-argocd-chart 4 | type: application 5 | version: 0.1.0 6 | appVersion: "1.0" 7 | dependencies: 8 | - name: argo-cd 9 | version: 8.0.3 10 | repository: https://argoproj.github.io/argo-helm 11 | -------------------------------------------------------------------------------- /cluster/init/argocd/values.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # https://github.com/argoproj/argo-helm/blob/main/charts/argo-cd/values.yaml 3 | argo-cd: 4 | global: 5 | affinity: 6 | nodeAffinity: 7 | requiredDuringSchedulingIgnoredDuringExecution: 8 | nodeSelectorTerms: 9 | - matchExpressions: 10 | - key: node-role.kubernetes.io/control-plane 11 | operator: Exists 12 | dex: 13 | enabled: false 14 | server: 15 | autoscaling: 16 | enabled: true 17 | minReplicas: 1 18 | maxReplicas: 2 19 | targetCPUUtilizationPercentage: 50 20 | targetMemoryUtilizationPercentage: 50 21 | behavior: 22 | scaleDown: 23 | stabilizationWindowSeconds: 300 24 | policies: 25 | - type: Pods 26 | value: 1 27 | periodSeconds: 180 28 | scaleUp: 29 | stabilizationWindowSeconds: 300 30 | policies: 31 | - type: Pods 32 | value: 2 33 | periodSeconds: 60 34 | resources: 35 | limits: 36 | cpu: 100m 37 | memory: 128Mi 38 | requests: 39 | cpu: 50m 40 | memory: 64Mi 41 | extraArgs: 42 | - --insecure 43 | ingress: 44 | enabled: true 45 | annotations: 46 | cert-manager.io/cluster-issuer: "letsencrypt-prod" 47 | nginx.ingress.kubernetes.io/auth-url: "https://auth.kblb.io/oauth2/auth" 48 | nginx.ingress.kubernetes.io/auth-signin: "https://auth.kblb.io/oauth2/start?rd=https://$host$uri" 49 | hajimari.io/enable: "true" 50 | labels: {} 51 | ingressClassName: "nginx" 52 | hostname: "argo.kblb.io" 53 | paths: 54 | - / 55 | pathType: Prefix 56 | extraPaths: 57 | extraTls: 58 | - secretName: my-certs-argo 59 | hosts: 60 | - argo.kblb.io 61 | repoServer: 62 | replicas: 1 63 | resources: 64 | limits: 65 | cpu: 2000m 66 | memory: 1024Mi 67 | requests: 68 | cpu: 500m 69 | memory: 256Mi 70 | controller: 71 | replicas: 1 72 | resources: 73 | requests: 74 | cpu: 512m 75 | memory: 512Mi 76 | limits: 77 | cpu: 2048m 78 | memory: 1024Mi 79 | applicationSet: 80 | replicas: 1 81 | resources: 82 | limits: 83 | cpu: 100m 84 | memory: 128Mi 85 | requests: 86 | cpu: 100m 87 | memory: 128Mi 88 | redis: 89 | enabled: true 90 | resources: 91 | limits: 92 | cpu: 50m 93 | memory: 64Mi 94 | requests: 95 | cpu: 10m 96 | memory: 32Mi 97 | notifications: 98 | resources: 99 | limits: 100 | cpu: 50m 101 | memory: 64Mi 102 | requests: 103 | cpu: 10m 104 | memory: 32Mi 105 | configs: 106 | secret: 107 | argocdServerAdminPassword: $2a$10$YtCUmdJ2B002tKFlEDmB7OmGv2r4xLt428YodSDJsrNIQ.z3wI/UK 108 | -------------------------------------------------------------------------------- /cluster/init/external-secrets/Chart.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v2 3 | name: my-external-secrets-chart 4 | type: application 5 | version: 0.1.0 6 | appVersion: "1.0" 7 | dependencies: 8 | - name: external-secrets 9 | version: 0.5.8 10 | repository: https://charts.external-secrets.io 11 | -------------------------------------------------------------------------------- /cluster/init/external-secrets/values.yaml: -------------------------------------------------------------------------------- 1 | # https://github.com/external-secrets/external-secrets/blob/main/deploy/charts/external-secrets/values.yaml 2 | --- 3 | external-secrets: 4 | replicaCount: 1 5 | 6 | image: 7 | repository: ghcr.io/external-secrets/external-secrets 8 | pullPolicy: IfNotPresent 9 | 10 | installCRDs: true 11 | 12 | resources: 13 | requests: 14 | cpu: 10m 15 | memory: 32Mi 16 | -------------------------------------------------------------------------------- /cluster/init/init.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: root-init 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | spec: 10 | destination: 11 | namespace: argocd 12 | name: in-cluster 13 | project: default 14 | source: 15 | path: cluster/init/main 16 | repoURL: https://github.com/omdv/homelab-server 17 | targetRevision: HEAD 18 | syncPolicy: 19 | automated: 20 | prune: true 21 | selfHeal: true 22 | -------------------------------------------------------------------------------- /cluster/init/main/Chart.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v2 3 | name: bootstrap-chart 4 | description: Applications 5 | type: application 6 | version: 0.1.0 7 | appVersion: "1.0" 8 | -------------------------------------------------------------------------------- /cluster/init/main/templates/argocd-apps.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: argocd-apps 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | annotations: 10 | argocd.argoproj.io/sync-wave: "-5" 11 | spec: 12 | destination: 13 | namespace: argocd 14 | server: {{ .Values.spec.destination.server }} 15 | project: default 16 | source: 17 | path: cluster/init/argocd-apps 18 | repoURL: {{ .Values.spec.source.repoURL }} 19 | targetRevision: {{ .Values.spec.source.targetRevision }} 20 | syncPolicy: 21 | automated: 22 | prune: true 23 | selfHeal: true 24 | syncOptions: 25 | - CreateNamespace=true 26 | -------------------------------------------------------------------------------- /cluster/init/main/templates/argocd.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: argocd 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | annotations: 10 | argocd.argoproj.io/sync-wave: "-5" 11 | spec: 12 | destination: 13 | namespace: argocd 14 | server: {{ .Values.spec.destination.server }} 15 | project: default 16 | source: 17 | path: cluster/init/argocd 18 | repoURL: {{ .Values.spec.source.repoURL }} 19 | targetRevision: {{ .Values.spec.source.targetRevision }} 20 | syncPolicy: 21 | automated: 22 | prune: true 23 | selfHeal: true 24 | syncOptions: 25 | - CreateNamespace=true 26 | -------------------------------------------------------------------------------- /cluster/init/main/templates/external-secrets.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: external-secrets 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | annotations: 10 | argocd.argoproj.io/sync-wave: "-8" 11 | spec: 12 | destination: 13 | namespace: external-secrets 14 | server: {{ .Values.spec.destination.server }} 15 | project: default 16 | source: 17 | path: cluster/init/external-secrets 18 | repoURL: {{ .Values.spec.source.repoURL }} 19 | targetRevision: {{ .Values.spec.source.targetRevision }} 20 | syncPolicy: 21 | automated: 22 | prune: true 23 | selfHeal: true 24 | syncOptions: 25 | - CreateNamespace=true 26 | -------------------------------------------------------------------------------- /cluster/init/main/templates/secrets-store.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: secrets-store 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | annotations: 10 | argocd.argoproj.io/sync-wave: "-7" 11 | spec: 12 | destination: 13 | namespace: external-secrets 14 | server: {{ .Values.spec.destination.server }} 15 | project: default 16 | source: 17 | path: cluster/init/secrets-store 18 | repoURL: {{ .Values.spec.source.repoURL }} 19 | targetRevision: {{ .Values.spec.source.targetRevision }} 20 | syncPolicy: 21 | automated: 22 | prune: true 23 | selfHeal: true 24 | syncOptions: 25 | - CreateNamespace=true 26 | -------------------------------------------------------------------------------- /cluster/init/main/templates/vault.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: vault 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | annotations: 10 | argocd.argoproj.io/sync-wave: "-10" 11 | spec: 12 | destination: 13 | namespace: vault 14 | server: {{ .Values.spec.destination.server }} 15 | project: default 16 | source: 17 | path: cluster/init/vault 18 | repoURL: {{ .Values.spec.source.repoURL }} 19 | targetRevision: {{ .Values.spec.source.targetRevision }} 20 | syncPolicy: 21 | automated: 22 | prune: true 23 | selfHeal: true 24 | syncOptions: 25 | - CreateNamespace=true 26 | -------------------------------------------------------------------------------- /cluster/init/main/templates/zfs-storage.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: argoproj.io/v1alpha1 3 | kind: Application 4 | metadata: 5 | name: zfs-storage 6 | namespace: argocd 7 | finalizers: 8 | - resources-finalizer.argocd.argoproj.io 9 | annotations: 10 | argocd.argoproj.io/sync-wave: "-8" 11 | spec: 12 | destination: 13 | namespace: zfs-storage 14 | server: {{ .Values.spec.destination.server }} 15 | project: default 16 | source: 17 | path: cluster/init/zfs-storage 18 | repoURL: {{ .Values.spec.source.repoURL }} 19 | targetRevision: {{ .Values.spec.source.targetRevision }} 20 | syncPolicy: 21 | automated: 22 | prune: true 23 | selfHeal: true 24 | syncOptions: 25 | - CreateNamespace=true 26 | -------------------------------------------------------------------------------- /cluster/init/main/values.yaml: -------------------------------------------------------------------------------- 1 | spec: 2 | destination: 3 | server: https://kubernetes.default.svc 4 | source: 5 | repoURL: https://github.com/omdv/homelab-server 6 | targetRevision: HEAD 7 | -------------------------------------------------------------------------------- /cluster/init/secrets-store/kustomization.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | resources: 3 | - secret-store.yaml 4 | - rbac.yaml 5 | -------------------------------------------------------------------------------- /cluster/init/secrets-store/rbac.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: secret-reader 6 | rules: 7 | - apiGroups: [""] 8 | resources: ["secrets"] 9 | verbs: ["get", "watch", "list"] 10 | 11 | --- 12 | apiVersion: rbac.authorization.k8s.io/v1 13 | kind: RoleBinding 14 | metadata: 15 | name: read-secrets 16 | namespace: external-secrets 17 | subjects: 18 | - kind: ServiceAccount 19 | name: default 20 | namespace: external-secrets 21 | roleRef: 22 | kind: ClusterRole 23 | name: secret-reader 24 | apiGroup: "" 25 | -------------------------------------------------------------------------------- /cluster/init/secrets-store/secret-store.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: external-secrets.io/v1beta1 3 | kind: ClusterSecretStore 4 | metadata: 5 | name: vault-backend 6 | spec: 7 | provider: 8 | vault: 9 | server: "http://vault.vault.svc.cluster.local:8200" 10 | path: "kv" 11 | version: "v2" 12 | auth: 13 | tokenSecretRef: 14 | name: "vault-secret" 15 | namespace: "external-secrets" 16 | key: "vault-token" 17 | status: 18 | conditions: 19 | - type: Ready 20 | status: "False" 21 | reason: "ConfigError" 22 | message: "SecretStore validation failed" 23 | lastTransitionTime: "2019-08-12T12:33:02Z" 24 | -------------------------------------------------------------------------------- /cluster/init/vault/Chart.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v2 3 | name: my-vault-chart 4 | type: application 5 | version: 0.1.0 6 | appVersion: "1.0" 7 | dependencies: 8 | - name: vault 9 | version: 0.28.1 10 | repository: https://helm.releases.hashicorp.com 11 | -------------------------------------------------------------------------------- /cluster/init/vault/values.yaml: -------------------------------------------------------------------------------- 1 | # https://github.com/hashicorp/vault-helm/blob/main/values.yaml 2 | --- 3 | vault: 4 | global: 5 | enabled: true 6 | tls_disable: true 7 | resources: 8 | requests: 9 | memory: '16Mi' 10 | cpu: '0.01' 11 | limits: 12 | memory: '64Mi' 13 | cpu: '0.05' 14 | 15 | service: 16 | enabled: false 17 | 18 | server: 19 | image: 20 | repository: "hashicorp/vault" 21 | tag: "1.17.2" 22 | 23 | readinessProbe: 24 | enabled: true 25 | path: "/v1/sys/health?standbyok=true&sealedcode=204&uninitcode=204" 26 | 27 | livenessProbe: 28 | enabled: false 29 | 30 | extraVolumes: 31 | - type: secret 32 | name: kms-creds 33 | load: false 34 | 35 | resources: 36 | requests: 37 | memory: 256Mi 38 | cpu: 250m 39 | limits: 40 | memory: 512Mi 41 | cpu: 500m 42 | 43 | dataStorage: 44 | enabled: true 45 | size: 10Gi 46 | mountPath: "/vault/data" 47 | storageClass: local-path 48 | accessMode: ReadWriteOnce 49 | 50 | standalone: 51 | config: | 52 | listener "tcp" { 53 | tls_disable = 1 54 | address = "[::]:8200" 55 | cluster_address = "[::]:8201" 56 | } 57 | storage "file" { 58 | path = "/vault/data" 59 | } 60 | seal "gcpckms" { 61 | credentials = "/vault/userconfig/kms-creds/credentials.json" 62 | project = "omdv-homelab" 63 | region = "global" 64 | key_ring = "vault-keyring" 65 | crypto_key = "vault-key" 66 | } 67 | -------------------------------------------------------------------------------- /cluster/init/zfs-storage/storage-class.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: storage.k8s.io/v1 3 | kind: StorageClass 4 | metadata: 5 | name: zfspv 6 | annotations: 7 | storageclass.kubernetes.io/is-default-class: "false" 8 | parameters: 9 | recordsize: "4k" 10 | compression: "off" 11 | dedup: "off" 12 | fstype: "zfs" 13 | poolname: "pool/k3s" 14 | provisioner: zfs.csi.openebs.io 15 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "flake-utils": { 4 | "inputs": { 5 | "systems": "systems" 6 | }, 7 | "locked": { 8 | "lastModified": 1731533236, 9 | "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", 10 | "owner": "numtide", 11 | "repo": "flake-utils", 12 | "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", 13 | "type": "github" 14 | }, 15 | "original": { 16 | "owner": "numtide", 17 | "repo": "flake-utils", 18 | "type": "github" 19 | } 20 | }, 21 | "nixpkgs": { 22 | "locked": { 23 | "lastModified": 1751271578, 24 | "narHash": "sha256-P/SQmKDu06x8yv7i0s8bvnnuJYkxVGBWLWHaU+tt4YY=", 25 | "owner": "NixOS", 26 | "repo": "nixpkgs", 27 | "rev": "3016b4b15d13f3089db8a41ef937b13a9e33a8df", 28 | "type": "github" 29 | }, 30 | "original": { 31 | "owner": "NixOS", 32 | "ref": "nixos-unstable", 33 | "repo": "nixpkgs", 34 | "type": "github" 35 | } 36 | }, 37 | "root": { 38 | "inputs": { 39 | "flake-utils": "flake-utils", 40 | "nixpkgs": "nixpkgs" 41 | } 42 | }, 43 | "systems": { 44 | "locked": { 45 | "lastModified": 1681028828, 46 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 47 | "owner": "nix-systems", 48 | "repo": "default", 49 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 50 | "type": "github" 51 | }, 52 | "original": { 53 | "owner": "nix-systems", 54 | "repo": "default", 55 | "type": "github" 56 | } 57 | } 58 | }, 59 | "root": "root", 60 | "version": 7 61 | } 62 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Python dev environment with uv and direnv"; 3 | 4 | inputs = { 5 | nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; 6 | flake-utils.url = "github:numtide/flake-utils"; 7 | }; 8 | 9 | outputs = { self, nixpkgs, flake-utils }: 10 | flake-utils.lib.eachDefaultSystem (system: 11 | let 12 | pkgs = import nixpkgs { 13 | inherit system; 14 | config.allowUnfree = true; 15 | }; 16 | in { 17 | devShells.default = pkgs.mkShell { 18 | packages = with pkgs; [ 19 | uv 20 | go-task 21 | kubernetes-helm 22 | envsubst 23 | age 24 | pre-commit 25 | mariadb 26 | popeye 27 | ansible 28 | ]; 29 | 30 | # Environment variables and commands to run when entering the shell. 31 | # This is where we integrate UV and the virtual environment. 32 | shellHook = '' 33 | # Create a virtual environment if it doesn't exist. 34 | # We place it in .venv in the project root. 35 | if [ ! -d ".venv" ]; then 36 | echo -e "\033[1;34mCreating virtual environment with uv...\033[0m" 37 | ${pkgs.uv}/bin/uv venv .venv 38 | fi 39 | 40 | # Activate the virtual environment 41 | source ./.venv/bin/activate 42 | 43 | # Install/sync dependencies from pyproject.toml or requirements.txt 44 | # You can choose one of these. pyproject.toml (Poetry/Rye/PDM) is generally preferred. 45 | if [ -f "pyproject.toml" ]; then 46 | echo -e "\033[1;34mSyncing dependencies with uv...\033[0m" 47 | # uv sync --extra=dev # if you have [tool.uv.extras.dev] defined 48 | uv sync 49 | elif [ -f "requirements.txt" ]; then 50 | echo -e "\033[1;34mInstalling dependencies from requirements.txt with uv...\033[0m" 51 | uv pip install -r requirements.txt 52 | else 53 | echo -e "\033[1;34mNo pyproject.toml or requirements.txt found. Manage dependencies manually with uv pip install.\033[0m" 54 | fi 55 | 56 | echo -e "\033[1;34m$(python --version) | $(uv --version)\033[0m" 57 | ''; 58 | }; 59 | }); 60 | } 61 | -------------------------------------------------------------------------------- /infra/cloudflare/main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | 3 | required_providers { 4 | cloudflare = { 5 | source = "cloudflare/cloudflare" 6 | version = "~> 3.0" 7 | } 8 | http = { 9 | source = "hashicorp/http" 10 | version = "~> 2.0" 11 | } 12 | sops = { 13 | source = "carlpett/sops" 14 | version = "~> 0.6" 15 | } 16 | } 17 | } 18 | 19 | data "sops_file" "cloudflare_secrets" { 20 | source_file = "secret.sops.yaml" 21 | } 22 | 23 | provider "cloudflare" { 24 | api_token = data.sops_file.cloudflare_secrets.data["cloudflare_api_token"] 25 | } 26 | 27 | data "cloudflare_zones" "domain" { 28 | filter { 29 | name = data.sops_file.cloudflare_secrets.data["cloudflare_domain"] 30 | } 31 | } 32 | 33 | resource "cloudflare_zone_settings_override" "cloudflare_settings" { 34 | zone_id = lookup(data.cloudflare_zones.domain.zones[0], "id") 35 | settings { 36 | # /ssl-tls 37 | ssl = "full" 38 | # /ssl-tls/edge-certificates 39 | always_use_https = "on" 40 | min_tls_version = "1.0" 41 | opportunistic_encryption = "on" 42 | tls_1_3 = "zrt" 43 | automatic_https_rewrites = "on" 44 | universal_ssl = "on" 45 | # /firewall/settings 46 | browser_check = "on" 47 | challenge_ttl = 1800 48 | privacy_pass = "on" 49 | security_level = "medium" 50 | # /speed/optimization 51 | brotli = "on" 52 | minify { 53 | css = "on" 54 | js = "on" 55 | html = "on" 56 | } 57 | rocket_loader = "on" 58 | # /caching/configuration 59 | always_online = "off" 60 | development_mode = "off" 61 | # /network 62 | http3 = "on" 63 | zero_rtt = "on" 64 | ipv6 = "on" 65 | websockets = "on" 66 | opportunistic_onion = "on" 67 | pseudo_ipv4 = "off" 68 | ip_geolocation = "on" 69 | # /content-protection 70 | email_obfuscation = "on" 71 | server_side_exclude = "on" 72 | hotlink_protection = "off" 73 | } 74 | } 75 | 76 | data "http" "ipv4" { 77 | url = "http://ipv4.icanhazip.com" 78 | } 79 | 80 | resource "cloudflare_record" "main" { 81 | name = "@" 82 | zone_id = lookup(data.cloudflare_zones.domain.zones[0], "id") 83 | # domain = data.sops_file.cloudflare_secrets.data["cloudflare_domain"] 84 | value = chomp(data.http.ipv4.body) 85 | type = "A" 86 | proxied = true 87 | ttl = 1 88 | } 89 | 90 | resource "cloudflare_record" "wildcard" { 91 | name = "*" 92 | zone_id = lookup(data.cloudflare_zones.domain.zones[0], "id") 93 | # value = data.sops_file.cloudflare_secrets.data["cloudflare_domain"] 94 | value = chomp(data.http.ipv4.body) 95 | type = "A" 96 | proxied = true 97 | ttl = 1 98 | } 99 | -------------------------------------------------------------------------------- /infra/cloudflare/secret.sops.yaml: -------------------------------------------------------------------------------- 1 | kind: Secret 2 | cloudflare_domain: ENC[AES256_GCM,data:jXTYzsbx,iv:NHHH7JooZdh7hUCe7z9D+oLmw4jshfxc6E+alj1se9s=,tag:Y4VF5KotKvkmkTyM4SXBnA==,type:str] 3 | cloudflare_api_token: ENC[AES256_GCM,data:CUktJS/2uvOO8hau81owkQrBNQsxsxCp8lprnSEdkrkDpqQ2d+4ZWw==,iv:jpsoYywb99Rnn1hWIiY8vQiJNW68S49QUM3qSwyrE4Q=,tag:1kbhxDfqSkHgZPY2VjHKvg==,type:str] 4 | sops: 5 | kms: [] 6 | gcp_kms: [] 7 | azure_kv: [] 8 | hc_vault: [] 9 | age: 10 | - recipient: age1k30whteuhd93qd9sgcrnj2cur0dz5dgtj7vyhsc2hjeph0u3p97s70v7lg 11 | enc: | 12 | -----BEGIN AGE ENCRYPTED FILE----- 13 | YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBocW95WHMyNzlwb0lKRkwr 14 | c09PNkpST0x1NTNHeEZZZnRyRE9RNm9LVkZZCjJXczNUNm8wWkZoc1NGZTZwN3hY 15 | VUV5U0NTZXVCU1hyR0VtUk9QeU1vdHMKLS0tIHNhUmlWUTV5clE5YnhwcFJUWVlQ 16 | V2tsbVY3Mit6NGxDNUQxbndnMlBlbEkKgy+U9EHrOrCWtR0s7DtBolFmzFX6KpDz 17 | BEGXge1UtTTmRPh6CvUn39U8tL+W6Sqj8PAjQP3mc0AjiHhMgAxYEw== 18 | -----END AGE ENCRYPTED FILE----- 19 | lastmodified: "2022-07-26T02:14:12Z" 20 | mac: ENC[AES256_GCM,data:+xWiqb/FMWhx7A1BHNi/XUfmPbLy9RmVXGs7wdGZmwsmiVQLmRQMGPHIjtx6pO93+xm/2vHEEAGbq0ZF00eo6oYVef61IiizxuwDya/pQms7x2E0zelgRKSJeBE9rQ9MbHspfHolFPN6V0mCZS7Hkc/MD0Od88VrfNlnwXqm9Pk=,iv:kcyIXfo5tycT3sWUwvVTE1ACm4/m7lpocIjh5kxe3HE=,tag:4mUCKIfM25PLrTigg4BlXA==,type:str] 21 | pgp: [] 22 | unencrypted_regex: ^(kind)$ 23 | version: 3.7.3 24 | -------------------------------------------------------------------------------- /infra/k3s-nodes/inventory.yaml: -------------------------------------------------------------------------------- 1 | all: 2 | children: 3 | k3s_worker: 4 | hosts: 5 | worker-1: 6 | ansible_host: 192.210.141.198 7 | ansible_user: om 8 | ansible_ssh_private_key_file: /home/om/.ssh/id_rsa 9 | ansible_port: 11111 10 | -------------------------------------------------------------------------------- /infra/k3s-nodes/roles/k3s_worker/tasks/common.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Hardening the system first by running the hardening script 3 | # https://github.com/akcryptoguy/vps-harden 4 | command: | 5 | echo "ssh into the host with root password" 6 | echo "run hardening script" 7 | echo "sudo git clone https://github.com/akcryptoguy/vps-harden.git && cd vps-harden && sudo bash get-hard.sh" 8 | echo "mkdir /home/om/.ssh && touch /home/om/.ssh/authorized_keys" 9 | echo "chmod 700 /home/om/.ssh && chmod 600 /home/om/.ssh/authorized_keys" 10 | echo "nano /home/om/.ssh/authorized_keys" 11 | echo "sudo chown -R om:om /home/om/.ssh" 12 | 13 | 14 | - name: Install tailscale 15 | command: | 16 | echo "curl -fsSL https://tailscale.com/install.sh | sh" 17 | echo "register tailscale on custom login server" 18 | 19 | # - name: Install openiscsi 20 | # apt: 21 | # name: open-iscsi 22 | # state: present 23 | # become: true 24 | 25 | # - name: Make sure openiscsi is enabled 26 | # service: 27 | # name: iscsid 28 | # enabled: true 29 | # state: restarted 30 | # become: true 31 | 32 | - name: Open firewall ports 33 | ufw: 34 | rule: allow 35 | port: "{{ item }}" 36 | proto: "{{ 'udp' if item == '51820' else 'any' }}" 37 | loop: 38 | - "11111" 39 | - "51820" 40 | become: true 41 | 42 | - name: Allow Tailscale specific ports 43 | ufw: 44 | rule: allow 45 | interface: tailscale0 46 | direction: in 47 | port: "{{ item }}" 48 | proto: any 49 | loop: 50 | - "8443" # ingress-nginx 51 | - "10250" # metrics 52 | become: true 53 | -------------------------------------------------------------------------------- /infra/k3s-nodes/roles/k3s_worker/tasks/k3s.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Download K3s install script 3 | get_url: 4 | url: https://get.k3s.io 5 | dest: /tmp/k3s-install.sh 6 | mode: '0755' 7 | 8 | - name: Install K3s worker node 9 | shell: | 10 | set -x # Enable command tracing 11 | export INSTALL_K3S_SKIP_START=true 12 | export K3S_URL=https://100.105.105.100:6443 13 | export K3S_TOKEN="{{ lookup('env', 'K3S_TOKEN') }}" 14 | sh /tmp/k3s-install.sh 15 | args: 16 | creates: /usr/local/bin/k3s 17 | register: install_result 18 | failed_when: install_result.rc != 0 19 | become: true 20 | 21 | - name: Debug installation output 22 | debug: 23 | var: install_result 24 | when: install_result is defined 25 | 26 | - name: Clean up install script 27 | file: 28 | path: /tmp/k3s-install.sh 29 | state: absent 30 | 31 | - name: Create K3s service configuration directory 32 | block: 33 | - file: 34 | path: /etc/rancher/k3s 35 | state: directory 36 | mode: '0755' 37 | recurse: true 38 | become: true 39 | 40 | - name: Configure K3s agent 41 | copy: 42 | dest: /etc/rancher/k3s/config.yaml 43 | content: | 44 | server: https://100.105.105.100:6443 45 | token: "{{ lookup('env', 'K3S_TOKEN') }}" 46 | node-external-ip: "100.105.105.101" 47 | vpn-auth: "name=tailscale,joinKey={{ lookup('env', 'K3S_TAILSCALE_AUTH') }}" 48 | node-label: 49 | - "node.kubernetes.io/role=worker" 50 | mode: '0600' 51 | become: true 52 | 53 | - name: Enable and start K3s service 54 | systemd: 55 | name: k3s-agent 56 | state: restarted 57 | enabled: true 58 | daemon_reload: true 59 | become: true 60 | -------------------------------------------------------------------------------- /infra/k3s-nodes/roles/k3s_worker/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - include_tasks: common.yaml 3 | - include_tasks: k3s.yaml 4 | -------------------------------------------------------------------------------- /infra/k3s-nodes/site.yaml: -------------------------------------------------------------------------------- 1 | # main playbook 2 | - hosts: k3s_worker 3 | vars: 4 | ansible_python_interpreter: /usr/bin/python3 5 | roles: 6 | - k3s_worker 7 | -------------------------------------------------------------------------------- /infra/vault-gcp-kms/terraform.tfvars: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------------------- 2 | # Required: 3 | # * gcloud-project - set it to your GCP project name to provision cloud resources 4 | # * account_file_path - the full path to your Cloud IAM service account file location 5 | #------------------------------------------------------------------------------------------- 6 | gcloud-project = "omdv-homelab" 7 | account_file_path = "../../../.bootstrap-secrets/credentials.json" 8 | gcloud-region = "us-east1" 9 | gcloud-zone = "us-east1-b" 10 | key_ring = "vault-keyring" 11 | crypto_key = "vault-key" 12 | keyring_location = "global" 13 | -------------------------------------------------------------------------------- /infra/vault-gcp-kms/variables.tf: -------------------------------------------------------------------------------- 1 | variable "vault_url" { 2 | default = "https://releases.hashicorp.com/vault/1.8.1/vault_1.8.1_linux_amd64.zip" 3 | } 4 | 5 | variable "gcloud-project" { 6 | description = "Google project name" 7 | } 8 | 9 | variable "gcloud-region" { 10 | default = "us-east1" 11 | } 12 | 13 | variable "gcloud-zone" { 14 | default = "us-east1-b" 15 | } 16 | 17 | variable "account_file_path" { 18 | description = "Path to GCP account file" 19 | } 20 | 21 | variable "key_ring" { 22 | description = "Cloud KMS key ring name to create" 23 | default = "test" 24 | } 25 | 26 | variable "crypto_key" { 27 | default = "vault-test" 28 | description = "Crypto key name to create under the key ring" 29 | } 30 | 31 | variable "keyring_location" { 32 | default = "global" 33 | } 34 | -------------------------------------------------------------------------------- /infra/vault-gcp-kms/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.12" 3 | } 4 | -------------------------------------------------------------------------------- /tmpl/.sops.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | creation_rules: 3 | - path_regex: provision/.*\.sops\.ya?ml 4 | unencrypted_regex: "^(kind)$" 5 | age: >- 6 | ${BOOTSTRAP_AGE_PUBLIC_KEY} 7 | - path_regex: cluster/.*\.ya?ml 8 | encrypted_regex: "^(data|stringData)$" 9 | age: >- 10 | ${BOOTSTRAP_AGE_PUBLIC_KEY} 11 | -------------------------------------------------------------------------------- /tmpl/argo/values.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # https://github.com/argoproj/argo-helm/blob/main/charts/argo-cd/values.yaml 3 | argo-cd: 4 | dex: 5 | enabled: false 6 | server: 7 | extraArgs: 8 | - --insecure 9 | ingress: 10 | enabled: true 11 | annotations: 12 | cert-manager.io/cluster-issuer: "letsencrypt-prod" 13 | nginx.ingress.kubernetes.io/auth-url: "https://auth.kblb.io/oauth2/auth" 14 | nginx.ingress.kubernetes.io/auth-signin: "https://auth.kblb.io/oauth2/start?rd=https://$host$uri" 15 | hajimari.io/enable: "true" 16 | labels: {} 17 | ingressClassName: "nginx" 18 | hosts: 19 | - argo.kblb.io 20 | paths: 21 | - / 22 | pathType: Prefix 23 | extraPaths: 24 | tls: 25 | - secretName: my-certs-argo 26 | hosts: 27 | - argo.kblb.io 28 | additionalApplications: 29 | - name: apps 30 | project: default 31 | source: 32 | repoURL: https://github.com/omdv/homelab-server 33 | targetRevision: HEAD 34 | path: cluster/apps/ 35 | destination: 36 | server: https://kubernetes.default.svc 37 | syncPolicy: 38 | automated: 39 | prune: true 40 | selfHeal: true 41 | controller: 42 | resources: 43 | requests: 44 | cpu: 250m 45 | memory: 256Mi 46 | limits: 47 | cpu: 500m 48 | memory: 512Mi 49 | configs: 50 | secret: 51 | argocdServerAdminPassword: ${ARGO_PWD} 52 | -------------------------------------------------------------------------------- /tmpl/cluster/cert-manager-secret.tmpl.yaml: -------------------------------------------------------------------------------- 1 | # yamllint disable 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: cloudflare-api-key 6 | namespace: cert-manager 7 | stringData: 8 | api-key: ${BOOTSTRAP_CLOUDFLARE_APIKEY} 9 | -------------------------------------------------------------------------------- /tmpl/cluster/cluster-settings.tmpl.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: cluster-settings 6 | namespace: flux-system 7 | data: 8 | METALLB_LB_RANGE: ${BOOTSTRAP_METALLB_LB_RANGE} 9 | METALLB_TRAEFIK_ADDR: ${BOOTSTRAP_METALLB_TRAEFIK_ADDR} 10 | -------------------------------------------------------------------------------- /tmpl/cluster/vault-token-secret.tmpl.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | stringData: 4 | vault-token: ${VAULT_TOKEN} 5 | kind: Secret 6 | metadata: 7 | name: vault-secret 8 | namespace: external-secrets 9 | type: Opaque 10 | -------------------------------------------------------------------------------- /tmpl/cluster/wireguard.secrets.tmpl.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | type: Opaque 5 | metadata: 6 | name: wireguard-config 7 | namespace: gateway 8 | data: 9 | vpnConfigfile: ${WIREGUARD_CONFIG_FILE} 10 | -------------------------------------------------------------------------------- /tmpl/terraform/secret.sops.yaml: -------------------------------------------------------------------------------- 1 | kind: Secret 2 | cloudflare_domain: ${BOOTSTRAP_CLOUDFLARE_DOMAIN} 3 | cloudflare_api_token: ${BOOTSTRAP_CLOUDFLARE_API_TOKEN} 4 | -------------------------------------------------------------------------------- /topology.conf: -------------------------------------------------------------------------------- 1 | { 2 | "theme": "neutral", 3 | "flowchart": { 4 | "rankSpacing": 30, 5 | "nodeSpacing": 5, 6 | "curve": "basis" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /topology.mmd: -------------------------------------------------------------------------------- 1 | graph LR 2 | user[user] --> nginx 3 | user --> panel 4 | user --> books 5 | user --> seafile 6 | user --> jpt 7 | user --> kanboard 8 | panel --> lo1 9 | panel --> lo2 10 | panel --> lo3 11 | panel --> lo4 12 | panel --> lo5 13 | panel --> lo6 14 | panel --> lo7 15 | panel --> lo8 16 | subgraph k3s[Traefik.io / k3s.io] 17 | subgraph 1 18 | subgraph sso[OAuth] 19 | panel(panel.*:443) 20 | books(books.*:443) 21 | jpt(jpt.*:443) 22 | seafile(seafile.*:443) 23 | kanboard(kb.*:443) 24 | end 25 | nginx[*:443] 26 | end 27 | end 28 | subgraph dc[Ansible / Docker] 29 | subgraph 3 30 | subgraph local[local] 31 | subgraph 2 32 | lo1(portainer :8001) 33 | lo2(grafana :8003) 34 | lo3(transmission :8004) 35 | lo4(cloudcmd :8005) 36 | lo5(pgadmin :8008) 37 | lo6(huginn :8009) 38 | lo7(mayan :8010) 39 | lo8(mongo :8011) 40 | end 41 | end 42 | end 43 | end 44 | style local fill:#67a9cf,padding:10px 45 | style sso fill:#ef8a62,padding:50px 46 | style user fill:#f7f7f7 47 | --------------------------------------------------------------------------------