├── .gitattributes ├── .github ├── copilot-instructions.md ├── instructions │ ├── README.md │ ├── applications.instructions.md │ ├── external-secrets.instructions.md │ ├── flux.instructions.md │ ├── helmrelease.instructions.md │ ├── secrets.instructions.md │ ├── talos.instructions.md │ ├── volsync.instructions.md │ └── yaml-schemas.instructions.md ├── labeler.yaml ├── labels.yaml ├── prompts │ ├── README.md │ ├── app-template.prompt.yaml │ ├── home-automation.prompt.yaml │ ├── media-app.prompt.yaml │ ├── monitoring.prompt.yaml │ └── network-service.prompt.yaml ├── renovate.json5 ├── scripts │ └── update_crds_local.py └── workflows │ ├── flux-local.yaml │ ├── label-sync.yaml │ ├── labeler.yaml │ ├── renovate.yml │ └── update-crds.yaml ├── .gitignore ├── .renovate ├── allowedVersions.json5 ├── autoMerge.json5 ├── customManagers.json5 ├── grafanaDashboards.json5 ├── groups.json5 ├── labels.json5 └── semanticCommits.json5 ├── .taskfiles ├── .minijinja.toml ├── k8s-bootstrap │ └── Taskfile.yaml ├── k8s │ └── Taskfile.yaml ├── talos │ └── Taskfile.yaml └── volsync │ ├── Taskfile.yaml │ └── resources │ ├── list-snapshots.yaml.j2 │ └── replicationdestination.yaml.j2 ├── LICENSE ├── README.md ├── Taskfile.yaml ├── kubernetes ├── cert-manager │ ├── README.md │ ├── cert-manager.yaml │ ├── cloudflare │ │ ├── cert-manager-cloudflare-api-key.yaml │ │ └── cert-manager-letsencrypt.yaml │ └── prometheusRule.yaml ├── default │ ├── README.md │ ├── audiobookshelf │ │ ├── audiobookshelf.yaml │ │ └── volsync.yml │ ├── cloudnative-pg │ │ ├── chart │ │ │ ├── cloudnative-pg.yaml │ │ │ └── externalsecret.yaml │ │ └── cluster │ │ │ ├── cluster-v17.yaml │ │ │ ├── prometheusrule.yaml │ │ │ ├── scheduledbackup.yaml │ │ │ └── service.yaml │ ├── echo-server │ │ └── echo-server.yaml │ ├── emqx │ │ ├── cluster.yaml │ │ ├── emqx-operator.yaml │ │ ├── externalsecret.yaml │ │ └── ingress.yaml │ ├── frigate │ │ ├── externalsecret.yaml │ │ ├── frigate-configmap.yml │ │ ├── frigate.yaml │ │ └── volsync.yaml │ ├── home-assistant │ │ ├── externalsecret-gcp-sa.yaml │ │ ├── externalsecret.yaml │ │ ├── home-assistant.yaml │ │ └── volsync.yaml │ ├── jellyseerr │ │ ├── jellyseerr.yaml │ │ └── volsync.yaml │ ├── minecraft │ │ ├── minecraft-creative.yaml │ │ ├── minecraft-lobby.yaml │ │ ├── minecraft-proxy.yaml │ │ ├── minecraft-survival.yaml │ │ └── minecraft-survival2.yaml │ ├── node-red │ │ ├── node-red.yaml │ │ └── volsync.yaml │ ├── plex │ │ ├── externalsecret.yaml │ │ ├── plex.yaml │ │ └── volsync.yaml │ ├── prowlarr │ │ ├── externalsecret.yaml │ │ ├── prowlarr.yaml │ │ └── volsync.yaml │ ├── qbittorrent │ │ ├── qbittorrent.yaml │ │ └── volsync.yaml │ ├── radarr │ │ ├── externalsecret.yaml │ │ ├── radarr.yaml │ │ └── volsync.yaml │ ├── readarr │ │ ├── readarr.yaml │ │ └── volsync.yaml │ ├── recyclarr │ │ ├── externalsecret.yaml │ │ ├── recyclarr-configmap.yml │ │ ├── recyclarr.yaml │ │ └── volsync.yaml │ ├── sabnzbd │ │ ├── externalsecret.yaml │ │ ├── sabnzbd.yaml │ │ └── volsync.yaml │ ├── ser2sock │ │ └── ser2sock.yaml │ ├── sonarr │ │ ├── externalsecret.yaml │ │ ├── sonarr.yaml │ │ └── volsync.yaml │ ├── tautulli │ │ ├── tautulli.yaml │ │ └── volsync.yaml │ ├── teslamate │ │ ├── externalsecret.yaml │ │ └── teslamate.yaml │ ├── unifi │ │ ├── unifi.yaml │ │ └── volsync.yaml │ └── zwave2mqtt │ │ ├── volsync.yaml │ │ └── zwave2mqtt.yaml ├── flux-system │ ├── README.md │ ├── discord-notifications │ │ ├── alerts.yaml │ │ ├── discord-webhook-secret.yaml │ │ └── provider.yaml │ ├── flux-instance │ │ └── flux-instance.yaml │ ├── flux-operator │ │ └── flux-operator.yaml │ └── receiver.yaml │ │ ├── externalsecret.yaml │ │ ├── ingress.yaml │ │ ├── prometheusrule.yaml │ │ └── receiver.yaml ├── kube-system │ ├── README.md │ ├── cilium │ │ ├── bgp.yaml │ │ ├── cilium.yaml │ │ └── gateway │ │ │ ├── gateway-external.yaml │ │ │ ├── gateway-tailscale.yaml │ │ │ └── redirect.yaml │ ├── coredns │ │ ├── coredns.yaml │ │ └── eviljungle.yaml │ ├── csi-driver-nfs │ │ └── csi-driver-nfs.yaml │ ├── descheduler │ │ └── descheduler.yaml │ ├── e1000e-fix │ │ └── e1000e-fix.yaml │ ├── external-secrets │ │ ├── 1password │ │ │ ├── 1password.yaml │ │ │ └── clustersecretstore.yaml │ │ └── chart │ │ │ └── external-secrets.yaml │ ├── intel-device-plugins │ │ ├── gpu-plugin.yaml │ │ └── operator.yaml │ ├── metrics-server │ │ └── metrics-server.yaml │ ├── nginx │ │ ├── nginx-external │ │ │ ├── external_minio.yaml │ │ │ └── external_proxmox.yaml │ │ ├── nginx-tailscale.yaml │ │ └── nginx.yaml │ ├── node-feature-discovery │ │ ├── alarmdecoder-device.yaml │ │ ├── coral-device.yaml │ │ ├── node-feature-discovery.yaml │ │ └── zwave-device.yaml │ ├── snapshot-controller │ │ └── snapshot-controller.yaml │ ├── spegel │ │ └── spegel.yaml │ ├── tailscale │ │ ├── externalsecret.yaml │ │ └── tailscale-operator.yaml │ ├── talos-backup │ │ ├── cronjob.yaml │ │ ├── externalsecret.yaml │ │ ├── secret.yaml │ │ └── serviceaccount.yaml │ └── volsync │ │ ├── mutatingadmissionpolicy.yaml │ │ ├── prometheusrule.yaml │ │ └── volsync.yaml ├── monitoring │ ├── README.md │ ├── grafana │ │ ├── dashboards │ │ │ ├── home_assistant.json │ │ │ ├── loki_logs.json │ │ │ ├── opnsense.json │ │ │ ├── prometheus_exporter_summary.json │ │ │ └── ups.json │ │ ├── externalsecret.yaml │ │ └── grafana.yaml │ ├── influxdb │ │ ├── influxdb.yaml │ │ └── volsync.yaml │ ├── loki │ │ └── loki.yaml │ ├── namespace.yaml │ ├── prometheus-rules │ │ ├── dockerhub.yaml │ │ ├── ingress-nginx.yaml │ │ ├── loki.yaml │ │ ├── node-exporter.yaml │ │ ├── oom.yaml │ │ ├── smartctl-exporter.yaml │ │ ├── upsc.yaml │ │ └── zfs-exporter.yaml │ ├── promtail │ │ └── promtail.yaml │ ├── speedtest-exporter │ │ ├── prometheusrule.yaml │ │ ├── servicemonitor.yaml │ │ └── speedtest-exporter.yaml │ └── victoria-metrics │ │ ├── externalsecret.yaml │ │ └── victoria-metrics.yaml ├── rook-ceph │ ├── cluster │ │ └── rook-ceph-cluster.yaml │ └── operator │ │ └── rook-ceph.yaml └── system-upgrade │ ├── README.md │ ├── kubernetes-plan.yaml │ ├── namespace.yaml │ ├── system-upgrade-controller.yaml │ └── talos-plan.yaml └── setup ├── README.md ├── bootstrap ├── helmfile.yaml └── templates │ ├── cert-manager-values.yaml.gotmpl │ ├── cilium-values.yaml.gotmpl │ ├── coredns-values.yaml.gotmpl │ ├── flux-instance-values.yaml.gotmpl │ ├── flux-operator-values.yaml.gotmpl │ └── resources.yaml.j2 ├── crds ├── kustomization.yaml └── vendor │ ├── backube_volsync │ ├── volsync.backube_replicationdestinations.yaml │ └── volsync.backube_replicationsources.yaml │ ├── cloudnative-pg_cloudnative-pg │ ├── postgresql.cnpg.io_backups.yaml │ ├── postgresql.cnpg.io_clusterimagecatalogs.yaml │ ├── postgresql.cnpg.io_clusters.yaml │ ├── postgresql.cnpg.io_databases.yaml │ ├── postgresql.cnpg.io_imagecatalogs.yaml │ ├── postgresql.cnpg.io_poolers.yaml │ ├── postgresql.cnpg.io_publications.yaml │ ├── postgresql.cnpg.io_scheduledbackups.yaml │ └── postgresql.cnpg.io_subscriptions.yaml │ ├── emqx_emqx-operator │ └── crds.yaml │ ├── external-secrets_external-secrets │ └── bundle.yaml │ ├── kubernetes-csi_external-snapshotter │ ├── snapshot.storage.k8s.io_volumesnapshotclasses.yaml │ ├── snapshot.storage.k8s.io_volumesnapshotcontents.yaml │ └── snapshot.storage.k8s.io_volumesnapshots.yaml │ ├── kubernetes-sigs_gateway-api │ └── experimental-install.yaml │ ├── kubernetes-sigs_node-feature-discovery │ └── nfd-api-crds.yaml │ ├── rancher_system-upgrade-controller │ └── crd.yaml │ └── rook_rook │ └── crds.yaml ├── flux ├── cluster │ └── cluster.yaml └── repositories │ ├── 1password-charts.yaml │ ├── backube.yaml │ ├── bjw-s.yaml │ ├── cilium.yaml │ ├── cloudnative-pg.yaml │ ├── controlplaneio-fluxcd.yaml │ ├── coredns.yaml │ ├── csi-driver-nfs.yaml │ ├── emqx-charts.yaml │ ├── external-secrets.yaml │ ├── grafana-charts.yaml │ ├── influxdata-charts.yaml │ ├── ingress-nginx-charts.yaml │ ├── intel.yaml │ ├── jetstack.yaml │ ├── kubernetes-sigs-descheduler-charts.yaml │ ├── kubernetes-sigs-nfd-charts.yaml │ ├── metrics-server.yaml │ ├── minecraft-server-charts.yaml │ ├── piraeus.yaml │ ├── rook-ceph.yaml │ ├── spegel-org.yaml │ ├── tailscale.yaml │ └── victoriametrics-charts.yaml └── talos ├── README.md ├── clusterconfig └── .gitignore ├── patches ├── controller │ ├── admission-controller-patch.yaml │ ├── cluster.yaml │ └── machine-features.yaml └── global │ ├── machine-dns.yaml │ ├── machine-files.yaml │ ├── machine-install.yaml │ ├── machine-network.yaml │ ├── machine-sysctls.yaml │ └── machine-udev.yaml ├── talconfig.yaml ├── talhelper-secrets.env └── talsecret.yaml /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | *.json linguist-detectable linguist-language=JSON 3 | *.json5 linguist-detectable linguist-language=JSON5 4 | *.md linguist-detectable linguist-language=MARKDOWN 5 | *.toml linguist-detectable linguist-language=TOML 6 | *.yml linguist-detectable linguist-language=YAML 7 | *.yaml linguist-detectable linguist-language=YAML 8 | *.yaml.j2 linguist-detectable linguist-language=YAML 9 | *.gotmpl linguist-detectable linguist-language=GOTEMPLATE 10 | -------------------------------------------------------------------------------- /.github/instructions/README.md: -------------------------------------------------------------------------------- 1 | # GitHub Copilot Modular Instructions 2 | 3 | This directory contains modular instruction files for different aspects of the k8s-gitops repository. These files serve as detailed reference documentation and a source of truth for the main `.github/copilot-instructions.md` file. 4 | 5 | ## Purpose of This Approach 6 | 7 | The modular approach helps with: 8 | 9 | 1. **Organization**: Breaking down complex guidelines by component 10 | 2. **Maintenance**: Updating specific sections without editing the entire instructions file 11 | 3. **Collaboration**: Allowing different team members to own different aspects of guidelines 12 | 4. **Future-Proofing**: Preparing for potential future support of modular instructions 13 | 14 | ## Important Note About GitHub Copilot 15 | 16 | As of May 2025, GitHub Copilot: 17 | 18 | - **Only reads** the main `.github/copilot-instructions.md` file 19 | - **Does not follow** links or references to other instruction files 20 | - **Does not support** conditional application of instructions based on file types 21 | 22 | The main file must contain all instructions needed by GitHub Copilot. References to these modular files in the main instructions file are for human readers only. 23 | 24 | ## File Descriptions 25 | 26 | - `flux.instructions.md`: Detailed FluxCD configuration guidelines 27 | - `helmrelease.instructions.md`: Complete HelmRelease patterns and examples 28 | - `talos.instructions.md`: Talos OS configuration best practices 29 | - `applications.instructions.md`: Application deployment patterns 30 | - `secrets.instructions.md`: Comprehensive secret management 31 | - `external-secrets.instructions.md`: External Secrets with 1Password 32 | - `yaml-schemas.instructions.md`: YAML Schema Validation Guidelines 33 | 34 | ## Workflow for Updates 35 | 36 | When updating these instruction files: 37 | 38 | 1. Make your changes to the appropriate modular instruction file 39 | 2. Review the impact on the main instructions file 40 | 3. Update the corresponding section in the main `.github/copilot-instructions.md` file 41 | 4. Commit both changes together 42 | 43 | This ensures that GitHub Copilot always has access to the most up-to-date guidance while maintaining the benefits of modular organization. 44 | -------------------------------------------------------------------------------- /.github/instructions/flux.instructions.md: -------------------------------------------------------------------------------- 1 | # GitHub Copilot Instructions for Flux Configuration 2 | 3 | ## When to Apply These Instructions 4 | 5 | These instructions should be applied when working with FluxCD configuration files, including: 6 | - Files in `/kubernetes/flux-system/` and `/setup/flux/` directories 7 | - Kustomization resources with `kustomize.toolkit.fluxcd.io` API group 8 | - GitRepository, HelmRepository, and OCIRepository resources 9 | - Any file related to FluxCD reconciliation 10 | 11 | ## Flux Configuration Best Practices 12 | 13 | 1. Use the correct API versions: 14 | - `kustomize.toolkit.fluxcd.io/v1` for Kustomization resources 15 | - `helm.toolkit.fluxcd.io/v2` for HelmRelease resources 16 | - `source.toolkit.fluxcd.io/v1` for source controller resources 17 | - `source.toolkit.fluxcd.io/v1` for HelmRepository resources 18 | 19 | 2. Always specify reconciliation intervals: 20 | - 30m for cluster-level Kustomizations 21 | - 30m for application HelmReleases 22 | - 1h for external source repositories 23 | 24 | 3. Always implement proper remediation for HelmRelease resources: 25 | ```yaml 26 | install: 27 | createNamespace: true 28 | remediation: 29 | retries: -1 30 | upgrade: 31 | cleanupOnFail: true 32 | remediation: 33 | retries: 3 34 | ``` 35 | 36 | 4. Use the following structure for sourcing Helm charts: 37 | ```yaml 38 | chart: 39 | spec: 40 | chart: chart-name 41 | version: x.y.z # Always pin versions 42 | sourceRef: 43 | kind: HelmRepository # Or OCIRepository for OCI-based charts 44 | name: repository-name 45 | namespace: flux-system 46 | ``` 47 | 48 | 5. For Kustomizations, always configure: 49 | - `prune: true` to enable garbage collection 50 | - `path: ./path/to/directory` pointing to the correct directory 51 | - `sourceRef` pointing to the GitRepository 52 | 53 | 6. Organize Flux resources: 54 | - Place sources in `/setup/flux/repositories/` 55 | - Place kustomizations in `/setup/flux/cluster/` 56 | - Group repositories by type (helm, git, oci) 57 | -------------------------------------------------------------------------------- /.github/instructions/secrets.instructions.md: -------------------------------------------------------------------------------- 1 | # GitHub Copilot Instructions for Secrets Management 2 | 3 | ## When to Apply These Instructions 4 | 5 | These instructions should be applied when working with secrets and sensitive data, including: 6 | - Files in `/setup/bootstrap/` directories containing secrets 7 | - When working with `Secret` resources in Kubernetes 8 | - When using the ExternalSecrets operator 9 | - When handling credentials, tokens, keys, or any sensitive information 10 | 11 | ## Secret Management Principles 12 | 13 | 1. Never commit plaintext secrets to the repository. 14 | 2. Use ExternalSecrets for retrieving secrets from external providers. 15 | 16 | ## External Secrets 17 | 18 | 1. Configure ClusterSecretStore: 19 | ```yaml 20 | apiVersion: external-secrets.io/v1 21 | kind: ClusterSecretStore 22 | metadata: 23 | name: provider-name 24 | spec: 25 | provider: 26 | # Provider-specific configuration 27 | ``` 28 | 29 | 2. Create ExternalSecret resources: 30 | ```yaml 31 | apiVersion: external-secrets.io/v1 32 | kind: ExternalSecret 33 | metadata: 34 | name: app-secret 35 | namespace: app-namespace 36 | spec: 37 | secretStoreRef: 38 | kind: ClusterSecretStore 39 | name: provider-name 40 | target: 41 | name: app-secret 42 | creationPolicy: Owner 43 | data: 44 | - secretKey: DB_PASSWORD 45 | remoteRef: 46 | key: path/to/secret 47 | property: password 48 | ``` 49 | 50 | 3. For OnePassword integration: 51 | ```yaml 52 | data: 53 | - secretKey: password 54 | remoteRef: 55 | key: op://kubernetes/item/field 56 | ``` 57 | 58 | ## Sensitive Environment Variables 59 | 60 | 1. Reference secrets in HelmRelease values: 61 | ```yaml 62 | envFrom: 63 | - secretRef: 64 | name: app-secret 65 | ``` 66 | 67 | 2. For individual environment variables: 68 | ```yaml 69 | env: 70 | - name: DB_PASSWORD 71 | valueFrom: 72 | secretKeyRef: 73 | name: app-secret 74 | key: password 75 | ``` 76 | -------------------------------------------------------------------------------- /.github/instructions/talos.instructions.md: -------------------------------------------------------------------------------- 1 | # GitHub Copilot Instructions for Talos Configuration 2 | 3 | ## When to Apply These Instructions 4 | 5 | These instructions should be applied when working with Talos OS configuration files, including: 6 | - Files in `/setup/talos/` directories 7 | - Files named `talconfig.yaml` 8 | - Any files related to Talos machine configuration 9 | - When configuring Kubernetes on Talos OS nodes 10 | 11 | ## Talos Configuration Structure 12 | 13 | 1. Follow the Talos configuration schema: 14 | ```yaml 15 | # yaml-language-server: $schema=https://raw.githubusercontent.com/budimanjojo/talhelper/master/pkg/config/schemas/talconfig.json 16 | ``` 17 | 18 | 2. Use YAML anchors for repeated values: 19 | ```yaml 20 | clusterName: &clusterName ${clusterName} 21 | endpoint: "https://${clusterName}.${domainName}:6443" 22 | ``` 23 | 24 | 3. Pin Talos and Kubernetes versions using Renovate annotations: 25 | ```yaml 26 | # renovate: depName=ghcr.io/siderolabs/installer datasource=docker 27 | talosVersion: v1.10.x 28 | # renovate: depName=ghcr.io/siderolabs/kubelet datasource=docker 29 | kubernetesVersion: v1.33.x 30 | ``` 31 | 32 | 4. Always include API server certificate SANs: 33 | ```yaml 34 | additionalApiServerCertSans: &sans 35 | - &talosControlplaneVip ${clusterEndpointIP} 36 | - ${clusterName}.${domainName} 37 | - "127.0.0.1" 38 | additionalMachineCertSans: *sans 39 | ``` 40 | 41 | ## Node Configuration 42 | 43 | 1. Define node configurations under the `nodes` section: 44 | ```yaml 45 | nodes: 46 | - hostname: node-name.domain 47 | controlPlane: true|false 48 | ipAddress: x.x.x.x 49 | installDisk: /dev/xxx 50 | ``` 51 | 52 | 2. Configure network interfaces: 53 | ```yaml 54 | networkInterfaces: 55 | deviceSelectors: 56 | - hardwareAddr: xx:xx:xx:xx:xx:xx 57 | driver: driver-name 58 | dhcp: true 59 | ``` 60 | 61 | ## Talos Machine Configuration 62 | 63 | 1. Use `talhelper` for generating machine configurations: 64 | - Use the task command: `task talos:generate-clusterconfig` 65 | - Apply with: `task talos:apply-clusterconfig` 66 | 67 | 2. Always version control the Talos configuration files. 68 | 69 | 3. For patches and customizations, use the `patches` section: 70 | ```yaml 71 | patches: 72 | - global: true 73 | patch: 74 | - op: add 75 | path: /machine/files/- 76 | value: 77 | content: | 78 | # File content here 79 | permissions: 0644 80 | path: /path/to/file 81 | ``` 82 | 83 | 4. For Cilium networking: 84 | ```yaml 85 | cniConfig: 86 | name: none 87 | ``` 88 | 89 | 5. Configure node labels and taints: 90 | ```yaml 91 | nodeLabels: 92 | key: value 93 | taints: 94 | - key: key 95 | value: value 96 | effect: NoSchedule|NoExecute|PreferNoSchedule 97 | ``` 98 | -------------------------------------------------------------------------------- /.github/instructions/volsync.instructions.md: -------------------------------------------------------------------------------- 1 | # GitHub Copilot Instructions for VolSync Integration 2 | 3 | ## When to Apply These Instructions 4 | 5 | These instructions should be applied when working with persistent storage in applications, including: 6 | - Any application that requires persistent storage 7 | - When creating new PVCs that should be backed up 8 | - When integrating with the VolSync operator for data backup and recovery 9 | - When working with both application-specific and shared PVCs 10 | 11 | ## VolSync Integration Pattern 12 | 13 | 1. Reference the VolSync-backed PVC in the HelmRelease: 14 | ```yaml 15 | # In .yaml 16 | persistence: 17 | config: 18 | storageClass: "ceph-block" 19 | accessMode: ReadWriteOnce 20 | size: "2Gi" # or appropriate size 21 | ``` 22 | 23 | ## Common VolSync Configuration Patterns 24 | 25 | ### Configuration with Multiple PVCs 26 | 27 | When an application needs multiple PVCs: 28 | 1. Create the main config PVC using VolSync (handled automatically) 29 | 2. Reference both PVCs in the HelmRelease: 30 | 31 | 32 | # In /.yaml 33 | ```yaml 34 | persistence: 35 | config: 36 | storageClass: "ceph-block" 37 | accessMode: ReadWriteOnce 38 | size: "2Gi" # or appropriate size 39 | cache: 40 | storageClass: "ceph-block" 41 | accessMode: ReadWriteOnce 42 | size: "2Gi" # or appropriate size 43 | globalMounts: 44 | - path: /config/cache 45 | ``` 46 | 47 | ## Working with Shared PVCs 48 | 49 | For applications that need access to shared data (media files, etc.), combine VolSync-backed PVCs with shared PVCs: 50 | 51 | # In /.yaml 52 | ```yaml 53 | persistence: 54 | config: 55 | storageClass: "ceph-block" 56 | accessMode: ReadWriteOnce 57 | size: "2Gi" # or appropriate size 58 | media: 59 | existingClaim: media-nfs-share-pvc # Shared PVC 60 | globalMounts: 61 | - path: /media 62 | ``` 63 | 64 | ## Best Practices 65 | 66 | 1. Use VolSync for all application configuration data that needs to be persisted 67 | 2. Use the default naming pattern where the PVC name matches the app name 68 | 3. Keep cache and temporary data in separate PVCs to avoid unnecessary backups 69 | 4. Use `ceph-block` and ReadWriteOnce for most application config volumes 70 | -------------------------------------------------------------------------------- /.github/labeler.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | area/bootstrap: 3 | - changed-files: 4 | - any-glob-to-any-file: "setup/bootstrap/**/*" 5 | area/docs: 6 | - changed-files: 7 | - any-glob-to-any-file: 8 | - "README.md" 9 | area/github: 10 | - all: 11 | - changed-files: 12 | - any-glob-to-any-file: '.github/**/*' 13 | - all-globs-to-all-files: '!.github/renovaterc.json5' 14 | area/kubernetes: 15 | - changed-files: 16 | - any-glob-to-any-file: "kubernetes/**/*" 17 | area/renovate: 18 | - changed-files: 19 | - any-glob-to-any-file: 20 | - ".renovate/**/*" 21 | - ".github/renovaterc.json5" 22 | area/talos: 23 | - changed-files: 24 | - any-glob-to-any-file: "setup/talos/**/*" 25 | area/taskfile: 26 | - changed-files: 27 | - any-glob-to-any-file: 28 | - ".taskfiles/**/*" 29 | - "Taskfile.yaml" 30 | -------------------------------------------------------------------------------- /.github/labels.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Areas 3 | - name: area/bootstrap 4 | color: "0e8a16" 5 | - name: area/docs 6 | color: "0e8a16" 7 | - name: area/github 8 | color: "0e8a16" 9 | - name: area/kubernetes 10 | color: "0e8a16" 11 | - name: area/renovate 12 | color: "0e8a16" 13 | - name: area/talos 14 | color: "0e8a16" 15 | - name: area/taskfile 16 | color: "0e8a16" 17 | # Renovate Types 18 | - name: renovate/container 19 | color: "027fa0" 20 | - name: renovate/github-action 21 | color: "027fa0" 22 | - name: renovate/grafana-dashboard 23 | color: "027fa0" 24 | - name: renovate/github-release 25 | color: "027fa0" 26 | - name: renovate/helm 27 | color: "027fa0" 28 | # Semantic Types 29 | - name: type/digest 30 | color: "ffeC19" 31 | - name: type/patch 32 | color: "ffeC19" 33 | - name: type/minor 34 | color: "ff9800" 35 | - name: type/major 36 | color: "f6412d" 37 | # retained defaults 38 | - name: bug 39 | color: "#d73a4a" 40 | - name: duplicate 41 | color: "#cfd3d7" 42 | - name: enhancement 43 | color: "#a2eeef" 44 | - name: invalid 45 | color: "#e4e669" 46 | - name: question 47 | color: "#d876e3" 48 | - name: wontfix 49 | color: "#ffffff" 50 | -------------------------------------------------------------------------------- /.github/prompts/README.md: -------------------------------------------------------------------------------- 1 | # Kubernetes GitOps Deployment Prompts 2 | 3 | This directory contains prompt templates to help you deploy various services to your Kubernetes clusters using GitOps with Flux. 4 | 5 | ## Available Prompt Templates 6 | 7 | 1. [**Generic App Template**](app-template.prompt.md) - For deploying basic applications using the app-template Helm chart. 8 | 9 | 2. [**Media Application**](media-app.prompt.md) - For deploying media management applications like Sonarr, Radarr, etc. 10 | 11 | 3. [**Database**](database.prompt.md) - For deploying database services like PostgreSQL, MySQL, Redis, etc. 12 | 13 | 4. [**Monitoring**](monitoring.prompt.md) - For deploying monitoring, observability, and metrics collection tools. 14 | 15 | 5. [**Home Automation**](home-automation.prompt.md) - For deploying home automation services like Home Assistant, Node-RED, etc. 16 | 17 | 6. [**Network Service**](network-service.prompt.md) - For deploying network-related services like ingress controllers, DNS, VPN, etc. 18 | 19 | ## How to Use These Prompts 20 | 21 | 1. Choose the appropriate prompt template for the type of service you want to deploy. 22 | 23 | 2. Copy the content of the template and fill in the placeholders with your specific requirements. 24 | 25 | 3. Submit the filled prompt to GitHub Copilot to generate the necessary Kubernetes manifests. 26 | 27 | 4. Review the generated manifests and apply them to your repository following the GitOps workflow. 28 | 29 | ## Example Usage 30 | 31 | "Please use the Media Application template to deploy Radarr to my default namespace. It should use the ghcr.io/onedr0p/radarr-develop:5.2.6.8376 image on the develop branch. It needs a Postgres database named radarr_main. Use 100m CPU requests and 2Gi memory limit. It needs access to /data/media and /data/downloads paths. Make it available at radarr.eviljungle.com through the internal tailscale ingress." 32 | 33 | ## Repository Structure 34 | 35 | Each deployed application typically follows this structure: 36 | 37 | ``` 38 | kubernetes/// 39 | ├── namespace.yaml # If creating a new namespace 40 | ├── app/ 41 | ├── externalsecret.yaml # If using external secrets 42 | ├── .yaml # The Helm release definition 43 | └── volsync.yaml # If using additional persistent storage 44 | ``` 45 | 46 | ## Best Practices 47 | 48 | 1. Always follow the repository's established patterns and conventions. 49 | 2. Use YAML schema validation as specified in the repository guidelines. 50 | 3. Pin Helm chart versions explicitly. 51 | 4. Configure resource limits and requests for all applications. 52 | 5. Use external secrets for sensitive information. 53 | 6. Configure proper health checks for all applications. 54 | 7. Follow appropriate security context settings for each application type. 55 | -------------------------------------------------------------------------------- /.github/renovate.json5: -------------------------------------------------------------------------------- 1 | { 2 | $schema: 'https://docs.renovatebot.com/renovate-schema.json', 3 | extends: [ 4 | 'config:recommended', 5 | 'docker:enableMajor', 6 | 'helpers:pinGitHubActionDigests', 7 | 'github>billimek/k8s-gitops//.renovate/allowedVersions.json5', 8 | 'github>billimek/k8s-gitops//.renovate/autoMerge.json5', 9 | 'github>billimek/k8s-gitops//.renovate/customManagers.json5', 10 | 'github>billimek/k8s-gitops//.renovate/grafanaDashboards.json5', 11 | 'github>billimek/k8s-gitops//.renovate/groups.json5', 12 | 'github>billimek/k8s-gitops//.renovate/labels.json5', 13 | 'github>billimek/k8s-gitops//.renovate/semanticCommits.json5', 14 | ':automergeBranch', 15 | ':disableRateLimiting', 16 | ':dependencyDashboard', 17 | ':semanticCommits', 18 | ':timezone(America/New_York)', 19 | ], 20 | 21 | dependencyDashboardTitle: 'Renovate Dashboard 🤖', 22 | suppressNotifications: [ 23 | 'prEditedNotification', 24 | 'prIgnoreNotification', 25 | ], 26 | flux: { 27 | managerFilePatterns: [ 28 | '/(^|/)kubernetes/.+\\.ya?ml$/', 29 | '/(^|/)setup/.+\\.ya?ml$/', 30 | ], 31 | }, 32 | 'helm-values': { 33 | managerFilePatterns: [ 34 | '/(^|/)kubernetes/.+\\.ya?ml$/', 35 | '/(^|/)setup/.+\\.ya?ml$/', 36 | ], 37 | }, 38 | kubernetes: { 39 | managerFilePatterns: [ 40 | '/(^|/)kubernetes/.+\\.ya?ml$/', 41 | '/(^|/)setup/.+\\.ya?ml$/', 42 | ], 43 | }, 44 | } 45 | -------------------------------------------------------------------------------- /.github/scripts/update_crds_local.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | import subprocess 4 | # Get the GitHub workspace path, defaulting to current dir if not set (for local runs) 5 | workspace_path = os.environ.get("GITHUB_WORKSPACE", os.getcwd()) 6 | 7 | kustomization_file_rel = "setup/crds/kustomization.yaml" 8 | vendor_dir_rel = "setup/crds/vendor" 9 | 10 | kustomization_file_abs = os.path.join(workspace_path, kustomization_file_rel) 11 | vendor_dir_abs = os.path.join(workspace_path, vendor_dir_rel) 12 | 13 | if not os.path.exists(vendor_dir_abs): 14 | os.makedirs(vendor_dir_abs) 15 | print(f"Created directory: {vendor_dir_abs}") 16 | 17 | if not os.path.exists(kustomization_file_abs): 18 | print(f"Error: Kustomization file not found at {kustomization_file_abs}") 19 | exit(1) 20 | 21 | with open(kustomization_file_abs, 'r') as f: 22 | content = f.read() 23 | 24 | # Find all crd-url comments and their corresponding local paths 25 | # The local path in kustomization.yaml is relative to kustomization.yaml itself (e.g., ./vendor/...) 26 | crd_urls = re.findall(r"# (https?://[^\s]+)\n\s*- (./vendor/[^\s]+)", content) 27 | 28 | if not crd_urls: 29 | print(f"No CRD URLs found in {kustomization_file_abs}. Check the file and regex pattern.") 30 | 31 | for url, local_path_rel_to_kustomization in crd_urls: 32 | print(f"Processing {url} -> {local_path_rel_to_kustomization}") 33 | 34 | # Construct the full local path for the CRD file 35 | # It's relative to the directory of kustomization_file_abs 36 | kustomization_dir = os.path.dirname(kustomization_file_abs) 37 | full_local_path = os.path.abspath(os.path.join(kustomization_dir, local_path_rel_to_kustomization.strip())) 38 | 39 | # Ensure the directory for the local file exists 40 | local_file_dir = os.path.dirname(full_local_path) 41 | if not os.path.exists(local_file_dir): 42 | os.makedirs(local_file_dir) 43 | print(f"Created directory: {local_file_dir}") 44 | 45 | try: 46 | # Download the CRD 47 | print(f"Downloading from {url} to {full_local_path}...") 48 | subprocess.run(["curl", "-sSL", "-o", full_local_path, url], check=True) 49 | print(f"Successfully downloaded {url} to {full_local_path}") 50 | except subprocess.CalledProcessError as e: 51 | print(f"Error downloading {url}: {e}") 52 | except Exception as e: 53 | print(f"An unexpected error occurred with {url}: {e}") 54 | 55 | print("CRD update process finished.") -------------------------------------------------------------------------------- /.github/workflows/label-sync.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json 3 | name: Label Sync 4 | 5 | on: 6 | workflow_dispatch: 7 | push: 8 | branches: ["master"] 9 | paths: [".github/labels.yaml"] 10 | schedule: 11 | - cron: "0 0 * * *" # Every day at midnight 12 | 13 | permissions: 14 | contents: read 15 | 16 | jobs: 17 | main: 18 | name: Label Sync - Sync Labels 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: Checkout 22 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 23 | with: 24 | sparse-checkout: .github/labels.yaml 25 | persist-credentials: false 26 | 27 | - name: Sync Labels 28 | uses: EndBug/label-sync@52074158190acb45f3077f9099fea818aa43f97a # v2.3.3 29 | with: 30 | config-file: .github/labels.yaml 31 | delete-other-labels: true 32 | -------------------------------------------------------------------------------- /.github/workflows/labeler.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json 3 | name: Labeler 4 | 5 | on: 6 | workflow_dispatch: 7 | pull_request_target: 8 | branches: ["master"] 9 | 10 | permissions: 11 | contents: read 12 | 13 | jobs: 14 | main: 15 | name: Labeler - Labeler 16 | permissions: 17 | contents: read 18 | pull-requests: write 19 | runs-on: ubuntu-latest 20 | if: ${{ github.event.pull_request.head.repo.full_name == github.repository }} 21 | steps: 22 | - name: Generate Token 23 | id: generate_token 24 | uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 25 | with: 26 | app-id: ${{ secrets.RENOVATE_APP_ID }} 27 | private-key: ${{ secrets.RENOVATE_PRIVATE_KEY }} 28 | - name: Labeler 29 | uses: actions/labeler@8558fd74291d67161a8a78ce36a881fa63b766a9 # v5.0.0 30 | with: 31 | repo-token: ${{ steps.generate_token.outputs.token }} 32 | configuration-path: .github/labeler.yaml 33 | -------------------------------------------------------------------------------- /.github/workflows/update-crds.yaml: -------------------------------------------------------------------------------- 1 | name: Update CRDs 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'renovate/**' 7 | paths: 8 | - 'setup/crds/kustomization.yaml' 9 | workflow_dispatch: # Allow manual triggering 10 | 11 | permissions: 12 | contents: write # Required for the 'Commit and push changes' step 13 | 14 | jobs: 15 | update-crds: 16 | runs-on: ubuntu-latest 17 | steps: 18 | 19 | - name: Generate Token 20 | id: generate_token 21 | uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 22 | with: 23 | app-id: ${{ secrets.RENOVATE_APP_ID }} 24 | private-key: ${{ secrets.RENOVATE_PRIVATE_KEY }} 25 | 26 | - name: Checkout 27 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 28 | with: 29 | token: ${{ steps.generate_token.outputs.token }} 30 | 31 | - name: Set up Python 32 | uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 33 | with: 34 | python-version: "3.x" 35 | 36 | - name: Update CRDs 37 | run: python .github/scripts/update_crds_local.py 38 | 39 | - name: Commit and push changes 40 | uses: stefanzweifel/git-auto-commit-action@b863ae1933cb653a53c021fe36dbb774e1fb9403 # v5 41 | with: 42 | commit_message: "Update vendored CRDs based on kustomization.yaml changes" 43 | file_pattern: setup/crds/vendor/**/*.yaml setup/crds/kustomization.yaml 44 | commit_options: "--signoff" 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Editors 3 | .vscode/ 4 | # Trash 5 | .DS_Store 6 | Thumbs.db 7 | # Binaries 8 | bin 9 | /flux 10 | *.iso 11 | # Temp 12 | .temp* 13 | /.private/ 14 | /.task/ 15 | /.venv/ 16 | Brewfile.lock.json 17 | # Kubernetes 18 | kubeconfig 19 | talosconfig 20 | # Other 21 | .env 22 | auth 23 | *.snap 24 | *.crt 25 | *.key 26 | .decrypted~* 27 | onepassword.env 28 | -------------------------------------------------------------------------------- /.renovate/allowedVersions.json5: -------------------------------------------------------------------------------- 1 | { 2 | packageRules: [ 3 | { 4 | "matchDatasources": ["docker"], 5 | "allowedVersions": "<2", 6 | "matchPackageNames": [ 7 | "influxdb" 8 | ] 9 | }, 10 | ], 11 | } -------------------------------------------------------------------------------- /.renovate/autoMerge.json5: -------------------------------------------------------------------------------- 1 | { 2 | $schema: "https://docs.renovatebot.com/renovate-schema.json", 3 | packageRules: [ 4 | // auto-updates - daily 5 | { 6 | "datasources": ["docker"], 7 | "automerge": true, 8 | automergeType: "pr", 9 | "schedule": "after 1am and before 5am", 10 | "updateTypes": ["minor", "patch"], 11 | "packageNames": [ 12 | "espresense/espresense-companion", 13 | "ghcr.io/home-assistant/home-assistant", 14 | "ghcr.io/home-operations/radarr", 15 | "ghcr.io/home-operations/sonarr", 16 | "ghcr.io/home-operations/sabnzbd", 17 | "plexinc/pms-docker", 18 | "nodered/node-red", 19 | "ghcr.io/zwave-js/zwave-js-ui", 20 | "codercom/code-server" 21 | ] 22 | }, 23 | // auto-updates - weekly 24 | { 25 | "datasources": ["docker"], 26 | "automerge": true, 27 | automergeType: "pr", 28 | "schedule": ["before 3am on Monday"], 29 | "updateTypes": ["minor", "patch"], 30 | "packageNames": [ 31 | "ghcr.io/home-operations/prowlarr", 32 | "ghcr.io/home-operations/readarr" 33 | ] 34 | }, 35 | { 36 | description: "Auto-merge trusted container digests", 37 | matchDatasources: ["docker"], 38 | automerge: true, 39 | automergeType: "pr", 40 | matchUpdateTypes: ["digest"], 41 | matchPackageNames: ["/home-operations/"], 42 | ignoreTests: false, 43 | }, 44 | { 45 | description: "Auto-merge GitHub Actions", 46 | matchManagers: ["github-actions"], 47 | automerge: true, 48 | automergeType: "branch", 49 | matchUpdateTypes: ["minor", "patch", "digest"], 50 | minimumReleaseAge: "3 days", 51 | ignoreTests: true, 52 | }, 53 | { 54 | description: "Auto-merge GitHub Releases", 55 | matchDatasources: ["github-releases"], 56 | automerge: true, 57 | automergeType: "branch", 58 | matchUpdateTypes: ["minor", "patch"], 59 | matchPackageNames: ["/external-dns/", "/gateway-api/", "/prometheus-operator/"], 60 | ignoreTests: true, 61 | }, 62 | ], 63 | } -------------------------------------------------------------------------------- /.renovate/grafanaDashboards.json5: -------------------------------------------------------------------------------- 1 | { 2 | $schema: "https://docs.renovatebot.com/renovate-schema.json", 3 | customDatasources: { 4 | "grafana-dashboards": { 5 | defaultRegistryUrlTemplate: "https://grafana.com/api/dashboards/{{packageName}}", 6 | format: "json", 7 | transformTemplates: ['{"releases":[{"version": $string(revision)}]}'], 8 | }, 9 | }, 10 | customManagers: [ 11 | { 12 | description: "Process Grafana dashboards", 13 | customType: "regex", 14 | fileMatch: ["(^|/)kubernetes/.+\\.ya?ml$"], 15 | matchStrings: [ 16 | 'depName="(?.*)"\\n(?\\s+)gnetId: (?\\d+)\\n.+revision: (?\\d+)' 17 | ], 18 | autoReplaceStringTemplate: 'depName="{{{depName}}}"\n{{{indentation}}}gnetId: {{{packageName}}}\n{{{indentation}}}revision: {{{newValue}}}', 19 | datasourceTemplate: "custom.grafana-dashboards", 20 | versioningTemplate: "regex:^(?\\d+)$", 21 | }, 22 | ], 23 | packageRules: [ 24 | { 25 | addLabels: ["renovate/grafana-dashboard"], 26 | automerge: true, 27 | automergeType: "branch", 28 | commitMessageExtra: "({{currentVersion}} → {{newVersion}})", 29 | commitMessageTopic: "dashboard {{depName}}", 30 | matchDatasources: ["custom.grafana-dashboards"], 31 | matchUpdateTypes: ["major"], 32 | semanticCommitScope: "grafana-dashboards", 33 | semanticCommitType: "chore", 34 | }, 35 | ], 36 | } -------------------------------------------------------------------------------- /.renovate/labels.json5: -------------------------------------------------------------------------------- 1 | { 2 | $schema: "https://docs.renovatebot.com/renovate-schema.json", 3 | packageRules: [ 4 | { 5 | matchUpdateTypes: ["major"], 6 | labels: ["type/major"], 7 | }, 8 | { 9 | matchUpdateTypes: ["minor"], 10 | labels: ["type/minor"], 11 | }, 12 | { 13 | matchUpdateTypes: ["patch"], 14 | labels: ["type/patch"], 15 | }, 16 | { 17 | matchUpdateTypes: ["digest"], 18 | labels: ["type/digest"], 19 | }, 20 | { 21 | matchDatasources: ["docker"], 22 | addLabels: ["renovate/container"], 23 | }, 24 | { 25 | matchDatasources: ["helm"], 26 | addLabels: ["renovate/helm"], 27 | }, 28 | { 29 | matchManagers: ["github-actions"], 30 | addLabels: ["renovate/github-action"], 31 | }, 32 | { 33 | matchDatasources: ["github-releases"], 34 | addLabels: ["renovate/github-release"], 35 | }, 36 | ], 37 | } -------------------------------------------------------------------------------- /.renovate/semanticCommits.json5: -------------------------------------------------------------------------------- 1 | { 2 | $schema: "https://docs.renovatebot.com/renovate-schema.json", 3 | packageRules: [ 4 | { 5 | matchUpdateTypes: ["major"], 6 | semanticCommitType: "feat", 7 | commitMessagePrefix: "{{semanticCommitType}}({{semanticCommitScope}})!:", 8 | commitMessageExtra: "( {{currentVersion}} → {{newVersion}} )", 9 | }, 10 | { 11 | matchUpdateTypes: ["minor"], 12 | semanticCommitType: "feat", 13 | commitMessageExtra: "( {{currentVersion}} → {{newVersion}} )", 14 | }, 15 | { 16 | matchUpdateTypes: ["patch"], 17 | semanticCommitType: "fix", 18 | commitMessageExtra: "( {{currentVersion}} → {{newVersion}} )", 19 | }, 20 | { 21 | matchUpdateTypes: ["digest"], 22 | semanticCommitType: "chore", 23 | commitMessageExtra: "( {{currentDigestShort}} → {{newDigestShort}} )", 24 | }, 25 | { 26 | matchDatasources: ["docker"], 27 | semanticCommitScope: "container", 28 | commitMessageTopic: "image {{depName}}", 29 | }, 30 | { 31 | matchDatasources: ["helm"], 32 | semanticCommitScope: "helm", 33 | commitMessageTopic: "chart {{depName}}", 34 | }, 35 | { 36 | matchManagers: ["github-actions"], 37 | semanticCommitType: "ci", 38 | semanticCommitScope: "github-action", 39 | commitMessageTopic: "action {{depName}}", 40 | }, 41 | { 42 | matchDatasources: ["github-releases"], 43 | semanticCommitScope: "github-release", 44 | commitMessageTopic: "release {{depName}}", 45 | }, 46 | ], 47 | } -------------------------------------------------------------------------------- /.taskfiles/.minijinja.toml: -------------------------------------------------------------------------------- 1 | autoescape = "none" 2 | newline = true 3 | trim-blocks = true 4 | lstrip-blocks = true 5 | env = true -------------------------------------------------------------------------------- /.taskfiles/k8s-bootstrap/Taskfile.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://taskfile.dev/schema.json 3 | version: "3" 4 | 5 | tasks: 6 | talos: 7 | desc: Bootstrap Talos 8 | vars: 9 | TALOS_CONTROLLER: 10 | sh: talosctl --talosconfig "{{.TALOSCONFIG}}" config info --output json | jq --raw-output '.endpoints[]' | shuf -n 1 11 | preconditions: 12 | - which jq minijinja-cli talosctl 13 | - test -f "{{.TALOSCONFIG}}" 14 | - talosctl config info 15 | cmds: 16 | - task: :talos:apply-clusterconfig 17 | vars: 18 | INSECURE: "true" 19 | - until talosctl --nodes {{.TALOS_CONTROLLER}} bootstrap; do sleep 5; done 20 | - talosctl kubeconfig --nodes {{.TALOS_CONTROLLER}} --force --force-context-name "home" "{{.KUBECONFIG}}" 21 | 22 | apps: 23 | desc: Bootstrap Apps 24 | prompt: Bootstrap apps into Talos cluster? 25 | preconditions: 26 | - which op helmfile kubectl 27 | - test -f "{{.TALOSCONFIG}}" 28 | - test -f {{.SETUP_DIR}}/bootstrap/helmfile.yaml 29 | - test -f {{.SETUP_DIR}}/bootstrap/templates/resources.yaml.j2 30 | - op user get --me 31 | - talosctl config info 32 | env: 33 | NODE_COUNT: 34 | sh: talosctl --talosconfig "{{.TALOSCONFIG}}" config info --output json | jq --raw-output '.nodes | length' 35 | cmds: 36 | - until kubectl wait nodes --for=condition=Ready=False --all --timeout=10m; do sleep 5; done 37 | - minijinja-cli "{{.SETUP_DIR}}/bootstrap/templates/resources.yaml.j2" | op inject | kubectl apply --server-side --filename - 38 | - helmfile --quiet --file {{.SETUP_DIR}}/bootstrap/helmfile.yaml sync --hide-notes 39 | 40 | wipe-disks: 41 | desc: Wipe disks on Talos nodes 42 | prompt: "WARNING: This will PERMANENTLY ERASE data on the specified disks. Continue?" 43 | preconditions: 44 | - which talosctl 45 | - test -f "{{.TALOSCONFIG}}" 46 | - talosctl config info 47 | vars: 48 | # See setup/talos/README.md for details on which nodes use which ceph disks that need to be wiped 49 | NODE_DISK_MAPPINGS: 50 | sh: | 51 | cat << 'EOF' 52 | 10.0.7.52:sda 53 | 10.0.7.53:sdb 54 | 10.0.7.55:sda 55 | 10.0.7.59:sda 56 | EOF 57 | 58 | cmds: 59 | - echo "The following disks will be wiped:" 60 | - cmd: | 61 | echo "{{.NODE_DISK_MAPPINGS}}" | tr ' ' '\n' 62 | - echo "Proceeding in 5 seconds... Press Ctrl+C to abort" 63 | - sleep 5 64 | - cmd: | 65 | echo "{{.NODE_DISK_MAPPINGS}}" | while IFS=: read -r node disk; do 66 | echo "Wiping disk /dev/${disk} on node ${node}..." 67 | talosctl --talosconfig "{{.TALOSCONFIG}}" wipe disk "${disk}" --nodes="${node}" || echo "Failed to wipe disk ${disk} on node ${node}, continuing..." 68 | talosctl --talosconfig "{{.TALOSCONFIG}}" get disk "${disk}" --nodes="${node}" || echo "Failed to get disk ${disk} on node ${node}, continuing..." 69 | done 70 | ignore_error: true 71 | -------------------------------------------------------------------------------- /.taskfiles/k8s/Taskfile.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://taskfile.dev/schema.json 3 | version: "3" 4 | 5 | tasks: 6 | browse-pvc: 7 | desc: Mount a PVC to an temp container [NS=default] [CLAIM=required] 8 | interactive: true 9 | cmd: kubectl browse-pvc --namespace {{.NS}} --image docker.io/library/alpine:latest {{.CLAIM}} 10 | vars: 11 | NS: '{{.NS | default "default"}}' 12 | requires: 13 | vars: [CLAIM] 14 | preconditions: 15 | - kubectl --namespace {{.NS}} get persistentvolumeclaims {{.CLAIM}} 16 | - kubectl browse-pvc --version 17 | - which kubectl 18 | 19 | node-shell: 20 | desc: Open a shell to a node [NODE=required] 21 | interactive: true 22 | cmd: kubectl node-shell -n kube-system -x {{.NODE}} 23 | requires: 24 | vars: [NODE] 25 | preconditions: 26 | - kubectl get nodes {{.NODE}} 27 | - kubectl node-shell --version 28 | - which kubectl 29 | 30 | sync-secrets: 31 | desc: Sync all ExternalSecrets 32 | cmds: 33 | - for: { var: SECRETS, split: "\n" } 34 | cmd: kubectl --namespace {{splitList "," .ITEM | first}} annotate externalsecret {{splitList "," .ITEM | last}} force-sync="{{now | unixEpoch}}" --overwrite 35 | vars: 36 | SECRETS: 37 | sh: kubectl get externalsecret --all-namespaces --no-headers --output=jsonpath='{range .items[*]}{.metadata.namespace},{.metadata.name}{"\n"}{end}' 38 | preconditions: 39 | - which kubectl 40 | 41 | cleanse-pods: 42 | desc: Cleanse pods with a Failed/Pending/Succeeded phase 43 | cmds: 44 | - for: 45 | matrix: 46 | PHASE: [Failed, Pending, Succeeded] 47 | cmd: kubectl delete pods --all-namespaces --field-selector status.phase={{.ITEM.PHASE}} --ignore-not-found=true 48 | preconditions: 49 | - which kubectl 50 | 51 | suspend-flux: 52 | desc: Suspend flux kusomization for cluster-apps 53 | preconditions: 54 | - which flux 55 | cmd: flux --namespace flux-system suspend kustomization cluster-apps 56 | 57 | resume-flux: 58 | desc: Resume flux kusomization for cluster-apps 59 | preconditions: 60 | - which flux 61 | cmd: flux --namespace flux-system resume kustomization cluster-apps 62 | -------------------------------------------------------------------------------- /.taskfiles/volsync/resources/list-snapshots.yaml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: list-snapshots-{{ ENV.APP }} 6 | namespace: {{ ENV.NS }} 7 | spec: 8 | ttlSecondsAfterFinished: 3600 9 | template: 10 | metadata: 11 | labels: 12 | app.kubernetes.io/created-by: volsync 13 | spec: 14 | automountServiceAccountToken: false 15 | restartPolicy: OnFailure 16 | containers: 17 | - name: list 18 | image: docker.io/restic/restic:0.16.2 19 | args: 20 | - snapshots 21 | envFrom: 22 | - secretRef: 23 | name: {{ ENV.APP }}-restic-secret 24 | volumeMounts: 25 | - mountPath: /repository 26 | name: repository 27 | volumes: 28 | - name: repository 29 | nfs: 30 | server: "nas.home" 31 | path: "/mnt/ssdtank/s3/volsync" -------------------------------------------------------------------------------- /.taskfiles/volsync/resources/replicationdestination.yaml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: volsync.backube/v1alpha1 3 | kind: ReplicationDestination 4 | metadata: 5 | name: {{ ENV.APP }}-manual 6 | namespace: {{ ENV.NS }} 7 | spec: 8 | trigger: 9 | manual: restore-once 10 | restic: 11 | repository: {{ ENV.APP }}-restic-secret 12 | destinationPVC: {{ ENV.CLAIM }} 13 | copyMethod: Direct 14 | storageClassName: {{ ENV.STORAGE_CLASS_NAME }} 15 | accessModes: ["ReadWriteOnce"] 16 | previous: {{ ENV.PREVIOUS }} 17 | restoreAsOf: {{ ENV.RESTORE_AS_OF }} 18 | moverSecurityContext: 19 | runAsUser: 1000 20 | runAsGroup: 1000 21 | fsGroup: 1000 22 | enableFileDeletion: true 23 | cleanupCachePVC: true 24 | cleanupTempPVC: true -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GitOps Workflow for Kubernetes Cluster 2 | 3 | ![kubefetch](https://i.imgur.com/J62ZnYF.png) 4 | 5 | Leverages [flux](https://github.com/fluxcd/flux2) to automate cluster state using code residing in this repo 6 | 7 | ## :computer:  Infrastructure 8 | 9 | See the [talos cluster setup](setup/talos/README.md) for more detail about hardware and infrastructure 10 | 11 | ## :gear:  Setup 12 | 13 | See [setup](setup/README.md) for more detail about setup & bootstrapping a new cluster 14 | 15 | ## :wrench:  Workloads (by namespace in kubernetes/) 16 | 17 | * [cert-manager](kubernetes/cert-manager/) 18 | * [default](kubernetes/default/) 19 | * [flux-system](kubernetes/flux-system/) 20 | * [kube-system](kubernetes/kube-system/) 21 | * [monitoring](kubernetes/monitoring/) 22 | * [rook-ceph](kubernetes/rook-ceph/) 23 | * [system-upgrade](kubernetes/system-upgrade/) 24 | 25 | ## :robot:  Automation 26 | 27 | * [Renovate](https://github.com/renovatebot/renovate) keeps workloads up-to-date by scanning the repo and opening pull requests when it detects a new container image update or a new helm chart 28 | * [System Upgrade Controller](https://github.com/rancher/system-upgrade-controller) automatically upgrades talos and kubernetes to new versions as they are released 29 | 30 | ## :handshake:  Community 31 | 32 | There is a k8s@home [Discord](https://discord.gg/7PbmHRK) for this community. 33 | -------------------------------------------------------------------------------- /Taskfile.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://taskfile.dev/schema.json 3 | version: "3" 4 | 5 | set: 6 | - pipefail 7 | shopt: 8 | - globstar 9 | 10 | includes: 11 | k8s: .taskfiles/k8s 12 | k8s-bootstrap: .taskfiles/k8s-bootstrap 13 | talos: .taskfiles/talos 14 | volsync: .taskfiles/volsync 15 | 16 | vars: 17 | K8S_DIR: "{{.ROOT_DIR}}/kubernetes" 18 | SETUP_DIR: "{{.ROOT_DIR}}/setup" 19 | KUBECONFIG: "{{.ROOT_DIR}}/kubeconfig" 20 | MINIJINJA_CONFIG_FILE: "{{.ROOT_DIR}}/.taskfiles/.minijinja.toml" 21 | TALOSCONFIG: "{{.SETUP_DIR}}/talos/clusterconfig/talosconfig" 22 | 23 | env: 24 | KUBECONFIG: "{{.KUBECONFIG}}" 25 | MINIJINJA_CONFIG_FILE: "{{.MINIJINJA_CONFIG_FILE}}" 26 | TALOSCONFIG: "{{.TALOSCONFIG}}" 27 | 28 | tasks: 29 | default: 30 | silent: true 31 | cmd: task --list 32 | 33 | noop: 34 | internal: true 35 | silent: true 36 | cmd: noop() { :; } -------------------------------------------------------------------------------- /kubernetes/cert-manager/README.md: -------------------------------------------------------------------------------- 1 | # cert-manager 2 | 3 | [cert-manager](https://github.com/jetstack/cert-manager) for natively automatically obtaining and renewing LetsEncrypt certificates 4 | 5 | * [cert-manager-chart.yaml](cert-manager-chart.yaml) 6 | * [prometheusRules.yaml](prometheusRules.yaml) 7 | * [cloudflare/cert-manager-cloudflare-api-key.yaml](cloudflare/cert-manager-cloudflare-api-key.yaml) 8 | * [cloudflare/cert-manager-letsencrypt.txt](cloudflare/cert-manager-letsencrypt.txt) 9 | -------------------------------------------------------------------------------- /kubernetes/cert-manager/cert-manager.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/helmrelease-helm-v2.json 3 | apiVersion: helm.toolkit.fluxcd.io/v2 4 | kind: HelmRelease 5 | metadata: 6 | name: cert-manager 7 | namespace: cert-manager 8 | spec: 9 | interval: 30m 10 | chart: 11 | spec: 12 | chart: cert-manager 13 | version: v1.17.2 14 | sourceRef: 15 | kind: HelmRepository 16 | name: jetstack 17 | namespace: flux-system 18 | interval: 30m 19 | install: 20 | crds: CreateReplace 21 | upgrade: 22 | crds: CreateReplace 23 | values: 24 | crds: 25 | enabled: true 26 | dns01RecursiveNameservers: https://1.1.1.1:443/dns-query,https://1.0.0.1:443/dns-query 27 | dns01RecursiveNameserversOnly: true 28 | prometheus: 29 | enabled: true 30 | servicemonitor: 31 | enabled: true -------------------------------------------------------------------------------- /kubernetes/cert-manager/cloudflare/cert-manager-cloudflare-api-key.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: cloudflare-api-key 7 | namespace: cert-manager 8 | spec: 9 | refreshInterval: 5m 10 | secretStoreRef: 11 | kind: ClusterSecretStore 12 | name: onepassword-connect 13 | target: 14 | name: cloudflare-api-key 15 | creationPolicy: Owner 16 | dataFrom: 17 | - extract: 18 | key: cloudflare 19 | -------------------------------------------------------------------------------- /kubernetes/cert-manager/cloudflare/cert-manager-letsencrypt.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/cert-manager.io/clusterissuer_v1.json 3 | apiVersion: cert-manager.io/v1 4 | kind: ClusterIssuer 5 | metadata: 6 | name: letsencrypt-test 7 | spec: 8 | acme: 9 | email: jeff@billimek.com 10 | server: https://acme-staging-v02.api.letsencrypt.org/directory 11 | privateKeySecretRef: 12 | name: letsencrypt-test 13 | solvers: 14 | # An empty 'selector' means that this solver matches all domains 15 | - selector: {} 16 | dns01: 17 | cloudflare: 18 | email: jeff@billimek.com 19 | apiKeySecretRef: 20 | name: cloudflare-api-key 21 | key: api-key 22 | --- 23 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/cert-manager.io/clusterissuer_v1.json 24 | apiVersion: cert-manager.io/v1 25 | kind: ClusterIssuer 26 | metadata: 27 | name: letsencrypt-prod 28 | spec: 29 | acme: 30 | email: jeff@billimek.com 31 | server: https://acme-v02.api.letsencrypt.org/directory 32 | privateKeySecretRef: 33 | name: letsencrypt-prod 34 | solvers: 35 | # An empty 'selector' means that this solver matches all domains 36 | - selector: {} 37 | dns01: 38 | cloudflare: 39 | email: jeff@billimek.com 40 | apiKeySecretRef: 41 | name: cloudflare-api-key 42 | key: api-key 43 | --- 44 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/cert-manager.io/certificate_v1.json 45 | apiVersion: cert-manager.io/v1 46 | kind: Certificate 47 | metadata: 48 | name: acme-crt 49 | namespace: cert-manager 50 | spec: 51 | secretName: acme-crt-secret 52 | issuerRef: 53 | name: letsencrypt-prod 54 | kind: ClusterIssuer 55 | dnsNames: 56 | - eviljungle.com 57 | - '*.eviljungle.com' 58 | - '*.t.eviljungle.com' 59 | -------------------------------------------------------------------------------- /kubernetes/default/audiobookshelf/volsync.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://crd.movishell.pl/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: audiobookshelf-restic 7 | namespace: default 8 | spec: 9 | secretStoreRef: 10 | kind: ClusterSecretStore 11 | name: onepassword-connect 12 | target: 13 | name: audiobookshelf-restic-secret 14 | creationPolicy: Owner 15 | template: 16 | engineVersion: v2 17 | data: 18 | RESTIC_REPOSITORY: '{{ .REPOSITORY_TEMPLATE }}/audiobookshelf' 19 | RESTIC_PASSWORD: '{{ .RESTIC_PASSWORD }}' 20 | AWS_ACCESS_KEY_ID: '{{ .MINIO_ACCESS_KEY }}' 21 | AWS_SECRET_ACCESS_KEY: '{{ .MINIO_SECRET_KEY }}' 22 | dataFrom: 23 | - extract: 24 | key: minio 25 | --- 26 | # yaml-language-server: $schema=https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/volsync.backube/replicationsource_v1alpha1.json 27 | apiVersion: volsync.backube/v1alpha1 28 | kind: ReplicationSource 29 | metadata: 30 | name: audiobookshelf 31 | namespace: default 32 | spec: 33 | sourcePVC: audiobookshelf-config 34 | trigger: 35 | schedule: "0 6 * * *" 36 | restic: 37 | copyMethod: Snapshot 38 | pruneIntervalDays: 10 39 | repository: audiobookshelf-restic-secret 40 | cacheCapacity: 1Gi 41 | volumeSnapshotClassName: csi-ceph-blockpool 42 | storageClassName: ceph-block 43 | moverSecurityContext: 44 | runAsUser: 1001 45 | runAsGroup: 1001 46 | fsGroup: 1001 47 | retain: 48 | daily: 10 49 | within: 3d -------------------------------------------------------------------------------- /kubernetes/default/cloudnative-pg/chart/cloudnative-pg.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/helmrelease-helm-v2.json 3 | apiVersion: helm.toolkit.fluxcd.io/v2 4 | kind: HelmRelease 5 | metadata: 6 | name: cloudnative-pg 7 | namespace: default 8 | spec: 9 | interval: 1h 10 | chart: 11 | spec: 12 | chart: cloudnative-pg 13 | version: 0.24.0 14 | sourceRef: 15 | kind: HelmRepository 16 | name: cloudnative-pg 17 | namespace: flux-system 18 | install: 19 | remediation: 20 | retries: -1 21 | upgrade: 22 | cleanupOnFail: true 23 | remediation: 24 | retries: 3 25 | values: 26 | crds: 27 | create: true 28 | -------------------------------------------------------------------------------- /kubernetes/default/cloudnative-pg/chart/externalsecret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://crd.movishell.pl/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: cloudnative-pg 7 | namespace: default 8 | spec: 9 | secretStoreRef: 10 | kind: ClusterSecretStore 11 | name: onepassword-connect 12 | target: 13 | name: cloudnative-pg-secret 14 | creationPolicy: Owner 15 | template: 16 | engineVersion: v2 17 | metadata: 18 | labels: 19 | cnpg.io/reload: "true" 20 | data: 21 | - secretKey: username 22 | remoteRef: 23 | key: cloudnative-pg 24 | property: POSTGRES_SUPER_USER 25 | - secretKey: password 26 | remoteRef: 27 | key: cloudnative-pg 28 | property: POSTGRES_SUPER_PASS 29 | - secretKey: aws-access-key-id 30 | remoteRef: 31 | key: minio 32 | property: MINIO_ACCESS_KEY 33 | - secretKey: aws-secret-access-key 34 | remoteRef: 35 | key: minio 36 | property: MINIO_SECRET_KEY 37 | -------------------------------------------------------------------------------- /kubernetes/default/cloudnative-pg/cluster/cluster-v17.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/postgresql.cnpg.io/cluster_v1.json 3 | apiVersion: postgresql.cnpg.io/v1 4 | kind: Cluster 5 | metadata: 6 | name: postgres-v17 7 | namespace: default 8 | spec: 9 | # using only 1 replica: very difficult to drain the node where postgres is running 10 | # using more than 1 replica: write amplification issues when leveraging replicated storage (e.g. ceph) 11 | instances: 2 12 | imageName: ghcr.io/cloudnative-pg/postgresql:17.4 13 | primaryUpdateStrategy: unsupervised 14 | storage: 15 | size: 20Gi 16 | storageClass: ceph-block 17 | enableSuperuserAccess: true 18 | superuserSecret: 19 | name: cloudnative-pg-secret 20 | postgresql: 21 | parameters: 22 | max_connections: "300" 23 | shared_buffers: 512MB 24 | pg_stat_statements.max: "10000" 25 | pg_stat_statements.track: all 26 | monitoring: 27 | enablePodMonitor: true 28 | # https://github.com/cloudnative-pg/cloudnative-pg/issues/2570 29 | enablePDB: false 30 | resources: 31 | requests: 32 | memory: "512Mi" 33 | cpu: "250m" 34 | limits: 35 | memory: "4Gi" 36 | backup: 37 | retentionPolicy: 30d 38 | barmanObjectStore: 39 | wal: 40 | compression: bzip2 41 | maxParallel: 8 42 | destinationPath: s3://postgresql/ 43 | endpointURL: http://nas.home:9000 44 | serverName: postgres-v17 45 | s3Credentials: 46 | accessKeyId: 47 | name: cloudnative-pg-secret 48 | key: aws-access-key-id 49 | secretAccessKey: 50 | name: cloudnative-pg-secret 51 | key: aws-secret-access-key 52 | 53 | # bootstrap: 54 | # use this to recover a net-new cluster from a backup 55 | # recovery: 56 | # source: postgres-backup # TODO: fix this to the real name of the backup when on the new cluster 57 | 58 | # # use this to 'migrate' from an existing cnpg cluster (e.g. "postgres-v15") to the new cluster 59 | # initdb: 60 | # import: 61 | # type: monolith 62 | # databases: 63 | # - "*" 64 | # roles: 65 | # - "*" 66 | # source: 67 | # externalCluster: postgres-v15 68 | 69 | externalClusters: 70 | # this represents an existing cnpg cluster to migrate from (e.g. upgrading from postgres v14 to postgres v15) 71 | - name: postgres-v15 72 | connectionParameters: 73 | host: postgres-v15-rw.default.svc.cluster.local 74 | user: postgres 75 | dbname: postgres 76 | sslmode: require 77 | password: 78 | name: cloudnative-pg-secret 79 | key: password 80 | -------------------------------------------------------------------------------- /kubernetes/default/cloudnative-pg/cluster/scheduledbackup.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: postgresql.cnpg.io/v1 3 | kind: ScheduledBackup 4 | metadata: 5 | name: postgres-v17 6 | namespace: default 7 | spec: 8 | # daily, 2am UCT 9 | schedule: "0 0 2 * * *" 10 | immediate: true 11 | backupOwnerReference: self 12 | cluster: 13 | name: postgres-v17 14 | -------------------------------------------------------------------------------- /kubernetes/default/cloudnative-pg/cluster/service.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: postgres-lb 6 | namespace: default 7 | spec: 8 | type: LoadBalancer 9 | externalTrafficPolicy: Local 10 | loadBalancerIP: 10.0.6.51 11 | ports: 12 | - name: postgres 13 | port: 5432 14 | protocol: TCP 15 | targetPort: 5432 16 | selector: 17 | cnpg.io/cluster: postgres-v17 18 | role: primary -------------------------------------------------------------------------------- /kubernetes/default/echo-server/echo-server.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/helmrelease-helm-v2.json 3 | apiVersion: helm.toolkit.fluxcd.io/v2 4 | kind: HelmRelease 5 | metadata: 6 | name: echo-server 7 | namespace: default 8 | spec: 9 | interval: 1h 10 | chart: 11 | spec: 12 | chart: app-template 13 | version: 4.0.1 14 | sourceRef: 15 | kind: HelmRepository 16 | name: bjw-s 17 | namespace: flux-system 18 | install: 19 | remediation: 20 | retries: -1 21 | upgrade: 22 | cleanupOnFail: true 23 | remediation: 24 | retries: 3 25 | values: 26 | controllers: 27 | echo-server: 28 | containers: 29 | app: 30 | image: 31 | repository: ghcr.io/mendhak/http-https-echo 32 | tag: 37 33 | env: 34 | HTTP_PORT: &port 8080 35 | LOG_WITHOUT_NEWLINE: "true" 36 | LOG_IGNORE_PATH: "/healthz" 37 | probes: 38 | liveness: 39 | enabled: true 40 | readiness: 41 | enabled: true 42 | startup: 43 | enabled: true 44 | spec: 45 | failureThreshold: 30 46 | periodSeconds: 5 47 | resources: 48 | requests: 49 | cpu: 5m 50 | memory: 64M 51 | limits: 52 | memory: 64M 53 | 54 | service: 55 | app: 56 | controller: echo-server 57 | ports: 58 | http: 59 | port: *port 60 | 61 | ingress: 62 | app: 63 | enabled: true 64 | # ensure that external DNS (cloudflare) has an entry for this directed to the router 65 | # ensure that internal DNS for this zone (coredns) has an entry for this directed to nginx LB IP 66 | className: nginx 67 | hosts: 68 | - host: &host www.eviljungle.com 69 | paths: 70 | - path: / 71 | pathType: Prefix 72 | service: 73 | identifier: app 74 | port: http 75 | tls: 76 | - hosts: 77 | - *host 78 | tailscale: 79 | enabled: true 80 | className: nginx-tailscale 81 | hosts: 82 | - host: *host 83 | paths: 84 | - path: / 85 | pathType: Prefix 86 | service: 87 | identifier: app 88 | port: http 89 | tls: 90 | - hosts: 91 | - *host 92 | -------------------------------------------------------------------------------- /kubernetes/default/emqx/cluster.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/apps.emqx.io/emqx_v2beta1.json 3 | apiVersion: apps.emqx.io/v2beta1 4 | kind: EMQX 5 | metadata: 6 | name: emqx 7 | namespace: default 8 | spec: 9 | image: public.ecr.aws/emqx/emqx:5.8.6 10 | config: 11 | data: | 12 | authentication { 13 | backend = "built_in_database" 14 | mechanism = "password_based" 15 | password_hash_algorithm { 16 | name = "bcrypt" 17 | } 18 | user_id_type = "username" 19 | bootstrap_file = "/opt/init-user.json" 20 | bootstrap_type = "plain" 21 | } 22 | authorization { 23 | sources = [ 24 | { 25 | type = built_in_database 26 | enable = true 27 | } 28 | { 29 | type = file 30 | path = "/opt/init-acl" 31 | } 32 | ] 33 | no_match: "deny" 34 | } 35 | coreTemplate: 36 | spec: 37 | replicas: 2 38 | envFrom: 39 | - secretRef: 40 | name: emqx-secret 41 | extraVolumeMounts: 42 | - name: init-user 43 | mountPath: /opt/init-user.json 44 | subPath: init-user.json 45 | readOnly: true 46 | - name: init-user 47 | mountPath: /opt/init-acl 48 | subPath: init-acl 49 | readOnly: true 50 | extraVolumes: 51 | - name: init-user 52 | secret: 53 | secretName: emqx-init-user-secret 54 | listenersServiceTemplate: 55 | spec: 56 | type: LoadBalancer 57 | loadBalancerIP: 10.0.6.50 58 | -------------------------------------------------------------------------------- /kubernetes/default/emqx/emqx-operator.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/helmrelease-helm-v2.json 3 | apiVersion: helm.toolkit.fluxcd.io/v2 4 | kind: HelmRelease 5 | metadata: 6 | name: emqx-operator 7 | namespace: default 8 | spec: 9 | interval: 30m 10 | chart: 11 | spec: 12 | chart: emqx-operator 13 | version: 2.2.29 14 | sourceRef: 15 | kind: HelmRepository 16 | name: emqx-charts 17 | namespace: flux-system 18 | interval: 5m 19 | install: 20 | crds: CreateReplace 21 | upgrade: 22 | crds: CreateReplace 23 | values: 24 | fullnameOverride: emqx-operator 25 | image: 26 | repository: ghcr.io/emqx/emqx-operator -------------------------------------------------------------------------------- /kubernetes/default/emqx/externalsecret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: emqx 7 | namespace: default 8 | spec: 9 | refreshInterval: 5m 10 | secretStoreRef: 11 | kind: ClusterSecretStore 12 | name: onepassword-connect 13 | target: 14 | name: emqx-secret 15 | creationPolicy: Owner 16 | template: 17 | data: 18 | EMQX_DASHBOARD__DEFAULT_USERNAME: '{{ index . "admin_username" }}' 19 | EMQX_DASHBOARD__DEFAULT_PASSWORD: '{{ index . "admin_password" }}' 20 | dataFrom: 21 | - extract: 22 | key: emqx 23 | --- 24 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/external-secrets.io/externalsecret_v1beta1.json 25 | apiVersion: external-secrets.io/v1 26 | kind: ExternalSecret 27 | metadata: 28 | name: emqx-init-user 29 | namespace: default 30 | spec: 31 | refreshInterval: 5m 32 | secretStoreRef: 33 | kind: ClusterSecretStore 34 | name: onepassword-connect 35 | target: 36 | name: emqx-init-user-secret 37 | template: 38 | data: 39 | init-user.json: | 40 | [ 41 | {"user_id": "{{ index . "admin_username" }}", "password": "{{ index . "admin_password" }}", "is_superuser": true}, 42 | {"user_id": "{{ index . "user_mqtt_username" }}", "password": "{{ index . "user_mqtt_password" }}", "is_superuser": false} 43 | ] 44 | init-acl: | 45 | {allow, {user, "{{ index . "user_mqtt_username" }}"}, all, ["#"]}. 46 | dataFrom: 47 | - extract: 48 | key: emqx 49 | -------------------------------------------------------------------------------- /kubernetes/default/emqx/ingress.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: networking.k8s.io/v1 3 | kind: Ingress 4 | metadata: 5 | name: emqx-dashboard 6 | namespace: default 7 | spec: 8 | ingressClassName: nginx-tailscale 9 | rules: 10 | - host: "emqx.eviljungle.com" 11 | http: 12 | paths: 13 | - path: / 14 | pathType: Prefix 15 | backend: 16 | service: 17 | name: emqx-dashboard 18 | port: 19 | number: 18083 20 | -------------------------------------------------------------------------------- /kubernetes/default/frigate/externalsecret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://crd.movishell.pl/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: frigate 7 | namespace: default 8 | spec: 9 | secretStoreRef: 10 | kind: ClusterSecretStore 11 | name: onepassword-connect 12 | target: 13 | name: frigate-secret 14 | creationPolicy: Owner 15 | dataFrom: 16 | - extract: 17 | key: frigate 18 | -------------------------------------------------------------------------------- /kubernetes/default/frigate/volsync.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://crd.movishell.pl/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: frigate-restic 7 | namespace: default 8 | spec: 9 | secretStoreRef: 10 | kind: ClusterSecretStore 11 | name: onepassword-connect 12 | target: 13 | name: frigate-restic-secret 14 | creationPolicy: Owner 15 | template: 16 | engineVersion: v2 17 | data: 18 | RESTIC_REPOSITORY: '{{ .REPOSITORY_TEMPLATE }}/frigate' 19 | RESTIC_PASSWORD: '{{ .RESTIC_PASSWORD }}' 20 | AWS_ACCESS_KEY_ID: '{{ .MINIO_ACCESS_KEY }}' 21 | AWS_SECRET_ACCESS_KEY: '{{ .MINIO_SECRET_KEY }}' 22 | dataFrom: 23 | - extract: 24 | key: minio 25 | --- 26 | # yaml-language-server: $schema=https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/volsync.backube/replicationsource_v1alpha1.json 27 | apiVersion: volsync.backube/v1alpha1 28 | kind: ReplicationSource 29 | metadata: 30 | name: frigate 31 | namespace: default 32 | spec: 33 | sourcePVC: frigate-config 34 | trigger: 35 | schedule: "0 4 * * *" 36 | restic: 37 | copyMethod: Snapshot 38 | pruneIntervalDays: 10 39 | repository: frigate-restic-secret 40 | cacheCapacity: 10Gi 41 | volumeSnapshotClassName: csi-ceph-blockpool 42 | storageClassName: ceph-block 43 | moverSecurityContext: 44 | runAsUser: 1000 45 | runAsGroup: 1000 46 | fsGroup: 1000 47 | retain: 48 | daily: 10 49 | within: 3d 50 | -------------------------------------------------------------------------------- /kubernetes/default/home-assistant/externalsecret-gcp-sa.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://crd.movishell.pl/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: home-assistant-gcp-sa 7 | namespace: default 8 | spec: 9 | secretStoreRef: 10 | kind: ClusterSecretStore 11 | name: onepassword-connect 12 | target: 13 | name: home-assistant-gcp-sa-secret 14 | creationPolicy: Owner 15 | data: 16 | - secretKey: home-assistant-4d8d1f2ca10f.json 17 | remoteRef: 18 | key: home-assistant-gcp-sa 19 | property: home-assistant-4d8d1f2ca10f.json 20 | -------------------------------------------------------------------------------- /kubernetes/default/home-assistant/externalsecret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://crd.movishell.pl/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: home-assistant 7 | namespace: default 8 | spec: 9 | secretStoreRef: 10 | kind: ClusterSecretStore 11 | name: onepassword-connect 12 | target: 13 | name: home-assistant-secret 14 | creationPolicy: Owner 15 | template: 16 | engineVersion: v2 17 | data: 18 | # Home Assistant 19 | CAMERA_AUTH: "{{ .CAMERA_AUTH }}" 20 | HASS_TOKEN: "{{ .HASS_TOKEN }}" 21 | LATITUDE: "{{ .LATITUDE }}" 22 | LONGITUDE: "{{ .LONGITUDE }}" 23 | WORK_LATITUDE: "{{ .WORK_LATITUDE }}" 24 | WORK_LONGITUDE: "{{ .WORK_LONGITUDE }}" 25 | SSC_LATITUDE: "{{ .SSC_LATITUDE }}" 26 | SSC_LONGITUDE: "{{ .SSC_LONGITUDE }}" 27 | JENS_WORK_LATITUDE: "{{ .JENS_WORK_LATITUDE }}" 28 | JENS_WORK_LONGITUDE: "{{ .JENS_WORK_LONGITUDE }}" 29 | ALARMCD: "{{ .ALARMCD }}" 30 | SECURE_DEVICES_PIN: "{{ .SECURE_DEVICES_PIN }}" 31 | JEFF_WATCH_IRK: "{{ .JEFF_WATCH_IRK }}" 32 | JEFF_PHONE_IRK: "{{ .JEFF_PHONE_IRK }}" 33 | JEN_WATCH_IRK: "{{ .JEN_WATCH_IRK }}" 34 | JEN_PHONE_IRK: "{{ .JEN_PHONE_IRK }}" 35 | ANSLEY_WATCH_IRK: "{{ .ANSLEY_WATCH_IRK }}" 36 | ANSLEY_PHONE_IRK: "{{ .ANSLEY_PHONE_IRK }}" 37 | BRINLEY_PHONE_IRK: "{{ .BRINLEY_PHONE_IRK }}" 38 | OPNSENSE_USER: "{{ .OPNSENSE_USER }}" 39 | OPNSENSE_KEY: "{{ .OPNSENSE_KEY }}" 40 | O365_APP_ID: "{{ .O365_APP_ID }}" 41 | O365_CLIENT_SECRET: "{{ .O365_CLIENT_SECRET }}" 42 | dataFrom: 43 | - extract: 44 | key: home-assistant 45 | -------------------------------------------------------------------------------- /kubernetes/default/home-assistant/volsync.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://crd.movishell.pl/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: home-assistant-restic 7 | namespace: default 8 | spec: 9 | secretStoreRef: 10 | kind: ClusterSecretStore 11 | name: onepassword-connect 12 | target: 13 | name: home-assistant-restic-secret 14 | creationPolicy: Owner 15 | template: 16 | engineVersion: v2 17 | data: 18 | RESTIC_REPOSITORY: '{{ .REPOSITORY_TEMPLATE }}/home-assistant' 19 | RESTIC_PASSWORD: '{{ .RESTIC_PASSWORD }}' 20 | AWS_ACCESS_KEY_ID: '{{ .MINIO_ACCESS_KEY }}' 21 | AWS_SECRET_ACCESS_KEY: '{{ .MINIO_SECRET_KEY }}' 22 | dataFrom: 23 | - extract: 24 | key: minio 25 | --- 26 | # yaml-language-server: $schema=https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/volsync.backube/replicationsource_v1alpha1.json 27 | apiVersion: volsync.backube/v1alpha1 28 | kind: ReplicationSource 29 | metadata: 30 | name: home-assistant 31 | namespace: default 32 | spec: 33 | sourcePVC: home-assistant-config 34 | trigger: 35 | schedule: "40 4 * * *" 36 | restic: 37 | copyMethod: Snapshot 38 | pruneIntervalDays: 10 39 | repository: home-assistant-restic-secret 40 | cacheCapacity: 60Gi 41 | volumeSnapshotClassName: csi-ceph-blockpool 42 | storageClassName: ceph-block 43 | moverSecurityContext: 44 | runAsUser: 1000 45 | runAsGroup: 1000 46 | fsGroup: 1000 47 | retain: 48 | daily: 10 49 | within: 3d 50 | -------------------------------------------------------------------------------- /kubernetes/default/jellyseerr/volsync.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://crd.movishell.pl/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: jellyseerr-restic 7 | namespace: default 8 | spec: 9 | secretStoreRef: 10 | kind: ClusterSecretStore 11 | name: onepassword-connect 12 | target: 13 | name: jellyseerr-restic-secret 14 | creationPolicy: Owner 15 | template: 16 | engineVersion: v2 17 | data: 18 | RESTIC_REPOSITORY: '{{ .REPOSITORY_TEMPLATE }}/jellyseerr' 19 | RESTIC_PASSWORD: '{{ .RESTIC_PASSWORD }}' 20 | AWS_ACCESS_KEY_ID: '{{ .MINIO_ACCESS_KEY }}' 21 | AWS_SECRET_ACCESS_KEY: '{{ .MINIO_SECRET_KEY }}' 22 | dataFrom: 23 | - extract: 24 | key: minio 25 | --- 26 | # yaml-language-server: $schema=https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/volsync.backube/replicationsource_v1alpha1.json 27 | apiVersion: volsync.backube/v1alpha1 28 | kind: ReplicationSource 29 | metadata: 30 | name: jellyseerr 31 | namespace: default 32 | spec: 33 | sourcePVC: jellyseerr-config 34 | trigger: 35 | schedule: "30 5 * * *" 36 | restic: 37 | copyMethod: Snapshot 38 | pruneIntervalDays: 10 39 | repository: jellyseerr-restic-secret 40 | cacheCapacity: 2Gi 41 | volumeSnapshotClassName: csi-ceph-blockpool 42 | storageClassName: ceph-block 43 | moverSecurityContext: 44 | runAsUser: 1001 45 | runAsGroup: 1001 46 | fsGroup: 1001 47 | retain: 48 | daily: 10 49 | within: 3d 50 | -------------------------------------------------------------------------------- /kubernetes/default/node-red/node-red.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/helmrelease-helm-v2.json 3 | apiVersion: helm.toolkit.fluxcd.io/v2 4 | kind: HelmRelease 5 | metadata: 6 | name: node-red 7 | namespace: default 8 | spec: 9 | interval: 1h 10 | chart: 11 | spec: 12 | chart: app-template 13 | version: 4.0.1 14 | sourceRef: 15 | kind: HelmRepository 16 | name: bjw-s 17 | namespace: flux-system 18 | install: 19 | remediation: 20 | retries: -1 21 | upgrade: 22 | cleanupOnFail: true 23 | remediation: 24 | retries: 3 25 | values: 26 | controllers: 27 | main: 28 | pod: 29 | securityContext: 30 | runAsUser: 1000 31 | runAsGroup: 1000 32 | runAsNonRoot: true 33 | fsGroup: 1000 34 | fsGroupChangePolicy: "OnRootMismatch" 35 | containers: 36 | main: 37 | image: 38 | repository: nodered/node-red 39 | tag: 4.0.9-18-minimal 40 | env: 41 | TZ: "America/New_York" 42 | FLOWS: "flows.json" 43 | NODE_RED_ENABLE_PROJECTS: "true" 44 | NODE_RED_ENABLE_SAFE_MODE: "false" 45 | resources: 46 | requests: 47 | memory: 350Mi 48 | cpu: 150m 49 | limits: 50 | memory: 1Gi 51 | service: 52 | main: 53 | controller: main 54 | type: ClusterIP 55 | ports: 56 | http: 57 | port: &port 1880 58 | ingress: 59 | main: 60 | className: "nginx-tailscale" 61 | hosts: 62 | - host: &host "node-red.eviljungle.com" 63 | paths: 64 | - path: / 65 | pathType: Prefix 66 | service: 67 | identifier: main 68 | port: http 69 | tls: 70 | - hosts: 71 | - *host 72 | persistence: 73 | data: 74 | suffix: data 75 | storageClass: "ceph-block" 76 | accessMode: ReadWriteOnce 77 | size: "5Gi" 78 | globalMounts: 79 | - path: /data 80 | -------------------------------------------------------------------------------- /kubernetes/default/node-red/volsync.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://crd.movishell.pl/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: node-red-restic 7 | namespace: default 8 | spec: 9 | secretStoreRef: 10 | kind: ClusterSecretStore 11 | name: onepassword-connect 12 | target: 13 | name: node-red-restic-secret 14 | creationPolicy: Owner 15 | template: 16 | engineVersion: v2 17 | data: 18 | RESTIC_REPOSITORY: '{{ .REPOSITORY_TEMPLATE }}/node-red' 19 | RESTIC_PASSWORD: '{{ .RESTIC_PASSWORD }}' 20 | AWS_ACCESS_KEY_ID: '{{ .MINIO_ACCESS_KEY }}' 21 | AWS_SECRET_ACCESS_KEY: '{{ .MINIO_SECRET_KEY }}' 22 | dataFrom: 23 | - extract: 24 | key: minio 25 | --- 26 | # yaml-language-server: $schema=https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/volsync.backube/replicationsource_v1alpha1.json 27 | apiVersion: volsync.backube/v1alpha1 28 | kind: ReplicationSource 29 | metadata: 30 | name: node-red 31 | namespace: default 32 | spec: 33 | sourcePVC: node-red-data 34 | trigger: 35 | schedule: "20 5 * * *" 36 | restic: 37 | copyMethod: Snapshot 38 | pruneIntervalDays: 10 39 | repository: node-red-restic-secret 40 | cacheCapacity: 10Gi 41 | volumeSnapshotClassName: csi-ceph-blockpool 42 | storageClassName: ceph-block 43 | moverSecurityContext: 44 | runAsUser: 1000 45 | runAsGroup: 1000 46 | fsGroup: 1000 47 | retain: 48 | daily: 10 49 | within: 3d 50 | -------------------------------------------------------------------------------- /kubernetes/default/plex/externalsecret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://crd.movishell.pl/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: plex 7 | namespace: default 8 | spec: 9 | secretStoreRef: 10 | kind: ClusterSecretStore 11 | name: onepassword-connect 12 | target: 13 | name: plex-secret 14 | creationPolicy: Owner 15 | dataFrom: 16 | - extract: 17 | # PLEX_CLAIM 18 | key: plex 19 | -------------------------------------------------------------------------------- /kubernetes/default/plex/volsync.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://crd.movishell.pl/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: plex-restic 7 | namespace: default 8 | spec: 9 | secretStoreRef: 10 | kind: ClusterSecretStore 11 | name: onepassword-connect 12 | target: 13 | name: plex-restic-secret 14 | creationPolicy: Owner 15 | template: 16 | engineVersion: v2 17 | data: 18 | RESTIC_REPOSITORY: '{{ .REPOSITORY_TEMPLATE }}/plex' 19 | RESTIC_PASSWORD: '{{ .RESTIC_PASSWORD }}' 20 | AWS_ACCESS_KEY_ID: '{{ .MINIO_ACCESS_KEY }}' 21 | AWS_SECRET_ACCESS_KEY: '{{ .MINIO_SECRET_KEY }}' 22 | dataFrom: 23 | - extract: 24 | key: minio 25 | --- 26 | # yaml-language-server: $schema=https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/volsync.backube/replicationsource_v1alpha1.json 27 | apiVersion: volsync.backube/v1alpha1 28 | kind: ReplicationSource 29 | metadata: 30 | name: plex 31 | namespace: default 32 | spec: 33 | sourcePVC: plex-config 34 | trigger: 35 | schedule: "40 5 * * *" 36 | restic: 37 | copyMethod: Snapshot 38 | pruneIntervalDays: 10 39 | repository: plex-restic-secret 40 | cacheCapacity: 65Gi 41 | volumeSnapshotClassName: csi-ceph-blockpool 42 | storageClassName: ceph-block 43 | moverSecurityContext: 44 | runAsUser: 1000 45 | runAsGroup: 1000 46 | fsGroup: 1000 47 | retain: 48 | daily: 10 49 | within: 3d 50 | -------------------------------------------------------------------------------- /kubernetes/default/prowlarr/externalsecret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: prowlarr 7 | namespace: default 8 | spec: 9 | refreshInterval: 5m 10 | secretStoreRef: 11 | kind: ClusterSecretStore 12 | name: onepassword-connect 13 | target: 14 | name: prowlarr-secret 15 | creationPolicy: Owner 16 | data: 17 | - secretKey: api_key 18 | remoteRef: 19 | key: prowlarr 20 | property: api_key 21 | -------------------------------------------------------------------------------- /kubernetes/default/prowlarr/volsync.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://crd.movishell.pl/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: prowlarr-restic 7 | namespace: default 8 | spec: 9 | secretStoreRef: 10 | kind: ClusterSecretStore 11 | name: onepassword-connect 12 | target: 13 | name: prowlarr-restic-secret 14 | creationPolicy: Owner 15 | template: 16 | engineVersion: v2 17 | data: 18 | RESTIC_REPOSITORY: '{{ .REPOSITORY_TEMPLATE }}/prowlarr' 19 | RESTIC_PASSWORD: '{{ .RESTIC_PASSWORD }}' 20 | AWS_ACCESS_KEY_ID: '{{ .MINIO_ACCESS_KEY }}' 21 | AWS_SECRET_ACCESS_KEY: '{{ .MINIO_SECRET_KEY }}' 22 | dataFrom: 23 | - extract: 24 | key: minio 25 | --- 26 | # yaml-language-server: $schema=https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/volsync.backube/replicationsource_v1alpha1.json 27 | apiVersion: volsync.backube/v1alpha1 28 | kind: ReplicationSource 29 | metadata: 30 | name: prowlarr 31 | namespace: default 32 | spec: 33 | sourcePVC: prowlarr-config 34 | trigger: 35 | schedule: "50 5 * * *" 36 | restic: 37 | copyMethod: Snapshot 38 | pruneIntervalDays: 10 39 | repository: prowlarr-restic-secret 40 | cacheCapacity: 5Gi 41 | volumeSnapshotClassName: csi-ceph-blockpool 42 | storageClassName: ceph-block 43 | moverSecurityContext: 44 | runAsUser: 1001 45 | runAsGroup: 1001 46 | fsGroup: 1001 47 | retain: 48 | daily: 10 49 | within: 3d 50 | -------------------------------------------------------------------------------- /kubernetes/default/qbittorrent/volsync.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://crd.movishell.pl/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: qbittorrent-restic 7 | namespace: default 8 | spec: 9 | secretStoreRef: 10 | kind: ClusterSecretStore 11 | name: onepassword-connect 12 | target: 13 | name: qbittorrent-restic-secret 14 | creationPolicy: Owner 15 | template: 16 | engineVersion: v2 17 | data: 18 | RESTIC_REPOSITORY: '{{ .REPOSITORY_TEMPLATE }}/qbittorrent' 19 | RESTIC_PASSWORD: '{{ .RESTIC_PASSWORD }}' 20 | AWS_ACCESS_KEY_ID: '{{ .MINIO_ACCESS_KEY }}' 21 | AWS_SECRET_ACCESS_KEY: '{{ .MINIO_SECRET_KEY }}' 22 | dataFrom: 23 | - extract: 24 | key: minio 25 | --- 26 | # yaml-language-server: $schema=https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/volsync.backube/replicationsource_v1alpha1.json 27 | apiVersion: volsync.backube/v1alpha1 28 | kind: ReplicationSource 29 | metadata: 30 | name: qbittorrent 31 | namespace: default 32 | spec: 33 | sourcePVC: qbittorrent-config 34 | trigger: 35 | schedule: "0 6 * * *" 36 | restic: 37 | copyMethod: Snapshot 38 | pruneIntervalDays: 10 39 | repository: qbittorrent-restic-secret 40 | cacheCapacity: 2Gi 41 | volumeSnapshotClassName: csi-ceph-blockpool 42 | storageClassName: ceph-block 43 | moverSecurityContext: 44 | runAsUser: 1001 45 | runAsGroup: 1001 46 | fsGroup: 1001 47 | retain: 48 | daily: 10 49 | within: 3d 50 | 51 | -------------------------------------------------------------------------------- /kubernetes/default/radarr/externalsecret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: radarr 7 | namespace: default 8 | spec: 9 | refreshInterval: 5m 10 | secretStoreRef: 11 | kind: ClusterSecretStore 12 | name: onepassword-connect 13 | target: 14 | name: radarr-secret 15 | creationPolicy: Owner 16 | data: 17 | - secretKey: api_key 18 | remoteRef: 19 | key: radarr 20 | property: api_key 21 | -------------------------------------------------------------------------------- /kubernetes/default/radarr/volsync.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://crd.movishell.pl/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: radarr-restic 7 | namespace: default 8 | spec: 9 | secretStoreRef: 10 | kind: ClusterSecretStore 11 | name: onepassword-connect 12 | target: 13 | name: radarr-restic-secret 14 | creationPolicy: Owner 15 | template: 16 | engineVersion: v2 17 | data: 18 | RESTIC_REPOSITORY: '{{ .REPOSITORY_TEMPLATE }}/radarr' 19 | RESTIC_PASSWORD: '{{ .RESTIC_PASSWORD }}' 20 | AWS_ACCESS_KEY_ID: '{{ .MINIO_ACCESS_KEY }}' 21 | AWS_SECRET_ACCESS_KEY: '{{ .MINIO_SECRET_KEY }}' 22 | dataFrom: 23 | - extract: 24 | key: minio 25 | --- 26 | # yaml-language-server: $schema=https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/volsync.backube/replicationsource_v1alpha1.json 27 | apiVersion: volsync.backube/v1alpha1 28 | kind: ReplicationSource 29 | metadata: 30 | name: radarr 31 | namespace: default 32 | spec: 33 | sourcePVC: radarr-config 34 | trigger: 35 | schedule: "10 6 * * *" 36 | restic: 37 | copyMethod: Snapshot 38 | pruneIntervalDays: 10 39 | repository: radarr-restic-secret 40 | cacheCapacity: 3Gi 41 | volumeSnapshotClassName: csi-ceph-blockpool 42 | storageClassName: ceph-block 43 | moverSecurityContext: 44 | runAsUser: 1001 45 | runAsGroup: 1001 46 | fsGroup: 1001 47 | retain: 48 | daily: 10 49 | within: 3d 50 | -------------------------------------------------------------------------------- /kubernetes/default/readarr/volsync.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://crd.movishell.pl/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: readarr-restic 7 | namespace: default 8 | spec: 9 | secretStoreRef: 10 | kind: ClusterSecretStore 11 | name: onepassword-connect 12 | target: 13 | name: readarr-restic-secret 14 | creationPolicy: Owner 15 | template: 16 | engineVersion: v2 17 | data: 18 | RESTIC_REPOSITORY: '{{ .REPOSITORY_TEMPLATE }}/readarr' 19 | RESTIC_PASSWORD: '{{ .RESTIC_PASSWORD }}' 20 | AWS_ACCESS_KEY_ID: '{{ .MINIO_ACCESS_KEY }}' 21 | AWS_SECRET_ACCESS_KEY: '{{ .MINIO_SECRET_KEY }}' 22 | dataFrom: 23 | - extract: 24 | key: minio 25 | --- 26 | # yaml-language-server: $schema=https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/volsync.backube/replicationsource_v1alpha1.json 27 | apiVersion: volsync.backube/v1alpha1 28 | kind: ReplicationSource 29 | metadata: 30 | name: readarr 31 | namespace: default 32 | spec: 33 | sourcePVC: readarr-config 34 | trigger: 35 | schedule: "20 6 * * *" 36 | restic: 37 | copyMethod: Snapshot 38 | pruneIntervalDays: 10 39 | repository: readarr-restic-secret 40 | cacheCapacity: 5Gi 41 | volumeSnapshotClassName: csi-ceph-blockpool 42 | storageClassName: ceph-block 43 | moverSecurityContext: 44 | runAsUser: 1001 45 | runAsGroup: 1001 46 | fsGroup: 1001 47 | retain: 48 | daily: 10 49 | within: 3d 50 | -------------------------------------------------------------------------------- /kubernetes/default/recyclarr/externalsecret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://crd.movishell.pl/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: recyclarr 7 | namespace: default 8 | spec: 9 | secretStoreRef: 10 | kind: ClusterSecretStore 11 | name: onepassword-connect 12 | target: 13 | name: recyclarr-secret 14 | creationPolicy: Owner 15 | data: 16 | - secretKey: RADARR_API_KEY 17 | remoteRef: 18 | key: radarr 19 | property: api_key 20 | - secretKey: SONARR_API_KEY 21 | remoteRef: 22 | key: sonarr 23 | property: api_key 24 | -------------------------------------------------------------------------------- /kubernetes/default/recyclarr/recyclarr.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/helmrelease-helm-v2.json 3 | apiVersion: helm.toolkit.fluxcd.io/v2 4 | kind: HelmRelease 5 | metadata: 6 | name: recyclarr 7 | namespace: default 8 | spec: 9 | interval: 1h 10 | chart: 11 | spec: 12 | chart: app-template 13 | version: 4.0.1 14 | sourceRef: 15 | kind: HelmRepository 16 | name: bjw-s 17 | namespace: flux-system 18 | values: 19 | controllers: 20 | recyclarr: 21 | type: cronjob 22 | 23 | cronjob: 24 | schedule: "@daily" 25 | backoffLimit: 0 26 | concurrencyPolicy: Forbid 27 | failedJobsHistory: 1 28 | successfulJobsHistory: 0 29 | 30 | pod: 31 | restartPolicy: Never 32 | 33 | containers: 34 | app: 35 | image: 36 | repository: ghcr.io/recyclarr/recyclarr 37 | tag: 7.4.1@sha256:759540877f95453eca8a26c1a93593e783a7a824c324fbd57523deffb67f48e1 38 | args: 39 | - sync 40 | env: 41 | TZ: America/New_York 42 | COMPlus_EnableDiagnostics: "0" 43 | envFrom: 44 | - secretRef: 45 | name: recyclarr-secret 46 | resources: 47 | requests: 48 | cpu: 5m 49 | memory: 36M 50 | limits: 51 | memory: 128M 52 | securityContext: 53 | allowPrivilegeEscalation: false 54 | readOnlyRootFilesystem: true 55 | capabilities: { drop: ["ALL"] } 56 | 57 | defaultPodOptions: 58 | securityContext: 59 | runAsNonRoot: true 60 | runAsUser: 1001 61 | runAsGroup: 1001 62 | fsGroup: 1001 63 | fsGroupChangePolicy: OnRootMismatch 64 | 65 | persistence: 66 | config: 67 | suffix: config 68 | storageClass: "ceph-block" 69 | accessMode: ReadWriteOnce 70 | size: 5Gi 71 | config-file: 72 | type: configMap 73 | name: recyclarr-configmap 74 | globalMounts: 75 | - path: /config/recyclarr.yml 76 | subPath: recyclarr.yml 77 | readOnly: true 78 | tmpfs: 79 | type: emptyDir 80 | advancedMounts: 81 | recyclarr: 82 | app: 83 | - path: /config/logs 84 | subPath: logs 85 | - path: /config/repositories 86 | subPath: repositories 87 | - path: /tmp 88 | subPath: tmp 89 | -------------------------------------------------------------------------------- /kubernetes/default/recyclarr/volsync.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://crd.movishell.pl/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: recyclarr-restic 7 | namespace: default 8 | spec: 9 | secretStoreRef: 10 | kind: ClusterSecretStore 11 | name: onepassword-connect 12 | target: 13 | name: recyclarr-restic-secret 14 | creationPolicy: Owner 15 | template: 16 | engineVersion: v2 17 | data: 18 | RESTIC_REPOSITORY: '{{ .REPOSITORY_TEMPLATE }}/recyclarr' 19 | RESTIC_PASSWORD: '{{ .RESTIC_PASSWORD }}' 20 | AWS_ACCESS_KEY_ID: '{{ .MINIO_ACCESS_KEY }}' 21 | AWS_SECRET_ACCESS_KEY: '{{ .MINIO_SECRET_KEY }}' 22 | dataFrom: 23 | - extract: 24 | key: minio 25 | --- 26 | # yaml-language-server: $schema=https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/volsync.backube/replicationsource_v1alpha1.json 27 | apiVersion: volsync.backube/v1alpha1 28 | kind: ReplicationSource 29 | metadata: 30 | name: recyclarr 31 | namespace: default 32 | spec: 33 | sourcePVC: recyclarr-config 34 | trigger: 35 | schedule: "30 6 * * *" 36 | restic: 37 | copyMethod: Snapshot 38 | pruneIntervalDays: 10 39 | repository: recyclarr-restic-secret 40 | cacheCapacity: 5Gi 41 | volumeSnapshotClassName: csi-ceph-blockpool 42 | storageClassName: ceph-block 43 | moverSecurityContext: 44 | runAsUser: 1001 45 | runAsGroup: 1001 46 | fsGroup: 1001 47 | retain: 48 | daily: 10 49 | within: 3d 50 | -------------------------------------------------------------------------------- /kubernetes/default/sabnzbd/externalsecret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: sabnzbd 7 | namespace: default 8 | spec: 9 | secretStoreRef: 10 | kind: ClusterSecretStore 11 | name: onepassword-connect 12 | target: 13 | name: sabnzbd-secret 14 | creationPolicy: Owner 15 | dataFrom: 16 | - extract: 17 | # SABNZBD__API_KEY, SABNZBD__NZB_KEY 18 | key: sabnzbd 19 | -------------------------------------------------------------------------------- /kubernetes/default/sabnzbd/volsync.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: sabnzbd-restic 7 | namespace: default 8 | spec: 9 | secretStoreRef: 10 | kind: ClusterSecretStore 11 | name: onepassword-connect 12 | target: 13 | name: sabnzbd-restic-secret 14 | creationPolicy: Owner 15 | template: 16 | engineVersion: v2 17 | data: 18 | RESTIC_REPOSITORY: '{{ .REPOSITORY_TEMPLATE }}/sabnzbd' 19 | RESTIC_PASSWORD: '{{ .RESTIC_PASSWORD }}' 20 | AWS_ACCESS_KEY_ID: '{{ .MINIO_ACCESS_KEY }}' 21 | AWS_SECRET_ACCESS_KEY: '{{ .MINIO_SECRET_KEY }}' 22 | dataFrom: 23 | - extract: 24 | key: minio 25 | --- 26 | # yaml-language-server: $schema=https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/volsync.backube/replicationsource_v1alpha1.json 27 | apiVersion: volsync.backube/v1alpha1 28 | kind: ReplicationSource 29 | metadata: 30 | name: sabnzbd 31 | namespace: default 32 | spec: 33 | sourcePVC: sabnzbd-config 34 | trigger: 35 | schedule: "40 6 * * *" 36 | restic: 37 | copyMethod: Snapshot 38 | pruneIntervalDays: 10 39 | repository: sabnzbd-restic-secret 40 | cacheCapacity: 2Gi 41 | volumeSnapshotClassName: csi-ceph-blockpool 42 | storageClassName: ceph-block 43 | moverSecurityContext: 44 | runAsUser: 1001 45 | runAsGroup: 1001 46 | fsGroup: 1001 47 | retain: 48 | daily: 10 49 | within: 3d 50 | -------------------------------------------------------------------------------- /kubernetes/default/ser2sock/ser2sock.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/helmrelease-helm-v2.json 3 | apiVersion: helm.toolkit.fluxcd.io/v2 4 | kind: HelmRelease 5 | metadata: 6 | name: ser2sock 7 | namespace: default 8 | spec: 9 | interval: 1h 10 | chart: 11 | spec: 12 | chart: app-template 13 | version: 4.0.1 14 | sourceRef: 15 | kind: HelmRepository 16 | name: bjw-s 17 | namespace: flux-system 18 | install: 19 | remediation: 20 | retries: -1 21 | upgrade: 22 | cleanupOnFail: true 23 | remediation: 24 | retries: 3 25 | values: 26 | defaultPodOptions: 27 | affinity: 28 | nodeAffinity: 29 | requiredDuringSchedulingIgnoredDuringExecution: 30 | nodeSelectorTerms: 31 | - matchExpressions: 32 | - key: nutech.feature.node.kubernetes.io/alarmdecoder 33 | operator: In 34 | values: 35 | - "true" 36 | controllers: 37 | main: 38 | containers: 39 | main: 40 | image: 41 | repository: tenstartups/ser2sock 42 | tag: latest 43 | pullPolicy: Always 44 | env: 45 | TZ: "America/New York" 46 | LISTENER_PORT: 10000 47 | BAUD_RATE: 115200 48 | SERIAL_DEVICE: "/dev/ttyUSB0" 49 | securityContext: 50 | privileged: true 51 | resources: 52 | requests: 53 | memory: 50Mi 54 | cpu: 15m 55 | limits: 56 | memory: 250Mi 57 | service: 58 | main: 59 | controller: main 60 | ports: 61 | server: 62 | port: 10000 63 | primary: true 64 | protocol: TCP 65 | persistence: 66 | usb: 67 | enabled: true 68 | type: hostPath 69 | hostPath: /dev/serial/by-id/usb-FTDI_FT230X_Basic_UART_DO00DPTS-if00-port0 70 | # hostPathType: Directory 71 | hostPathType: CharDevice 72 | globalMounts: 73 | - path: /dev/ttyUSB0 74 | 75 | # MountVolume.SetUp failed for volume "usb" : hostPath type check failed: /dev/serial/by-id/usb-FTDI_FT230X_Basic_UART_DO00DPTS-if00-port0 is not a directory -------------------------------------------------------------------------------- /kubernetes/default/sonarr/externalsecret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: sonarr 7 | namespace: default 8 | spec: 9 | refreshInterval: 5m 10 | secretStoreRef: 11 | kind: ClusterSecretStore 12 | name: onepassword-connect 13 | target: 14 | name: sonarr-secret 15 | creationPolicy: Owner 16 | data: 17 | - secretKey: api_key 18 | remoteRef: 19 | key: sonarr 20 | property: api_key 21 | -------------------------------------------------------------------------------- /kubernetes/default/sonarr/volsync.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://crd.movishell.pl/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: sonarr-restic 7 | namespace: default 8 | spec: 9 | secretStoreRef: 10 | kind: ClusterSecretStore 11 | name: onepassword-connect 12 | target: 13 | name: sonarr-restic-secret 14 | creationPolicy: Owner 15 | template: 16 | engineVersion: v2 17 | data: 18 | RESTIC_REPOSITORY: '{{ .REPOSITORY_TEMPLATE }}/sonarr' 19 | RESTIC_PASSWORD: '{{ .RESTIC_PASSWORD }}' 20 | AWS_ACCESS_KEY_ID: '{{ .MINIO_ACCESS_KEY }}' 21 | AWS_SECRET_ACCESS_KEY: '{{ .MINIO_SECRET_KEY }}' 22 | dataFrom: 23 | - extract: 24 | key: minio 25 | --- 26 | # yaml-language-server: $schema=https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/volsync.backube/replicationsource_v1alpha1.json 27 | apiVersion: volsync.backube/v1alpha1 28 | kind: ReplicationSource 29 | metadata: 30 | name: sonarr 31 | namespace: default 32 | spec: 33 | sourcePVC: sonarr-config 34 | trigger: 35 | schedule: "10 6 * * *" 36 | restic: 37 | copyMethod: Snapshot 38 | pruneIntervalDays: 10 39 | repository: sonarr-restic-secret 40 | cacheCapacity: 3Gi 41 | volumeSnapshotClassName: csi-ceph-blockpool 42 | storageClassName: ceph-block 43 | moverSecurityContext: 44 | runAsUser: 1001 45 | runAsGroup: 1001 46 | fsGroup: 1001 47 | retain: 48 | daily: 10 49 | within: 3d 50 | -------------------------------------------------------------------------------- /kubernetes/default/tautulli/tautulli.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/helmrelease-helm-v2.json 3 | apiVersion: helm.toolkit.fluxcd.io/v2 4 | kind: HelmRelease 5 | metadata: 6 | name: tautulli 7 | namespace: default 8 | spec: 9 | interval: 1h 10 | chart: 11 | spec: 12 | chart: app-template 13 | version: 4.0.1 14 | sourceRef: 15 | kind: HelmRepository 16 | name: bjw-s 17 | namespace: flux-system 18 | install: 19 | remediation: 20 | retries: -1 21 | upgrade: 22 | cleanupOnFail: true 23 | remediation: 24 | retries: 3 25 | values: 26 | controllers: 27 | tautulli: 28 | containers: 29 | app: 30 | image: 31 | repository: ghcr.io/home-operations/tautulli 32 | tag: 2.15.2@sha256:4e7d75c9fe8f96ae766269fb451fc5ad215451b30a463c11142c492512c021cd 33 | env: 34 | TZ: America/New_York 35 | TAUTULLI__PORT: &port 8181 36 | probes: 37 | liveness: &probes 38 | enabled: true 39 | custom: true 40 | spec: 41 | httpGet: 42 | path: /status 43 | port: *port 44 | initialDelaySeconds: 0 45 | periodSeconds: 10 46 | timeoutSeconds: 1 47 | failureThreshold: 3 48 | readiness: *probes 49 | securityContext: 50 | allowPrivilegeEscalation: false 51 | readOnlyRootFilesystem: true 52 | capabilities: { drop: ["ALL"] } 53 | resources: 54 | requests: 55 | cpu: 5m 56 | memory: 128Mi 57 | limits: 58 | memory: 512Mi 59 | defaultPodOptions: 60 | securityContext: 61 | runAsNonRoot: true 62 | runAsUser: 1001 63 | runAsGroup: 1001 64 | fsGroup: 1001 65 | fsGroupChangePolicy: OnRootMismatch 66 | service: 67 | app: 68 | controller: tautulli 69 | ports: 70 | http: 71 | port: *port 72 | ingress: 73 | main: 74 | className: "nginx-tailscale" 75 | hosts: 76 | - host: &host "tautulli.eviljungle.com" 77 | paths: 78 | - path: / 79 | pathType: Prefix 80 | service: 81 | identifier: app 82 | port: http 83 | tls: 84 | - hosts: 85 | - *host 86 | persistence: 87 | config: 88 | suffix: config 89 | storageClass: "ceph-block" 90 | accessMode: ReadWriteOnce 91 | size: "1Gi" 92 | tmpfs: 93 | type: emptyDir 94 | advancedMounts: 95 | tautulli: 96 | app: 97 | - path: /config/logs 98 | subPath: logs 99 | - path: /tmp 100 | subPath: tmp 101 | -------------------------------------------------------------------------------- /kubernetes/default/tautulli/volsync.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://crd.movishell.pl/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: tautulli-restic 7 | namespace: default 8 | spec: 9 | secretStoreRef: 10 | kind: ClusterSecretStore 11 | name: onepassword-connect 12 | target: 13 | name: tautulli-restic-secret 14 | creationPolicy: Owner 15 | template: 16 | engineVersion: v2 17 | data: 18 | RESTIC_REPOSITORY: '{{ .REPOSITORY_TEMPLATE }}/tautulli' 19 | RESTIC_PASSWORD: '{{ .RESTIC_PASSWORD }}' 20 | AWS_ACCESS_KEY_ID: '{{ .MINIO_ACCESS_KEY }}' 21 | AWS_SECRET_ACCESS_KEY: '{{ .MINIO_SECRET_KEY }}' 22 | dataFrom: 23 | - extract: 24 | key: minio 25 | --- 26 | # yaml-language-server: $schema=https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/volsync.backube/replicationsource_v1alpha1.json 27 | apiVersion: volsync.backube/v1alpha1 28 | kind: ReplicationSource 29 | metadata: 30 | name: tautulli 31 | namespace: default 32 | spec: 33 | sourcePVC: tautulli-config 34 | trigger: 35 | schedule: "0 7 * * *" 36 | restic: 37 | copyMethod: Snapshot 38 | pruneIntervalDays: 10 39 | repository: tautulli-restic-secret 40 | cacheCapacity: 2Gi 41 | volumeSnapshotClassName: csi-ceph-blockpool 42 | storageClassName: ceph-block 43 | moverSecurityContext: 44 | runAsUser: 1001 45 | runAsGroup: 1001 46 | fsGroup: 1001 47 | retain: 48 | daily: 10 49 | within: 3d 50 | -------------------------------------------------------------------------------- /kubernetes/default/teslamate/externalsecret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://crd.movishell.pl/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: teslamate 7 | namespace: default 8 | spec: 9 | secretStoreRef: 10 | kind: ClusterSecretStore 11 | name: onepassword-connect 12 | target: 13 | name: teslamate-secret 14 | creationPolicy: Owner 15 | template: 16 | engineVersion: v2 17 | data: 18 | # Teslamate 19 | MQTT_PASSWORD: "{{ .MQTT_PASSWORD }}" 20 | ENCRYPTION_KEY: "{{ .TESLAMATE_ENCRYPTION_KEY }}" 21 | DATABASE_NAME: teslamate 22 | DATABASE_HOST: postgres-v17-rw.default.svc.cluster.local 23 | DATABASE_PASS: "{{ .TESLAMATE_POSTGRES_PASS }}" 24 | DATABASE_USER: "{{ .TESLAMATE_POSTGRES_USER }}" 25 | # Postgres Init 26 | INIT_POSTGRES_DBNAME: teslamate 27 | INIT_POSTGRES_HOST: postgres-v17-rw.default.svc.cluster.local 28 | INIT_POSTGRES_SUPER_PASS: "{{ .POSTGRES_SUPER_PASS }}" 29 | INIT_POSTGRES_PASS: "{{ .TESLAMATE_POSTGRES_PASS }}" 30 | INIT_POSTGRES_USER: "{{ .TESLAMATE_POSTGRES_USER }}" 31 | dataFrom: 32 | - extract: 33 | key: teslamate 34 | - extract: 35 | key: cloudnative-pg 36 | -------------------------------------------------------------------------------- /kubernetes/default/teslamate/teslamate.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/helmrelease-helm-v2.json 3 | apiVersion: helm.toolkit.fluxcd.io/v2 4 | kind: HelmRelease 5 | metadata: 6 | name: teslamate 7 | namespace: default 8 | spec: 9 | interval: 1h 10 | chart: 11 | spec: 12 | chart: app-template 13 | version: 4.0.1 14 | sourceRef: 15 | kind: HelmRepository 16 | name: bjw-s 17 | namespace: flux-system 18 | interval: 15m 19 | install: 20 | remediation: 21 | retries: -1 22 | upgrade: 23 | cleanupOnFail: true 24 | remediation: 25 | retries: 3 26 | values: 27 | controllers: 28 | teslamate: 29 | initContainers: 30 | init-db: 31 | image: 32 | repository: ghcr.io/home-operations/postgres-init 33 | tag: 17@sha256:e0c87ce7df39d06b93f27cf2cc6a056611f13faaa88cc07ab4dc8bf7a85d0b11 34 | pullPolicy: IfNotPresent 35 | envFrom: 36 | - secretRef: 37 | name: teslamate-secret 38 | 39 | containers: 40 | main: 41 | image: 42 | repository: teslamate/teslamate 43 | tag: 2.0.0 44 | env: 45 | TZ: "America/New_York" 46 | DISABLE_MQTT: "false" 47 | MQTT_USERNAME: "mqtt" 48 | MQTT_HOST: "emqx-listeners" 49 | envFrom: &envFrom 50 | - secretRef: 51 | name: teslamate-secret 52 | resources: 53 | requests: 54 | memory: 250Mi 55 | cpu: 50m 56 | limits: 57 | memory: 500Mi 58 | 59 | service: 60 | main: 61 | controller: teslamate 62 | ports: 63 | http: 64 | port: 4000 65 | 66 | ingress: 67 | main: 68 | className: "nginx-tailscale" 69 | hosts: 70 | - host: &host "teslamate.eviljungle.com" 71 | paths: 72 | - path: / 73 | pathType: Prefix 74 | service: 75 | identifier: main 76 | port: http 77 | tls: 78 | - hosts: 79 | - *host 80 | -------------------------------------------------------------------------------- /kubernetes/default/unifi/unifi.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/helmrelease-helm-v2.json 3 | apiVersion: helm.toolkit.fluxcd.io/v2 4 | kind: HelmRelease 5 | metadata: 6 | name: unifi 7 | namespace: default 8 | spec: 9 | interval: 1h 10 | chart: 11 | spec: 12 | chart: app-template 13 | version: 4.0.1 14 | sourceRef: 15 | kind: HelmRepository 16 | name: bjw-s 17 | namespace: flux-system 18 | install: 19 | remediation: 20 | retries: -1 21 | upgrade: 22 | cleanupOnFail: true 23 | remediation: 24 | retries: 3 25 | values: 26 | controllers: 27 | unifi: 28 | containers: 29 | app: 30 | image: 31 | repository: jacobalberty/unifi 32 | tag: v9.1.120@sha256:150af8f7bd96f597e7441f4598bd82435c2ee73b03b833179d30e6e2666be12b 33 | pullPolicy: IfNotPresent 34 | env: 35 | TZ: "America/New_York" 36 | RUNAS_UID0: "false" 37 | UNIFI_UID: "999" 38 | UNIFI_GID: "999" 39 | UNIFI_STDOUT: "true" 40 | JVM_INIT_HEAP_SIZE: 41 | JVM_MAX_HEAP_SIZE: 1024M 42 | resources: 43 | requests: 44 | memory: 1Gi 45 | cpu: 50m 46 | limits: 47 | memory: 1600Mi 48 | service: 49 | app: 50 | controller: unifi 51 | type: LoadBalancer 52 | externalTrafficPolicy: Local 53 | loadBalancerIP: 10.0.6.57 54 | ports: 55 | http: 56 | port: 8443 57 | protocol: HTTPS 58 | controller: 59 | enabled: true 60 | port: 8080 61 | protocol: TCP 62 | portal-http: 63 | enabled: false 64 | port: 8880 65 | protocol: HTTP 66 | portal-https: 67 | enabled: false 68 | port: 8843 69 | protocol: HTTPS 70 | speedtest: 71 | enabled: true 72 | port: 6789 73 | protocol: TCP 74 | stun: 75 | enabled: true 76 | port: 3478 77 | protocol: UDP 78 | syslog: 79 | enabled: true 80 | port: 5514 81 | protocol: UDP 82 | discovery: 83 | enabled: true 84 | port: 10001 85 | protocol: UDP 86 | ingress: 87 | app: 88 | enabled: true 89 | className: nginx-tailscale 90 | annotations: 91 | nginx.ingress.kubernetes.io/backend-protocol: HTTPS 92 | hosts: 93 | - host: &host "unifi.eviljungle.com" 94 | paths: 95 | - path: / 96 | service: 97 | identifier: app 98 | port: http 99 | tls: 100 | - hosts: 101 | - *host 102 | persistence: 103 | data: 104 | suffix: data 105 | storageClass: "ceph-block" 106 | accessMode: ReadWriteOnce 107 | size: "20Gi" 108 | globalMounts: 109 | - path: /unifi 110 | -------------------------------------------------------------------------------- /kubernetes/default/unifi/volsync.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://crd.movishell.pl/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: unifi-restic 7 | namespace: default 8 | spec: 9 | secretStoreRef: 10 | kind: ClusterSecretStore 11 | name: onepassword-connect 12 | target: 13 | name: unifi-restic-secret 14 | creationPolicy: Owner 15 | template: 16 | engineVersion: v2 17 | data: 18 | RESTIC_REPOSITORY: '{{ .REPOSITORY_TEMPLATE }}/unifi' 19 | RESTIC_PASSWORD: '{{ .RESTIC_PASSWORD }}' 20 | AWS_ACCESS_KEY_ID: '{{ .MINIO_ACCESS_KEY }}' 21 | AWS_SECRET_ACCESS_KEY: '{{ .MINIO_SECRET_KEY }}' 22 | dataFrom: 23 | - extract: 24 | key: minio 25 | --- 26 | # yaml-language-server: $schema=https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/volsync.backube/replicationsource_v1alpha1.json 27 | apiVersion: volsync.backube/v1alpha1 28 | kind: ReplicationSource 29 | metadata: 30 | name: unifi 31 | namespace: default 32 | spec: 33 | sourcePVC: unifi-data 34 | trigger: 35 | schedule: "0 5 * * *" 36 | restic: 37 | copyMethod: Snapshot 38 | pruneIntervalDays: 10 39 | repository: unifi-restic-secret 40 | cacheCapacity: 20Gi 41 | volumeSnapshotClassName: csi-ceph-blockpool 42 | storageClassName: ceph-block 43 | moverSecurityContext: 44 | runAsUser: 999 45 | runAsGroup: 999 46 | fsGroup: 999 47 | retain: 48 | daily: 10 49 | within: 3d 50 | -------------------------------------------------------------------------------- /kubernetes/default/zwave2mqtt/volsync.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://crd.movishell.pl/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: zwave2mqtt-restic 7 | namespace: default 8 | spec: 9 | secretStoreRef: 10 | kind: ClusterSecretStore 11 | name: onepassword-connect 12 | target: 13 | name: zwave2mqtt-restic-secret 14 | creationPolicy: Owner 15 | template: 16 | engineVersion: v2 17 | data: 18 | RESTIC_REPOSITORY: '{{ .REPOSITORY_TEMPLATE }}/zwave2mqtt' 19 | RESTIC_PASSWORD: '{{ .RESTIC_PASSWORD }}' 20 | AWS_ACCESS_KEY_ID: '{{ .MINIO_ACCESS_KEY }}' 21 | AWS_SECRET_ACCESS_KEY: '{{ .MINIO_SECRET_KEY }}' 22 | dataFrom: 23 | - extract: 24 | key: minio 25 | --- 26 | # yaml-language-server: $schema=https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/volsync.backube/replicationsource_v1alpha1.json 27 | apiVersion: volsync.backube/v1alpha1 28 | kind: ReplicationSource 29 | metadata: 30 | name: zwave2mqtt 31 | namespace: default 32 | spec: 33 | sourcePVC: zwave2mqtt-config 34 | trigger: 35 | schedule: "10 7 * * *" 36 | restic: 37 | copyMethod: Snapshot 38 | pruneIntervalDays: 10 39 | repository: zwave2mqtt-restic-secret 40 | cacheCapacity: 2Gi 41 | volumeSnapshotClassName: csi-ceph-blockpool 42 | storageClassName: ceph-block 43 | retain: 44 | daily: 10 45 | within: 3d 46 | -------------------------------------------------------------------------------- /kubernetes/default/zwave2mqtt/zwave2mqtt.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/helmrelease-helm-v2.json 3 | apiVersion: helm.toolkit.fluxcd.io/v2 4 | kind: HelmRelease 5 | metadata: 6 | name: zwave2mqtt 7 | namespace: default 8 | spec: 9 | interval: 1h 10 | chart: 11 | spec: 12 | chart: app-template 13 | version: 4.0.1 14 | sourceRef: 15 | kind: HelmRepository 16 | name: bjw-s 17 | namespace: flux-system 18 | install: 19 | remediation: 20 | retries: -1 21 | upgrade: 22 | cleanupOnFail: true 23 | remediation: 24 | retries: 3 25 | values: 26 | controllers: 27 | zwave: 28 | containers: 29 | app: 30 | image: 31 | repository: ghcr.io/zwave-js/zwave-js-ui 32 | tag: 10.6.1@sha256:fe8166b41b7d808a2cb7b39d830db4cb5aaac0b70066552bc1fd4456fbdb3802 33 | env: 34 | TZ: America/New_York 35 | PORT: &port 8091 36 | probes: 37 | liveness: &probes 38 | enabled: true 39 | custom: true 40 | spec: 41 | httpGet: 42 | path: /health 43 | port: *port 44 | initialDelaySeconds: 0 45 | periodSeconds: 10 46 | timeoutSeconds: 1 47 | failureThreshold: 3 48 | readiness: *probes 49 | securityContext: 50 | privileged: true 51 | resources: 52 | requests: 53 | cpu: 10m 54 | memory: 200Mi 55 | limits: 56 | memory: 512Mi 57 | defaultPodOptions: 58 | affinity: 59 | nodeAffinity: 60 | requiredDuringSchedulingIgnoredDuringExecution: 61 | nodeSelectorTerms: 62 | - matchExpressions: 63 | - key: aeotec.feature.node.kubernetes.io/zwave 64 | operator: In 65 | values: 66 | - "true" 67 | service: 68 | app: 69 | controller: zwave 70 | ports: 71 | http: 72 | port: *port 73 | websocket: 74 | port: 3000 75 | ingress: 76 | main: 77 | className: "nginx-tailscale" 78 | hosts: 79 | - host: &host "z.eviljungle.com" 80 | paths: 81 | - path: / 82 | pathType: Prefix 83 | service: 84 | identifier: app 85 | port: http 86 | tls: 87 | - hosts: 88 | - *host 89 | persistence: 90 | config: 91 | suffix: config 92 | storageClass: "ceph-block" 93 | accessMode: ReadWriteOnce 94 | size: "1Gi" 95 | globalMounts: 96 | - path: /usr/src/app/store 97 | tmp: 98 | type: emptyDir 99 | usb: 100 | type: hostPath 101 | hostPath: /dev/serial/by-id/usb-0658_0200-if00 102 | hostPathType: CharDevice 103 | globalMounts: 104 | - path: /dev/ttyACM0 105 | -------------------------------------------------------------------------------- /kubernetes/flux-system/README.md: -------------------------------------------------------------------------------- 1 | # flux-system 2 | 3 | [Flux2](https://github.com/fluxcd/flux2) to automate cluster state using code residing in this repo 4 | 5 | ![](https://i.imgur.com/QcJ1Tx8.png) 6 | 7 | * [discord-notifications/](discord-notifications/) - configure discord for notifications and alerts 8 | * [flux-instance/](flux-instance/) - main entrypoint for flux 9 | * [flux-operator/](flux-operator/) - helm chart to manage flux 10 | 11 | There are additional components outside of this directory that are managed by flux. See the following directories for more details: 12 | 13 | * [../../setup/flux/cluster](../../setup/flux/cluster) - flux kustomization definition for this cluster & repo. 14 | * [../../setup/flux/repositories](../../setup/flux/repositories) - all of the `HelmRepository` definitions used by various HelmReleases in the cluster. It is necessary to ensure that the Helm repositories are available before the HelmReleases are applied. 15 | -------------------------------------------------------------------------------- /kubernetes/flux-system/discord-notifications/alerts.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/notification.toolkit.fluxcd.io/alert_v1beta3.json 3 | apiVersion: notification.toolkit.fluxcd.io/v1beta3 4 | kind: Alert 5 | metadata: 6 | name: home-cluster 7 | namespace: flux-system 8 | spec: 9 | providerRef: 10 | name: discord 11 | eventSeverity: info 12 | eventSources: 13 | - kind: GitRepository 14 | name: '*' 15 | - kind: Kustomization 16 | name: '*' 17 | exclusionList: 18 | - "error.*lookup github\\.com" 19 | - "error.*lookup raw\\.githubusercontent\\.com" 20 | - "dial.*tcp.*timeout" 21 | - "waiting.*socket" 22 | - "snapshot-controller configured" 23 | - "snapshot-validation-webhook configured" 24 | - "volsync configured" 25 | - "Health check passed in" 26 | - "Dependencies do not meet ready condition, retrying in" 27 | - "read: connection timed out" 28 | - "GitRepository/flux-system/flux-system configured" 29 | - "CustomResourceDefinition/clustersecretstores.external-secrets.io configured" 30 | - "CustomResourceDefinition/externalsecrets.external-secrets.io configured" 31 | - "CustomResourceDefinition/secretstores.external-secrets.io configured" 32 | suspend: false 33 | --- 34 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/notification.toolkit.fluxcd.io/alert_v1beta3.json 35 | apiVersion: notification.toolkit.fluxcd.io/v1beta3 36 | kind: Alert 37 | metadata: 38 | name: helmreleases 39 | namespace: flux-system 40 | spec: 41 | providerRef: 42 | name: discord 43 | eventSeverity: info 44 | eventSources: 45 | - kind: HelmRelease 46 | namespace: 'cert-manager' 47 | name: '*' 48 | - kind: HelmRelease 49 | namespace: 'default' 50 | name: '*' 51 | - kind: HelmRelease 52 | namespace: 'flux-system' 53 | name: '*' 54 | - kind: HelmRelease 55 | namespace: 'kube-system' 56 | name: '*' 57 | - kind: HelmRelease 58 | namespace: 'monitoring' 59 | name: '*' 60 | - kind: HelmRelease 61 | namespace: 'rook-ceph' 62 | name: '*' 63 | suspend: false 64 | -------------------------------------------------------------------------------- /kubernetes/flux-system/discord-notifications/discord-webhook-secret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: discord-webhook 7 | namespace: flux-system 8 | spec: 9 | secretStoreRef: 10 | kind: ClusterSecretStore 11 | name: onepassword-connect 12 | target: 13 | name: discord-webhook-secret 14 | creationPolicy: Owner 15 | dataFrom: 16 | - extract: 17 | key: discord-webhook 18 | -------------------------------------------------------------------------------- /kubernetes/flux-system/discord-notifications/provider.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/notification.toolkit.fluxcd.io/provider_v1beta3.json 3 | apiVersion: notification.toolkit.fluxcd.io/v1beta3 4 | kind: Provider 5 | metadata: 6 | name: discord 7 | namespace: flux-system 8 | spec: 9 | type: discord 10 | username: Flux 11 | channel: flux 12 | secretRef: 13 | name: discord-webhook-secret 14 | -------------------------------------------------------------------------------- /kubernetes/flux-system/flux-operator/flux-operator.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/helm.toolkit.fluxcd.io/helmrelease_v2.json 3 | apiVersion: helm.toolkit.fluxcd.io/v2 4 | kind: HelmRelease 5 | metadata: 6 | name: flux-operator 7 | namespace: flux-system 8 | spec: 9 | chart: 10 | spec: 11 | chart: flux-operator 12 | version: 0.22.0 13 | sourceRef: 14 | kind: HelmRepository 15 | name: controlplaneio-fluxcd 16 | namespace: flux-system 17 | interval: 30m 18 | interval: 1h 19 | install: 20 | remediation: 21 | retries: -1 22 | upgrade: 23 | cleanupOnFail: true 24 | remediation: 25 | retries: 3 26 | values: 27 | serviceMonitor: 28 | create: true 29 | -------------------------------------------------------------------------------- /kubernetes/flux-system/receiver.yaml/externalsecret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: github-webhook-token 7 | namespace: flux-system 8 | spec: 9 | secretStoreRef: 10 | kind: ClusterSecretStore 11 | name: onepassword-connect 12 | target: 13 | name: github-webhook-token-secret 14 | template: 15 | data: 16 | token: "{{ .FLUX_GITHUB_WEBHOOK_TOKEN }}" 17 | dataFrom: 18 | - extract: 19 | key: flux -------------------------------------------------------------------------------- /kubernetes/flux-system/receiver.yaml/ingress.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | name: webhook-receiver 5 | namespace: flux-system 6 | spec: 7 | ingressClassName: nginx 8 | rules: 9 | - host: &host flux-webhook.eviljungle.com 10 | http: 11 | paths: 12 | - pathType: Prefix 13 | path: / 14 | backend: 15 | service: 16 | name: webhook-receiver 17 | port: 18 | number: 80 19 | tls: 20 | - hosts: 21 | - *host -------------------------------------------------------------------------------- /kubernetes/flux-system/receiver.yaml/prometheusrule.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/monitoring.coreos.com/prometheusrule_v1.json 3 | apiVersion: monitoring.coreos.com/v1 4 | kind: PrometheusRule 5 | metadata: 6 | name: flux-instance-rules 7 | namespace: flux-system 8 | spec: 9 | groups: 10 | - name: flux-instance.rules 11 | rules: 12 | - alert: FluxInstanceAbsent 13 | expr: | 14 | absent(flux_instance_info{exported_namespace="flux-system", name="flux"}) 15 | for: 5m 16 | annotations: 17 | summary: >- 18 | Flux instance metric is missing 19 | labels: 20 | severity: critical 21 | 22 | - alert: FluxInstanceNotReady 23 | expr: | 24 | flux_instance_info{exported_namespace="flux-system", name="flux", ready!="True"} 25 | for: 5m 26 | annotations: 27 | summary: >- 28 | Flux instance {{ $labels.name }} is not ready 29 | labels: 30 | severity: critical -------------------------------------------------------------------------------- /kubernetes/flux-system/receiver.yaml/receiver.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/notification.toolkit.fluxcd.io/receiver_v1.json 3 | apiVersion: notification.toolkit.fluxcd.io/v1 4 | kind: Receiver 5 | metadata: 6 | name: github-webhook 7 | namespace: flux-system 8 | spec: 9 | type: github 10 | events: ["ping", "push"] 11 | secretRef: 12 | name: github-webhook-token-secret 13 | resources: 14 | - apiVersion: source.toolkit.fluxcd.io/v1 15 | kind: GitRepository 16 | name: flux-system 17 | -------------------------------------------------------------------------------- /kubernetes/kube-system/cilium/bgp.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/cilium.io/ciliumloadbalancerippool_v2alpha1.json 3 | apiVersion: cilium.io/v2alpha1 4 | kind: CiliumLoadBalancerIPPool 5 | metadata: 6 | name: pool 7 | spec: 8 | allowFirstLastIPs: "No" 9 | blocks: 10 | - start: 10.0.6.2 11 | stop: 10.0.6.250 12 | --- 13 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/cilium.io/ciliumbgppeeringpolicy_v2alpha1.json 14 | apiVersion: cilium.io/v2alpha1 15 | kind: CiliumBGPPeeringPolicy 16 | metadata: 17 | name: bgp-policy 18 | spec: 19 | virtualRouters: 20 | - localASN: 64513 21 | exportPodCIDR: false 22 | serviceSelector: 23 | matchExpressions: 24 | - key: thisFakeSelector 25 | operator: NotIn 26 | values: 27 | - will-match-and-announce-all-services 28 | neighbors: 29 | - peerAddress: 10.0.7.1/32 30 | peerASN: 64512 31 | eBGPMultihopTTL: 10 32 | gracefulRestart: 33 | enabled: true 34 | -------------------------------------------------------------------------------- /kubernetes/kube-system/cilium/gateway/gateway-external.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/gateway.networking.k8s.io/gateway_v1.json 3 | apiVersion: gateway.networking.k8s.io/v1 4 | kind: Gateway 5 | metadata: 6 | name: external 7 | namespace: kube-system 8 | spec: 9 | gatewayClassName: cilium 10 | addresses: 11 | - type: IPAddress 12 | value: 10.0.5.10 13 | listeners: 14 | - name: http 15 | protocol: HTTP 16 | port: 80 17 | hostname: "*.eviljungle.com" 18 | allowedRoutes: 19 | namespaces: 20 | from: All 21 | - name: https 22 | protocol: HTTPS 23 | port: 443 24 | hostname: "*.eviljungle.com" 25 | allowedRoutes: 26 | namespaces: 27 | from: All 28 | tls: 29 | certificateRefs: 30 | - kind: Secret 31 | name: acme-crt 32 | namespace: cert-manager 33 | -------------------------------------------------------------------------------- /kubernetes/kube-system/cilium/gateway/gateway-tailscale.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/gateway.networking.k8s.io/gateway_v1.json 3 | apiVersion: gateway.networking.k8s.io/v1 4 | kind: Gateway 5 | metadata: 6 | name: tailscale 7 | namespace: kube-system 8 | spec: 9 | gatewayClassName: cilium 10 | addresses: 11 | - type: IPAddress 12 | value: 100.127.102.113 13 | infrastructure: 14 | annotations: 15 | tailscale.com/hostname: "gateway-tailscale" 16 | tailscale.com/expose: "true" 17 | listeners: 18 | - name: http 19 | protocol: HTTP 20 | port: 80 21 | hostname: "*.eviljungle.com" 22 | allowedRoutes: 23 | namespaces: 24 | from: All 25 | - name: https 26 | protocol: HTTPS 27 | port: 443 28 | hostname: "*.eviljungle.com" 29 | allowedRoutes: 30 | namespaces: 31 | from: All 32 | tls: 33 | certificateRefs: 34 | - kind: Secret 35 | name: acme-crt 36 | namespace: cert-manager 37 | -------------------------------------------------------------------------------- /kubernetes/kube-system/cilium/gateway/redirect.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/gateway.networking.k8s.io/httproute_v1.json 3 | apiVersion: gateway.networking.k8s.io/v1 4 | kind: HTTPRoute 5 | metadata: 6 | name: httpsredirect 7 | namespace: kube-system 8 | annotations: 9 | external-dns.alpha.kubernetes.io/controller: none 10 | spec: 11 | parentRefs: 12 | - name: external 13 | namespace: kube-system 14 | sectionName: http 15 | # - name: tailscale 16 | # namespace: kube-system 17 | # sectionName: http 18 | rules: 19 | - filters: 20 | - requestRedirect: 21 | scheme: https 22 | statusCode: 301 23 | type: RequestRedirect -------------------------------------------------------------------------------- /kubernetes/kube-system/coredns/eviljungle.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/helmrelease-helm-v2.json 3 | apiVersion: helm.toolkit.fluxcd.io/v2 4 | kind: HelmRelease 5 | metadata: 6 | name: coredns-eviljungle 7 | namespace: kube-system 8 | spec: 9 | chart: 10 | spec: 11 | chart: coredns 12 | version: 1.42.2 13 | sourceRef: 14 | kind: HelmRepository 15 | name: coredns 16 | namespace: flux-system 17 | interval: 30m 18 | interval: 30m 19 | values: 20 | fullnameOverride: coredns-eviljungle 21 | image: 22 | repository: mirror.gcr.io/coredns/coredns 23 | replicaCount: 2 24 | serviceType: LoadBalancer 25 | prometheus: 26 | service: 27 | enabled: true 28 | monitor: 29 | enabled: true 30 | service: 31 | externalTrafficPolicy: Cluster 32 | loadBalancerIP: 10.0.6.99 33 | affinity: 34 | podAntiAffinity: 35 | requiredDuringSchedulingIgnoredDuringExecution: 36 | - labelSelector: 37 | matchExpressions: 38 | - key: app.kubernetes.io/name 39 | operator: In 40 | values: 41 | - coredns 42 | topologyKey: "kubernetes.io/hostname" 43 | rbac: 44 | create: true 45 | isClusterService: false 46 | servers: 47 | - zones: 48 | - zone: eviljungle.com. 49 | scheme: dns:// 50 | use_tcp: false 51 | port: 53 52 | plugins: 53 | - name: errors 54 | - name: health 55 | configBlock: |- 56 | lameduck 5s 57 | - name: ready 58 | - name: prometheus 59 | parameters: 0.0.0.0:9153 60 | - name: forward 61 | parameters: . /etc/resolv.conf 62 | - name: cache 63 | parameters: 30 64 | - name: loop 65 | - name: reload 66 | - name: loadbalance 67 | - name: file 68 | parameters: /etc/coredns/eviljungle.com 69 | zoneFiles: 70 | - filename: eviljungle.com 71 | domain: eviljungle.com 72 | contents: | 73 | eviljungle.com. IN SOA etta.ns.cloudflare.com. dns.cloudflare.com. 2020100600 10000 2400 604800 3600 74 | abs.eviljungle.com. IN A 10.0.6.150 75 | mc.eviljungle.com. IN A 10.0.6.106 76 | plex.eviljungle.com. IN A 10.0.6.150 77 | hass.eviljungle.com. IN A 10.0.6.150 78 | mcsv2-map.eviljungle.com. IN A 10.0.6.150 79 | request.eviljungle.com. IN A 10.0.6.150 80 | *.t.eviljungle.com. IN CNAME nginx-tailscale.drake-eel.ts.net 81 | *.eviljungle.com. IN A 100.65.132.11 82 | eviljungle.com. IN A 10.0.7.1 -------------------------------------------------------------------------------- /kubernetes/kube-system/csi-driver-nfs/csi-driver-nfs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/helm.toolkit.fluxcd.io/helmrelease_v2.json 3 | apiVersion: helm.toolkit.fluxcd.io/v2 4 | kind: HelmRelease 5 | metadata: 6 | name: csi-driver-nfs 7 | namespace: kube-system 8 | spec: 9 | interval: 1h 10 | chart: 11 | spec: 12 | chart: csi-driver-nfs 13 | version: 4.11.0 14 | sourceRef: 15 | kind: HelmRepository 16 | name: csi-driver-nfs 17 | namespace: flux-system 18 | interval: 30m 19 | install: 20 | remediation: 21 | retries: -1 22 | upgrade: 23 | cleanupOnFail: true 24 | remediation: 25 | retries: 3 26 | values: 27 | controller: 28 | replicas: 1 29 | storageClass: 30 | create: true 31 | name: nfs-k8s 32 | parameters: 33 | server: nas.home 34 | share: /mnt/tank/data/k8s-nfs 35 | mountOptions: 36 | - nfsvers=4.2 37 | - nconnect=16 38 | - hard 39 | - noatime 40 | reclaimPolicy: Delete 41 | volumeBindingMode: Immediate -------------------------------------------------------------------------------- /kubernetes/kube-system/descheduler/descheduler.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/helmrelease-helm-v2.json 3 | apiVersion: helm.toolkit.fluxcd.io/v2 4 | kind: HelmRelease 5 | metadata: 6 | name: descheduler 7 | namespace: kube-system 8 | spec: 9 | interval: 1h 10 | chart: 11 | spec: 12 | chart: descheduler 13 | version: 0.33.0 14 | sourceRef: 15 | kind: HelmRepository 16 | name: kubernetes-sigs-descheduler-charts 17 | namespace: flux-system 18 | install: 19 | remediation: 20 | retries: -1 21 | upgrade: 22 | cleanupOnFail: true 23 | remediation: 24 | retries: 3 25 | values: 26 | replicas: 2 27 | kind: Deployment 28 | deschedulerPolicyAPIVersion: descheduler/v1alpha2 29 | deschedulerPolicy: 30 | profiles: 31 | - name: Default 32 | pluginConfig: 33 | - name: DefaultEvictor 34 | args: 35 | evictFailedBarePods: true 36 | evictLocalStoragePods: true 37 | evictSystemCriticalPods: true 38 | nodeFit: true 39 | - name: RemovePodsViolatingInterPodAntiAffinity 40 | - name: RemovePodsViolatingNodeAffinity 41 | args: 42 | nodeAffinityType: 43 | - requiredDuringSchedulingIgnoredDuringExecution 44 | - name: RemovePodsViolatingNodeTaints 45 | - name: RemovePodsViolatingTopologySpreadConstraint 46 | args: 47 | constraints: 48 | - DoNotSchedule 49 | - ScheduleAnyway 50 | plugins: 51 | balance: 52 | enabled: 53 | - RemovePodsViolatingTopologySpreadConstraint 54 | deschedule: 55 | enabled: 56 | - RemovePodsViolatingInterPodAntiAffinity 57 | - RemovePodsViolatingNodeAffinity 58 | - RemovePodsViolatingNodeTaints 59 | service: 60 | enabled: true 61 | serviceMonitor: 62 | enabled: true 63 | leaderElection: 64 | enabled: true -------------------------------------------------------------------------------- /kubernetes/kube-system/e1000e-fix/e1000e-fix.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/helmrelease-helm-v2.json 3 | apiVersion: helm.toolkit.fluxcd.io/v2 4 | kind: HelmRelease 5 | metadata: 6 | # https://github.com/siderolabs/talos/issues/10200 7 | name: e1000e-fix 8 | namespace: kube-system 9 | spec: 10 | interval: 1h 11 | chart: 12 | spec: 13 | chart: app-template 14 | version: 4.0.1 15 | sourceRef: 16 | name: bjw-s 17 | kind: HelmRepository 18 | namespace: flux-system 19 | values: 20 | controllers: 21 | e1000e-fix: 22 | type: daemonset 23 | containers: 24 | main: 25 | image: 26 | repository: ghcr.io/nicolaka/netshoot 27 | tag: v0.13@sha256:a20c2531bf35436ed3766cd6cfe89d352b050ccc4d7005ce6400adf97503da1b 28 | command: ["/bin/bash", "-c"] 29 | args: 30 | - | 31 | find /sys/class/net/*/device/driver/module/drivers -maxdepth 1 -path "*e1000e*" | awk -F'/' '{print $5}' | xargs -I% nsenter --mount=/host/proc/$(pidof /usr/local/bin/kubelet)/ns/mnt --net=/host/proc/$(pidof /usr/local/bin/kubelet)/ns/net -- sh -c " 32 | echo '% - BEFORE' && 33 | echo '==========' && 34 | ethtool -k % && 35 | echo '==========' && 36 | echo 'Disabling offloads for %...' && 37 | ethtool -K % tso off gso off gro off && 38 | echo '==========' && 39 | echo '% - AFTER' && 40 | echo '==========' && 41 | ethtool -k % && 42 | echo '=========='" && 43 | 44 | echo 'Setting bridge MACs based on bridge master interfaces' && 45 | for br in $(ip -json link show type bridge | jq -r '.[].ifname'); do 46 | ip link show dev $br 47 | ip -json link show dev $(ip -json link show master $br | jq -r '.[] | select(.flags[] | index("MASTER")) | .ifname') | jq -r '.[0].address' | xargs -I% ip link set dev $br address % 48 | ip link show dev $br 49 | done && 50 | sleep infinity 51 | securityContext: 52 | privileged: true 53 | resources: 54 | requests: 55 | cpu: "10m" 56 | limits: 57 | memory: "50Mi" 58 | persistence: 59 | procfs: 60 | type: hostPath 61 | hostPath: /proc 62 | hostPathType: Directory 63 | globalMounts: 64 | - path: /host/proc 65 | readOnly: true 66 | netfs: 67 | type: hostPath 68 | hostPath: /sys 69 | hostPathType: Directory 70 | globalMounts: 71 | - path: /host/net 72 | readOnly: true 73 | defaultPodOptions: 74 | automountServiceAccountToken: false 75 | enableServiceLinks: false 76 | hostNetwork: true 77 | hostPID: true 78 | # nodeSelector: 79 | # feature.node.kubernetes.io/e1000e.present: "true" -------------------------------------------------------------------------------- /kubernetes/kube-system/external-secrets/1password/clustersecretstore.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: external-secrets.io/v1 3 | kind: ClusterSecretStore 4 | metadata: 5 | name: onepassword-connect 6 | namespace: kube-system 7 | spec: 8 | provider: 9 | onepassword: 10 | connectHost: http://onepassword-connect:8080 11 | vaults: 12 | kubernetes: 1 13 | auth: 14 | secretRef: 15 | connectTokenSecretRef: 16 | name: onepassword-secret 17 | key: token 18 | namespace: kube-system 19 | -------------------------------------------------------------------------------- /kubernetes/kube-system/external-secrets/chart/external-secrets.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/helmrelease-helm-v2.json 3 | apiVersion: helm.toolkit.fluxcd.io/v2 4 | kind: HelmRelease 5 | metadata: 6 | name: external-secrets 7 | namespace: kube-system 8 | spec: 9 | interval: 30m 10 | chart: 11 | spec: 12 | chart: external-secrets 13 | version: 0.17.0 14 | sourceRef: 15 | kind: HelmRepository 16 | name: external-secrets 17 | namespace: flux-system 18 | interval: 30m 19 | values: 20 | installCRDs: false 21 | replicaCount: 1 22 | serviceMonitor: 23 | enabled: true 24 | webhook: 25 | serviceMonitor: 26 | enabled: true 27 | certController: 28 | serviceMonitor: 29 | enabled: true 30 | grafanaDashboard: 31 | enabled: true 32 | -------------------------------------------------------------------------------- /kubernetes/kube-system/intel-device-plugins/gpu-plugin.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/helmrelease-helm-v2.json 3 | apiVersion: helm.toolkit.fluxcd.io/v2 4 | kind: HelmRelease 5 | metadata: 6 | name: intel-device-plugin-gpu 7 | namespace: kube-system 8 | spec: 9 | interval: 15m 10 | chart: 11 | spec: 12 | chart: intel-device-plugins-gpu 13 | version: 0.32.1 14 | sourceRef: 15 | kind: HelmRepository 16 | name: intel 17 | namespace: flux-system 18 | maxHistory: 3 19 | install: 20 | remediation: 21 | retries: 3 22 | upgrade: 23 | cleanupOnFail: true 24 | remediation: 25 | retries: 3 26 | uninstall: 27 | keepHistory: false 28 | values: 29 | name: intel-gpu-plugin 30 | sharedDevNum: 2 # TODO: the higher the number, the less resrouce slices each client gets, consider setting this to 1 31 | nodeFeatureRule: true 32 | -------------------------------------------------------------------------------- /kubernetes/kube-system/intel-device-plugins/operator.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/helmrelease-helm-v2.json 3 | apiVersion: helm.toolkit.fluxcd.io/v2 4 | kind: HelmRelease 5 | metadata: 6 | name: intel-device-plugin-operator 7 | namespace: kube-system 8 | spec: 9 | interval: 30m 10 | chart: 11 | spec: 12 | chart: intel-device-plugins-operator 13 | version: 0.32.1 14 | sourceRef: 15 | kind: HelmRepository 16 | name: intel 17 | namespace: flux-system 18 | maxHistory: 3 19 | install: 20 | crds: CreateReplace 21 | remediation: 22 | retries: 3 23 | upgrade: 24 | cleanupOnFail: true 25 | crds: CreateReplace 26 | remediation: 27 | retries: 3 28 | uninstall: 29 | keepHistory: false 30 | values: 31 | manager: 32 | devices: 33 | gpu: true -------------------------------------------------------------------------------- /kubernetes/kube-system/metrics-server/metrics-server.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/helmrelease-helm-v2.json 3 | apiVersion: helm.toolkit.fluxcd.io/v2 4 | kind: HelmRelease 5 | metadata: 6 | name: metrics-server 7 | namespace: kube-system 8 | spec: 9 | interval: 30m 10 | chart: 11 | spec: 12 | chart: metrics-server 13 | version: 3.12.2 14 | sourceRef: 15 | kind: HelmRepository 16 | name: metrics-server 17 | namespace: flux-system 18 | interval: 30m 19 | values: 20 | args: 21 | - --kubelet-insecure-tls 22 | - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname 23 | - --kubelet-use-node-status-port 24 | - --metric-resolution=10s 25 | - --kubelet-request-timeout=2s 26 | metrics: 27 | enabled: true 28 | serviceMonitor: 29 | enabled: true 30 | -------------------------------------------------------------------------------- /kubernetes/kube-system/nginx/nginx-external/external_minio.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: networking.k8s.io/v1 3 | kind: Ingress 4 | metadata: 5 | name: external-minio 6 | namespace: default 7 | spec: 8 | ingressClassName: nginx-tailscale 9 | rules: 10 | - host: &host minio-nas.eviljungle.com 11 | http: 12 | paths: 13 | - path: / 14 | pathType: Prefix 15 | backend: 16 | service: 17 | name: external-minio 18 | port: 19 | number: 9001 20 | tls: 21 | - hosts: 22 | - *host 23 | --- 24 | apiVersion: v1 25 | kind: Service 26 | metadata: 27 | name: external-minio 28 | namespace: default 29 | spec: 30 | ports: 31 | - name: minio 32 | port: 9001 33 | targetPort: 9001 34 | type: ExternalName 35 | externalName: nas.home -------------------------------------------------------------------------------- /kubernetes/kube-system/nginx/nginx-external/external_proxmox.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: networking.k8s.io/v1 3 | kind: Ingress 4 | metadata: 5 | name: external-proxmox 6 | namespace: default 7 | labels: 8 | app.kubernetes.io/name: proxmox 9 | annotations: 10 | nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" 11 | nginx.ingress.kubernetes.io/proxy-ssl-verify: "off" 12 | nginx.ingress.kubernetes.io/proxy-read-timeout: "1800s" 13 | spec: 14 | ingressClassName: nginx-tailscale 15 | rules: 16 | - host: &host proxmox.eviljungle.com 17 | http: 18 | paths: 19 | - path: / 20 | pathType: Prefix 21 | backend: 22 | service: 23 | name: external-proxmox 24 | port: 25 | number: 8006 26 | tls: 27 | - hosts: 28 | - *host 29 | --- 30 | apiVersion: v1 31 | kind: Service 32 | metadata: 33 | name: external-proxmox 34 | namespace: default 35 | spec: 36 | ports: 37 | - name: proxmox 38 | port: 8006 39 | targetPort: 8006 40 | type: ExternalName 41 | externalName: nas.home -------------------------------------------------------------------------------- /kubernetes/kube-system/node-feature-discovery/alarmdecoder-device.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/nfd.k8s-sigs.io/nodefeaturerule_v1alpha1.json 3 | apiVersion: nfd.k8s-sigs.io/v1alpha1 4 | kind: NodeFeatureRule 5 | metadata: 6 | name: alarmdecoder-device 7 | spec: 8 | rules: 9 | - # NuTech Alarmdecoder 10 | name: nutech.alarmdecoder 11 | labels: 12 | nutech.feature.node.kubernetes.io/alarmdecoder: "true" 13 | matchFeatures: 14 | - feature: usb.device 15 | matchExpressions: 16 | class: { op: In, value: ["ff"] } 17 | vendor: { op: In, value: ["0403"] } 18 | device: { op: In, value: ["6015"] } 19 | -------------------------------------------------------------------------------- /kubernetes/kube-system/node-feature-discovery/coral-device.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/nfd.k8s-sigs.io/nodefeaturerule_v1alpha1.json 3 | apiVersion: nfd.k8s-sigs.io/v1alpha1 4 | kind: NodeFeatureRule 5 | metadata: 6 | name: google-coral-device 7 | spec: 8 | rules: 9 | - # Google Coral USB Accelerator 10 | name: google.coral 11 | labels: 12 | google.feature.node.kubernetes.io/coral: "true" 13 | matchFeatures: 14 | - feature: usb.device 15 | matchExpressions: 16 | vendor: { op: In, value: ["1a6e", "18d1"] } 17 | -------------------------------------------------------------------------------- /kubernetes/kube-system/node-feature-discovery/node-feature-discovery.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/helmrelease-helm-v2.json 3 | 4 | apiVersion: helm.toolkit.fluxcd.io/v2 5 | kind: HelmRelease 6 | metadata: 7 | name: node-feature-discovery 8 | namespace: kube-system 9 | spec: 10 | interval: 15m 11 | chart: 12 | spec: 13 | chart: node-feature-discovery 14 | version: 0.17.3 15 | sourceRef: 16 | kind: HelmRepository 17 | name: kubernetes-sigs-nfd-charts 18 | namespace: flux-system 19 | maxHistory: 3 20 | install: 21 | createNamespace: true 22 | crds: CreateReplace 23 | remediation: 24 | retries: 3 25 | upgrade: 26 | cleanupOnFail: true 27 | crds: CreateReplace 28 | remediation: 29 | retries: 3 30 | uninstall: 31 | keepHistory: false 32 | values: 33 | worker: 34 | config: 35 | core: 36 | sources: ["custom", "pci", "usb"] 37 | sources: 38 | usb: 39 | deviceClassWhitelist: ["02", "03", "0e", "ef", "fe", "ff"] 40 | deviceLabelFields: ["class", "vendor", "device"] 41 | tolerations: 42 | - key: arm 43 | operator: Exists 44 | - key: "node-role.kubernetes.io/master" 45 | operator: "Exists" 46 | - effect: "NoExecute" 47 | operator: "Exists" 48 | - effect: "NoSchedule" 49 | operator: "Exists" 50 | # resources: 51 | # limits: 52 | # cpu: null 53 | # master: 54 | # resources: 55 | # limits: 56 | # cpu: null 57 | # gc: 58 | # resources: 59 | # limits: 60 | # cpu: null 61 | prometheus: 62 | enable: true 63 | -------------------------------------------------------------------------------- /kubernetes/kube-system/node-feature-discovery/zwave-device.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/nfd.k8s-sigs.io/nodefeaturerule_v1alpha1.json 3 | apiVersion: nfd.k8s-sigs.io/v1alpha1 4 | kind: NodeFeatureRule 5 | metadata: 6 | name: aeotec-zwave-device 7 | spec: 8 | rules: 9 | - # Aeotec Z-Stick Gen5+ 10 | name: aeotec.zwave 11 | labels: 12 | aeotec.feature.node.kubernetes.io/zwave: "true" 13 | matchFeatures: 14 | - feature: usb.device 15 | matchExpressions: 16 | class: { op: In, value: ["02"] } 17 | vendor: { op: In, value: ["0658"] } 18 | device: { op: In, value: ["0200"] } -------------------------------------------------------------------------------- /kubernetes/kube-system/snapshot-controller/snapshot-controller.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/helmrelease-helm-v2.json 3 | apiVersion: helm.toolkit.fluxcd.io/v2 4 | kind: HelmRelease 5 | metadata: 6 | name: snapshot-controller 7 | namespace: kube-system 8 | spec: 9 | interval: 15m 10 | chart: 11 | spec: 12 | chart: snapshot-controller 13 | version: 4.0.2 14 | sourceRef: 15 | kind: HelmRepository 16 | name: piraeus 17 | namespace: flux-system 18 | install: 19 | crds: CreateReplace 20 | remediation: 21 | retries: -1 22 | upgrade: 23 | cleanupOnFail: true 24 | crds: CreateReplace 25 | remediation: 26 | retries: 3 27 | uninstall: 28 | keepHistory: false 29 | values: 30 | controller: 31 | serviceMonitor: 32 | create: true 33 | -------------------------------------------------------------------------------- /kubernetes/kube-system/spegel/spegel.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/helmrelease-helm-v2.json 3 | apiVersion: helm.toolkit.fluxcd.io/v2 4 | kind: HelmRelease 5 | metadata: 6 | name: spegel 7 | namespace: kube-system 8 | spec: 9 | interval: 30m 10 | chart: 11 | spec: 12 | chart: spegel 13 | version: 0.3.0 14 | sourceRef: 15 | kind: HelmRepository 16 | name: spegel-org 17 | namespace: flux-system 18 | install: 19 | remediation: 20 | retries: 3 21 | upgrade: 22 | cleanupOnFail: true 23 | remediation: 24 | strategy: rollback 25 | retries: 3 26 | values: 27 | spegel: 28 | appendMirrors: true 29 | containerdSock: /run/containerd/containerd.sock 30 | containerdRegistryConfigPath: /etc/cri/conf.d/hosts 31 | serviceMonitor: 32 | enabled: true 33 | grafanaDashboard: 34 | enabled: true 35 | resources: 36 | requests: 37 | cpu: 50m 38 | memory: 128Mi 39 | limits: 40 | memory: 1Gi 41 | -------------------------------------------------------------------------------- /kubernetes/kube-system/tailscale/externalsecret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: tailscale-operator 7 | namespace: kube-system 8 | spec: 9 | secretStoreRef: 10 | kind: ClusterSecretStore 11 | name: onepassword-connect 12 | target: 13 | name: operator-oauth 14 | creationPolicy: Owner 15 | template: 16 | engineVersion: v2 17 | data: 18 | client_id: "{{ .tailscale_operator_oauth_client_id }}" 19 | client_secret: "{{ .tailscale_operator_oauth_client_secret }}" 20 | dataFrom: 21 | - extract: 22 | # tailscale_operator_oauth_client_id, tailscale_operator_oauth_client_secret 23 | key: tailscale 24 | -------------------------------------------------------------------------------- /kubernetes/kube-system/tailscale/tailscale-operator.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/helmrelease-helm-v2.json 3 | apiVersion: helm.toolkit.fluxcd.io/v2 4 | kind: HelmRelease 5 | metadata: 6 | name: tailscale-operator 7 | namespace: kube-system 8 | spec: 9 | interval: 30m 10 | chart: 11 | spec: 12 | chart: tailscale-operator 13 | version: 1.84.0 14 | interval: 30m 15 | sourceRef: 16 | kind: HelmRepository 17 | name: tailscale 18 | namespace: flux-system 19 | values: 20 | operatorConfig: 21 | hostname: "tailscale-operator" 22 | apiServerProxyConfig: 23 | mode: "true" 24 | -------------------------------------------------------------------------------- /kubernetes/kube-system/talos-backup/cronjob.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: batch/v1 3 | kind: CronJob 4 | metadata: 5 | name: talos-s3-backup 6 | namespace: kube-system 7 | spec: 8 | schedule: "10 0/6 * * *" # 10 mins past the hour every 6 hours 9 | jobTemplate: 10 | spec: 11 | template: 12 | spec: 13 | containers: 14 | - name: talos-backup 15 | image: ghcr.io/siderolabs/talos-backup:v0.1.0-beta.3 16 | workingDir: /tmp 17 | imagePullPolicy: Always 18 | envFrom: 19 | - secretRef: 20 | name: talos-s3-secret 21 | securityContext: 22 | runAsUser: 1000 23 | runAsGroup: 1000 24 | allowPrivilegeEscalation: false 25 | runAsNonRoot: true 26 | capabilities: 27 | drop: [ALL] 28 | seccompProfile: 29 | type: RuntimeDefault 30 | command: [/talos-backup] 31 | volumeMounts: 32 | - mountPath: /tmp 33 | name: tmp 34 | - mountPath: /var/run/secrets/talos.dev 35 | name: talos-secrets 36 | restartPolicy: OnFailure 37 | volumes: 38 | - emptyDir: {} 39 | name: tmp 40 | - name: talos-secrets 41 | secret: 42 | secretName: talos-s3-backup -------------------------------------------------------------------------------- /kubernetes/kube-system/talos-backup/externalsecret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://crd.movishell.pl/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: &name talos-s3-secret 7 | namespace: kube-system 8 | spec: 9 | secretStoreRef: 10 | kind: ClusterSecretStore 11 | name: onepassword-connect 12 | target: 13 | name: *name 14 | creationPolicy: Owner 15 | template: 16 | data: 17 | AWS_REGION: us-east-1 18 | AWS_ACCESS_KEY_ID: '{{ .MINIO_ACCESS_KEY }}' # minio 19 | AWS_SECRET_ACCESS_KEY: '{{ .MINIO_SECRET_KEY }}' # minio 20 | CUSTOM_S3_ENDPOINT: http://nas.home:9000 21 | BUCKET: talos-backup 22 | CLUSTER_NAME: home 23 | DISABLE_ENCRYPTION: "true" 24 | USE_PATH_STYLE: "false" 25 | dataFrom: 26 | - extract: 27 | key: minio 28 | - extract: 29 | key: talos 30 | -------------------------------------------------------------------------------- /kubernetes/kube-system/talos-backup/secret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: talos-s3-backup 6 | namespace: kube-system 7 | annotations: 8 | kubernetes.io/service-account.name: talos-s3-backup -------------------------------------------------------------------------------- /kubernetes/kube-system/talos-backup/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/talos.dev/serviceaccount_v1alpha1.json 3 | apiVersion: talos.dev/v1alpha1 4 | kind: ServiceAccount 5 | metadata: 6 | name: talos-s3-backup 7 | namespace: kube-system 8 | spec: 9 | roles: [os:etcd:backup] -------------------------------------------------------------------------------- /kubernetes/kube-system/volsync/prometheusrule.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/monitoring.coreos.com/prometheusrule_v1.json 3 | apiVersion: monitoring.coreos.com/v1 4 | kind: PrometheusRule 5 | metadata: 6 | name: volsync 7 | namespace: kube-system 8 | spec: 9 | groups: 10 | - name: volsync.rules 11 | rules: 12 | - alert: VolSyncComponentAbsent 13 | expr: | 14 | absent(up{job="volsync-metrics"}) 15 | annotations: 16 | summary: >- 17 | VolSync component has disappeared from Prometheus target discovery 18 | for: 5m 19 | labels: 20 | severity: critical 21 | 22 | - alert: VolSyncVolumeOutOfSync 23 | expr: | 24 | volsync_volume_out_of_sync == 1 25 | annotations: 26 | summary: >- 27 | {{ $labels.obj_namespace }}/{{ $labels.obj_name }} volume is out of sync 28 | for: 5m 29 | labels: 30 | severity: critical -------------------------------------------------------------------------------- /kubernetes/kube-system/volsync/volsync.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/helmrelease-helm-v2.json 3 | apiVersion: helm.toolkit.fluxcd.io/v2 4 | kind: HelmRelease 5 | metadata: 6 | name: volsync 7 | namespace: kube-system 8 | spec: 9 | interval: 30m 10 | chart: 11 | spec: 12 | chart: volsync 13 | version: 0.12.1 14 | sourceRef: 15 | kind: HelmRepository 16 | name: backube 17 | namespace: flux-system 18 | maxHistory: 3 19 | install: 20 | createNamespace: true 21 | remediation: 22 | retries: 3 23 | upgrade: 24 | cleanupOnFail: true 25 | remediation: 26 | retries: 3 27 | uninstall: 28 | keepHistory: false 29 | values: 30 | manageCRDs: true 31 | metrics: 32 | disableAuth: true 33 | -------------------------------------------------------------------------------- /kubernetes/monitoring/README.md: -------------------------------------------------------------------------------- 1 | # grafana 2 | 3 | ![](https://i.imgur.com/hzBFkEE.png) 4 | 5 | [Grafana](https://github.com/grafana/grafana) is a metrics and logging dashboard 6 | 7 | * [grafana/grafana.yaml](grafana/grafana.yaml) 8 | * [grafana/dashboards/](grafana/dashboards/) 9 | 10 | # influxdb 11 | 12 | [influxdb](https://github.com/influxdata/influxdb) is a metrics collection database 13 | 14 | * [influxdb/influxdb.yaml](influxdb/influxdb.yaml) 15 | 16 | # loki 17 | 18 | [loki](https://github.com/grafana/loki) is a logging collection system 19 | 20 | * [loki/loki.yaml](loki/loki.yaml) 21 | * [loki/objectbucketclaim.yaml](loki/objectbucketclaim.yaml) 22 | 23 | # prometheus-rules 24 | 25 | Various custom PrometheusRule definitions for this cluster 26 | 27 | * [prometheus-rules/](prometheus-rules/) 28 | 29 | # promtail 30 | 31 | [promtail](https://github.com/grafana/helm-charts/tree/main/charts/promtail) is an agent which ships the contents of local logs to a Loki instance 32 | 33 | * [promtail/promtail.yaml](promtail/promtail.yaml) 34 | 35 | # speedtest-exporter 36 | 37 | ![](https://i.imgur.com/avohPk6.png) 38 | 39 | ISP speed test results collector 40 | 41 | * [speedtest-exporter/speedtest-exporter.yaml](speedtest-exporter/speedtest-exporter.yaml) 42 | 43 | # victoria metrics 44 | 45 | ![](https://i.imgur.com/ab4qB97.png) 46 | 47 | VictoriaMetrics [k8s stack helm chart](https://github.com/VictoriaMetrics/helm-charts/tree/master/charts/victoria-metrics-k8s-stack) to take the place of kube-prometheus-stack helm chart & thanos for the same features/functionality but more stable and less resource intensive. 48 | 49 | * [victoria-metrics/victoria-metrics.yaml](victoria-metrics/victoria-metrics.yaml) 50 | -------------------------------------------------------------------------------- /kubernetes/monitoring/grafana/externalsecret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://crd.movishell.pl/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: grafana 7 | namespace: monitoring 8 | spec: 9 | secretStoreRef: 10 | kind: ClusterSecretStore 11 | name: onepassword-connect 12 | target: 13 | name: grafana-secret 14 | creationPolicy: Owner 15 | template: 16 | engineVersion: v2 17 | data: 18 | # Grafana 19 | admin-user: "admin" 20 | admin-password: "{{ .GRAFANA_ADMIN_PASSWORD }}" 21 | # TODO: revisit the use of postgres for grafana 22 | # GF_DATABASE_USER: "{{ .GF_DATABASE_USER }}" 23 | # GF_DATABASE_PASSWORD: "{{ .GF_DATABASE_PASSWORD }}" 24 | # GF_DATABASE_HOST: postgres-v17-rw.default.svc.cluster.local:5432 25 | # GF_DATABASE_NAME: grafana 26 | # GF_DATABASE_SSL_MODE: disable 27 | # GF_DATABASE_TYPE: postgres 28 | GF_AUTH_AZUREAD_CLIENT_ID: "{{ .AZURE_GRAFANA_CLIENT_ID }}" 29 | GF_AUTH_AZUREAD_CLIENT_SECRET: "{{ .AZURE_GRAFANA_CLIENT_SECRET }}" 30 | GF_AUTH_AZUREAD_AUTH_URL: "{{ .AZURE_AUTH_URL }}" 31 | GF_AUTH_AZUREAD_TOKEN_URL: "{{ .AZURE_TOKEN_URL }}" 32 | TESLAMATE_DB_PASSWORD: "{{ .TESLAMATE_POSTGRES_PASS }}" 33 | # Postgres Init 34 | # TODO: revisit the use of postgres for grafana 35 | # INIT_POSTGRES_DBNAME: grafana 36 | # INIT_POSTGRES_HOST: postgres-v17-rw.default.svc.cluster.local 37 | # INIT_POSTGRES_SUPER_PASS: "{{ .POSTGRES_SUPER_PASS }}" 38 | # INIT_POSTGRES_PASS: "{{ .GF_DATABASE_PASSWORD }}" 39 | # INIT_POSTGRES_USER: "{{ .GF_DATABASE_USER }}" 40 | dataFrom: 41 | - extract: 42 | key: grafana 43 | - extract: 44 | key: teslamate 45 | - extract: 46 | key: cloudnative-pg 47 | -------------------------------------------------------------------------------- /kubernetes/monitoring/influxdb/influxdb.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/helmrelease-helm-v2.json 3 | apiVersion: helm.toolkit.fluxcd.io/v2 4 | kind: HelmRelease 5 | metadata: 6 | name: influxdb 7 | namespace: monitoring 8 | spec: 9 | interval: 1h 10 | chart: 11 | spec: 12 | chart: influxdb 13 | version: 4.12.5 14 | sourceRef: 15 | kind: HelmRepository 16 | name: influxdata-charts 17 | namespace: flux-system 18 | interval: 5m 19 | values: 20 | image: 21 | repository: "influxdb" 22 | tag: "1.8.10-alpine" # TODO: 1.11.8-alpine has issues and need to migrate to 2.x anyway 23 | service: 24 | type: LoadBalancer 25 | loadBalancerIP: 10.0.6.2 26 | externalTrafficPolicy: Local 27 | persistence: 28 | enabled: true 29 | size: 50Gi 30 | storageClass: ceph-block 31 | resources: 32 | requests: 33 | memory: 2Gi 34 | cpu: 100m 35 | limits: 36 | memory: 4Gi 37 | livenessProbe: 38 | timeoutSeconds: 10 39 | readinessProbe: 40 | timeoutSeconds: 10 41 | startupProbe: 42 | enabled: true 43 | failureThreshold: 10 44 | periodSeconds: 10 45 | config: 46 | opentsdb: 47 | enabled: true 48 | bind-address: ":4242" 49 | graphite: 50 | enabled: true 51 | database: graphitedb 52 | retention-policy: "" 53 | bind-address: ":2003" 54 | protocol: tcp 55 | consistency-lvel: one 56 | templates: 57 | - "*.app env.service.resource.measurement" 58 | - "servers.* .host.resource.measurement.field*" 59 | -------------------------------------------------------------------------------- /kubernetes/monitoring/influxdb/volsync.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://crd.movishell.pl/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: influxdb-restic 7 | namespace: monitoring 8 | spec: 9 | secretStoreRef: 10 | kind: ClusterSecretStore 11 | name: onepassword-connect 12 | target: 13 | name: influxdb-restic-secret 14 | creationPolicy: Owner 15 | template: 16 | engineVersion: v2 17 | data: 18 | RESTIC_REPOSITORY: '{{ .REPOSITORY_TEMPLATE }}/influxdb' 19 | RESTIC_PASSWORD: '{{ .RESTIC_PASSWORD }}' 20 | AWS_ACCESS_KEY_ID: '{{ .MINIO_ACCESS_KEY }}' 21 | AWS_SECRET_ACCESS_KEY: '{{ .MINIO_SECRET_KEY }}' 22 | dataFrom: 23 | - extract: 24 | key: minio 25 | --- 26 | # yaml-language-server: $schema=https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/volsync.backube/replicationsource_v1alpha1.json 27 | apiVersion: volsync.backube/v1alpha1 28 | kind: ReplicationSource 29 | metadata: 30 | name: influxdb 31 | namespace: monitoring 32 | spec: 33 | sourcePVC: influxdb-data-influxdb-0 34 | trigger: 35 | schedule: "20 7 * * *" 36 | restic: 37 | copyMethod: Snapshot 38 | pruneIntervalDays: 10 39 | repository: influxdb-restic-secret 40 | cacheCapacity: 2Gi 41 | volumeSnapshotClassName: csi-ceph-blockpool 42 | storageClassName: ceph-block 43 | moverSecurityContext: 44 | runAsUser: 1500 45 | runAsGroup: 1500 46 | fsGroup: 1500 47 | retain: 48 | daily: 10 49 | within: 3d 50 | -------------------------------------------------------------------------------- /kubernetes/monitoring/loki/loki.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/helmrelease-helm-v2.json 3 | apiVersion: helm.toolkit.fluxcd.io/v2 4 | kind: HelmRelease 5 | metadata: 6 | name: loki 7 | namespace: monitoring 8 | spec: 9 | interval: 1h 10 | chart: 11 | spec: 12 | chart: loki 13 | version: 6.30.1 14 | sourceRef: 15 | kind: HelmRepository 16 | name: grafana-charts 17 | namespace: flux-system 18 | maxHistory: 3 19 | install: 20 | createNamespace: true 21 | remediation: 22 | retries: 3 23 | upgrade: 24 | cleanupOnFail: true 25 | remediation: 26 | retries: 3 27 | uninstall: 28 | keepHistory: false 29 | timeout: 20m 30 | values: 31 | deploymentMode: SingleBinary 32 | loki: 33 | analytics: 34 | reporting_enabled: false 35 | auth_enabled: false 36 | commonConfig: 37 | replication_factor: 1 38 | compactor: 39 | working_directory: /var/loki/compactor/retention 40 | delete_request_store: filesystem 41 | retention_enabled: true 42 | ingester: 43 | chunk_encoding: snappy 44 | limits_config: 45 | retention_period: 15d 46 | schemaConfig: 47 | configs: 48 | - from: "2024-04-01" 49 | store: tsdb 50 | object_store: filesystem 51 | schema: v13 52 | index: 53 | prefix: loki_index_ 54 | period: 24h 55 | server: 56 | log_level: info 57 | storage: 58 | type: filesystem 59 | backend: 60 | replicas: 0 61 | chunksCache: 62 | enabled: false 63 | gateway: 64 | replicas: 0 65 | lokiCanary: 66 | enabled: false 67 | read: 68 | replicas: 0 69 | resultsCache: 70 | enabled: false 71 | sidecar: 72 | image: 73 | repository: ghcr.io/kiwigrid/k8s-sidecar 74 | rules: 75 | searchNamespace: ALL 76 | singleBinary: 77 | replicas: 1 78 | persistence: 79 | enabled: true 80 | storageClass: ceph-block 81 | size: 5Gi # TODO: revisit? 82 | test: 83 | enabled: false 84 | write: 85 | replicas: 0 86 | -------------------------------------------------------------------------------- /kubernetes/monitoring/namespace.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Namespace 4 | metadata: 5 | name: monitoring 6 | -------------------------------------------------------------------------------- /kubernetes/monitoring/prometheus-rules/dockerhub.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/monitoring.coreos.com/prometheusrule_v1.json 3 | apiVersion: monitoring.coreos.com/v1 4 | kind: PrometheusRule 5 | metadata: 6 | name: dockerhub-rules 7 | namespace: monitoring 8 | spec: 9 | groups: 10 | - name: dockerhub 11 | rules: 12 | - alert: DockerhubRateLimitRisk 13 | annotations: 14 | summary: Kubernetes cluster Dockerhub rate limit risk 15 | expr: count(time() - container_last_seen{image=~"(docker.io).*",container!=""} < 30) > 100 16 | labels: 17 | severity: warning 18 | -------------------------------------------------------------------------------- /kubernetes/monitoring/prometheus-rules/ingress-nginx.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/monitoring.coreos.com/prometheusrule_v1.json 3 | apiVersion: monitoring.coreos.com/v1 4 | kind: PrometheusRule 5 | metadata: 6 | name: ingress-nginx-rules 7 | namespace: monitoring 8 | spec: 9 | groups: 10 | - name: ingress-nginx.rules 11 | rules: 12 | - alert: NginxLatencyHigh 13 | expr: histogram_quantile(0.99, sum(rate(nginx_http_request_duration_seconds_bucket[2m])) by (host, node)) > 3 14 | for: 2m 15 | labels: 16 | severity: warning 17 | annotations: 18 | summary: Nginx latency high (instance {{ $labels.instance }}) 19 | description: "Nginx p99 latency is higher than 3 seconds\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" -------------------------------------------------------------------------------- /kubernetes/monitoring/prometheus-rules/loki.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/monitoring.coreos.com/prometheusrule_v1.json 3 | apiVersion: monitoring.coreos.com/v1 4 | kind: PrometheusRule 5 | metadata: 6 | name: loki.rules 7 | namespace: monitoring 8 | spec: 9 | groups: 10 | - name: loki.rules 11 | rules: 12 | - alert: LokiProcessTooManyRestarts 13 | expr: 'changes(process_start_time_seconds{job=~".*loki.*"}[15m]) > 2' 14 | for: 0m 15 | labels: 16 | severity: warning 17 | annotations: 18 | summary: Loki process too many restarts (instance {{ $labels.instance }}) 19 | description: "A loki process had too many restarts (target {{ $labels.instance }})\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 20 | 21 | - alert: LokiRequestErrors 22 | expr: '100 * sum(rate(loki_request_duration_seconds_count{status_code=~"5.."}[1m])) by (namespace, job, route) / sum(rate(loki_request_duration_seconds_count[1m])) by (namespace, job, route) > 10' 23 | for: 15m 24 | labels: 25 | severity: critical 26 | annotations: 27 | summary: Loki request errors (instance {{ $labels.instance }}) 28 | description: "The {{ $labels.job }} and {{ $labels.route }} are experiencing errors\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 29 | 30 | - alert: LokiRequestPanic 31 | expr: 'sum(increase(loki_panic_total[10m])) by (namespace, job) > 0' 32 | for: 5m 33 | labels: 34 | severity: critical 35 | annotations: 36 | summary: Loki request panic (instance {{ $labels.instance }}) 37 | description: "The {{ $labels.job }} is experiencing {{ printf \"%.2f\" $value }}% increase of panics\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 38 | 39 | - alert: LokiRequestLatency 40 | expr: '(histogram_quantile(0.99, sum(rate(loki_request_duration_seconds_bucket{route!~"(?i).*tail.*"}[5m])) by (le))) > 1' 41 | for: 5m 42 | labels: 43 | severity: critical 44 | annotations: 45 | summary: Loki request latency (instance {{ $labels.instance }}) 46 | description: "The {{ $labels.job }} {{ $labels.route }} is experiencing {{ printf \"%.2f\" $value }}s 99th percentile latency\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 47 | -------------------------------------------------------------------------------- /kubernetes/monitoring/prometheus-rules/oom.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/monitoring.coreos.com/prometheusrule_v1.json 3 | apiVersion: monitoring.coreos.com/v1 4 | kind: PrometheusRule 5 | metadata: 6 | name: oom-rules 7 | namespace: monitoring 8 | spec: 9 | groups: 10 | - name: oom 11 | rules: 12 | - alert: OomKilled 13 | annotations: 14 | summary: Container {{ $labels.container }} in pod {{ $labels.namespace }}/{{ $labels.pod }} has been OOMKilled {{ $value }} times in the last 10 minutes. 15 | expr: (kube_pod_container_status_restarts_total - kube_pod_container_status_restarts_total offset 10m >= 1) and ignoring (reason) min_over_time(kube_pod_container_status_last_terminated_reason{reason="OOMKilled"}[10m]) == 1 16 | labels: 17 | severity: warning 18 | -------------------------------------------------------------------------------- /kubernetes/monitoring/prometheus-rules/smartctl-exporter.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/monitoring.coreos.com/prometheusrule_v1.json 3 | apiVersion: monitoring.coreos.com/v1 4 | kind: PrometheusRule 5 | metadata: 6 | labels: 7 | prometheus: k8s 8 | role: alert-rules 9 | name: smartctl-exporter-rules 10 | namespace: monitoring 11 | spec: 12 | groups: 13 | - name: SmartctlExporter 14 | rules: 15 | - alert: SmartDeviceTemperatureWarning 16 | expr: 'smartctl_device_temperature > 60' 17 | for: 2m 18 | labels: 19 | severity: warning 20 | annotations: 21 | summary: Smart device temperature warning (instance {{ $labels.instance }}) 22 | description: "Device temperature warning (instance {{ $labels.instance }})\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 23 | 24 | - alert: SmartDeviceTemperatureCritical 25 | expr: 'smartctl_device_temperature > 80' 26 | for: 2m 27 | labels: 28 | severity: critical 29 | annotations: 30 | summary: Smart device temperature critical (instance {{ $labels.instance }}) 31 | description: "Device temperature critical (instance {{ $labels.instance }})\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 32 | 33 | - alert: SmartCriticalWarning 34 | expr: 'smartctl_device_critical_warning > 0' 35 | for: 15m 36 | labels: 37 | severity: critical 38 | annotations: 39 | summary: Smart critical warning (instance {{ $labels.instance }}) 40 | description: "device has critical warning (instance {{ $labels.instance }})\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 41 | 42 | - alert: SmartMediaErrors 43 | expr: 'smartctl_device_media_errors > 0' 44 | for: 15m 45 | labels: 46 | severity: critical 47 | annotations: 48 | summary: Smart media errors (instance {{ $labels.instance }}) 49 | description: "device has media errors (instance {{ $labels.instance }})\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 50 | 51 | - alert: SmartNvmeWearoutIndicator 52 | expr: 'smartctl_device_available_spare{device=~"nvme.*"} < smartctl_device_available_spare_threshold{device=~"nvme.*"}' 53 | for: 15m 54 | labels: 55 | severity: critical 56 | annotations: 57 | summary: Smart NVME Wearout Indicator (instance {{ $labels.instance }}) 58 | description: "NVMe device is wearing out (instance {{ $labels.instance }})\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 59 | -------------------------------------------------------------------------------- /kubernetes/monitoring/prometheus-rules/upsc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/monitoring.coreos.com/prometheusrule_v1.json 3 | apiVersion: monitoring.coreos.com/v1 4 | kind: PrometheusRule 5 | metadata: 6 | labels: 7 | prometheus: k8s 8 | role: alert-rules 9 | name: upsc-rules 10 | namespace: monitoring 11 | spec: 12 | groups: 13 | - name: upsc.rules 14 | rules: 15 | - alert: UPS5MinutesRemain 16 | annotations: 17 | description: UPS almost depleted 18 | summary: UPS {{$labels.instance}} has less than 5 minutes of battery left 19 | expr: upsc_battery_runtime/60 < 5 20 | for: 30s 21 | labels: 22 | severity: critical 23 | - alert: UPS10MinutesRemain 24 | annotations: 25 | description: UPS almost depleted 26 | summary: UPS {{$labels.instance}} has less than 10 minutes of battery left 27 | expr: upsc_battery_runtime/60 < 10 28 | for: 30s 29 | labels: 30 | severity: critical 31 | # - alert: UPSOnBattery 32 | # annotations: 33 | # description: UPS is running on its battery 34 | # summary: UPS {{$labels.instance}} is running on batteries 35 | # expr: TBD > 0 36 | # for: 5m 37 | # labels: 38 | # severity: critical 39 | -------------------------------------------------------------------------------- /kubernetes/monitoring/prometheus-rules/zfs-exporter.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/monitoring.coreos.com/prometheusrule_v1.json 3 | apiVersion: monitoring.coreos.com/v1 4 | kind: PrometheusRule 5 | metadata: 6 | labels: 7 | prometheus: k8s 8 | role: alert-rules 9 | name: zfs-exporter-rules 10 | namespace: monitoring 11 | spec: 12 | groups: 13 | # https://github.com/samber/awesome-prometheus-alerts/blob/master/_data/rules.yml 14 | - name: zfs-exporter.rules 15 | rules: 16 | - alert: HostOutOfMemory 17 | expr: node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes * 100 < 10 18 | for: 5m 19 | labels: 20 | severity: warning 21 | annotations: 22 | summary: "Host out of memory (instance {{ $labels.instance }})" 23 | description: "Node memory is filling up (< 10% left)\n VALUE = {{ $value }}\n LABELS: {{ $labels }}" 24 | - alert: ZFS pool out of space 25 | expr: 'zfs_pool_free_bytes * 100 / zfs_pool_size_bytes < 10 and ON (instance, device, mountpoint) zfs_pool_readonly == 0' 26 | for: 15m 27 | labels: 28 | severity: warning 29 | annotations: 30 | summary: "Host out of memory (instance {{ $labels.instance }})" 31 | description: Disk is almost full (< 10% left) 32 | - alert: ZFS pool unhealthy 33 | expr: 'zfs_pool_health > 0' 34 | labels: 35 | severity: critical 36 | comments: | 37 | 0: ONLINE 38 | 1: DEGRADED 39 | 2: FAULTED 40 | 3: OFFLINE 41 | 4: UNAVAIL 42 | 5: REMOVED 43 | 6: SUSPENDED 44 | annotations: 45 | summary: "ZFS pool unhealthy" 46 | description: ZFS pool state is {{ $value }}. See comments for more information. 47 | - alert: ZFS collector failed 48 | expr: 'zfs_scrape_collector_success != 1' 49 | for: 5m 50 | labels: 51 | severity: critical 52 | annotations: 53 | summary: "ZFS collector failed" 54 | description: ZFS collector for {{ $labels.instance }} has failed to collect information 55 | - alert: ZfsUnexpectedPoolState 56 | annotations: 57 | summary: ZFS pool {{$labels.zpool}} on {{$labels.instance}} is in a unexpected state {{$labels.state}} 58 | expr: node_zfs_zpool_state{state!="online"} > 0 59 | labels: 60 | severity: critical 61 | -------------------------------------------------------------------------------- /kubernetes/monitoring/promtail/promtail.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/helmrelease-helm-v2.json 3 | apiVersion: helm.toolkit.fluxcd.io/v2 4 | kind: HelmRelease 5 | metadata: 6 | name: promtail 7 | namespace: monitoring 8 | spec: 9 | interval: 1h 10 | chart: 11 | spec: 12 | chart: promtail 13 | version: 6.17.0 14 | sourceRef: 15 | kind: HelmRepository 16 | name: grafana-charts 17 | namespace: flux-system 18 | install: 19 | remediation: 20 | retries: -1 21 | upgrade: 22 | cleanupOnFail: true 23 | remediation: 24 | retries: 3 25 | timeout: 20m 26 | values: 27 | fullnameOverride: promtail 28 | 29 | config: 30 | clients: 31 | - url: http://loki-headless.monitoring.svc.cluster.local:3100/loki/api/v1/push 32 | 33 | serviceMonitor: 34 | enabled: true 35 | -------------------------------------------------------------------------------- /kubernetes/monitoring/speedtest-exporter/prometheusrule.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://kube-schemas.pages.dev/monitoring.coreos.com/prometheusrule_v1.json 3 | apiVersion: monitoring.coreos.com/v1 4 | kind: PrometheusRule 5 | metadata: 6 | name: speedtest-exporter-rules 7 | namespace: monitoring 8 | spec: 9 | groups: 10 | - name: speedtest-exporter.rules 11 | rules: 12 | - alert: SpeedtestExporterAbsent 13 | annotations: 14 | description: Speedtest Exporter has disappeared from Prometheus target discovery. 15 | summary: Speedtest Exporter is down. 16 | expr: | 17 | absent(up{job=~".*speedtest-exporter.*"} == 1) 18 | for: 75m 19 | labels: 20 | severity: critical 21 | - alert: SpeedtestSlowInternetDownload 22 | annotations: 23 | description: Internet download speed is averaging {{ humanize $value }} Mbps. 24 | summary: SpeedTest slow internet download. 25 | expr: | 26 | avg_over_time(speedtest_download_bits_per_second{job=~".*speedtest-exporter.*"}[4h]) 27 | < 400 28 | for: 0m 29 | labels: 30 | severity: warning 31 | - alert: SpeedtestSlowInternetUpload 32 | annotations: 33 | description: Internet upload speed is averaging {{ humanize $value }} Mbps. 34 | summary: SpeedTest slow internet upload. 35 | expr: | 36 | avg_over_time(speedtest_upload_bits_per_second{job=~".*speedtest-exporter.*"}[4h]) 37 | < 400 38 | for: 0m 39 | labels: 40 | severity: warning 41 | - alert: SpeedtestHighPingLatency 42 | annotations: 43 | description: Internet ping latency is averaging {{ humanize $value }} ms. 44 | summary: SpeedTest high ping latency. 45 | expr: | 46 | avg_over_time(speedtest_ping_latency_milliseconds{job=~".*speedtest-exporter.*"}[4h]) 47 | > 20 48 | for: 0m 49 | labels: 50 | severity: warning 51 | - alert: SpeedtestHighJitterLatency 52 | annotations: 53 | description: Internet jitter latency is averaging {{ humanize $value }} ms. 54 | summary: SpeedTest high jitter latency. 55 | expr: | 56 | avg_over_time(speedtest_jitter_latency_milliseconds{job=~".*speedtest-exporter.*"}[4h]) 57 | > 30 58 | for: 0m 59 | labels: 60 | severity: warning 61 | -------------------------------------------------------------------------------- /kubernetes/monitoring/speedtest-exporter/servicemonitor.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://kube-schemas.pages.dev/monitoring.coreos.com/servicemonitor_v1.json 3 | apiVersion: monitoring.coreos.com/v1 4 | kind: ServiceMonitor 5 | metadata: 6 | name: &app speedtest-exporter 7 | namespace: monitoring 8 | labels: &labels 9 | app.kubernetes.io/instance: *app 10 | app.kubernetes.io/name: *app 11 | spec: 12 | selector: 13 | matchLabels: 14 | <<: *labels 15 | endpoints: 16 | - port: metrics 17 | interval: 60m 18 | scrapeTimeout: 1m 19 | path: /metrics 20 | metricRelabelings: 21 | - action: labeldrop 22 | regex: (pod) 23 | -------------------------------------------------------------------------------- /kubernetes/monitoring/speedtest-exporter/speedtest-exporter.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/helmrelease-helm-v2.json 3 | apiVersion: helm.toolkit.fluxcd.io/v2 4 | kind: HelmRelease 5 | metadata: 6 | name: speedtest-exporter 7 | namespace: monitoring 8 | spec: 9 | interval: 1h 10 | chart: 11 | spec: 12 | chart: app-template 13 | version: 4.0.1 14 | sourceRef: 15 | kind: HelmRepository 16 | name: bjw-s 17 | namespace: flux-system 18 | interval: 5m 19 | values: 20 | controllers: 21 | main: 22 | containers: 23 | main: 24 | image: 25 | repository: ghcr.io/lpicanco/prometheus-speedtest-exporter 26 | tag: 0.2.2 27 | resources: 28 | requests: 29 | cpu: 10m 30 | memory: 15Mi 31 | limits: 32 | memory: 100Mi 33 | service: 34 | app: 35 | controller: main 36 | ipFamilyPolicy: PreferDualStack 37 | ports: 38 | metrics: 39 | port: 9516 -------------------------------------------------------------------------------- /kubernetes/monitoring/victoria-metrics/externalsecret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://crd.movishell.pl/external-secrets.io/externalsecret_v1beta1.json 3 | apiVersion: external-secrets.io/v1 4 | kind: ExternalSecret 5 | metadata: 6 | name: victoriametrics 7 | namespace: monitoring 8 | spec: 9 | secretStoreRef: 10 | kind: ClusterSecretStore 11 | name: onepassword-connect 12 | target: 13 | name: victoria-metrics-k8s-stack-helm-values 14 | creationPolicy: Owner 15 | template: 16 | engineVersion: v2 17 | data: 18 | values.yaml: | 19 | alertmanager: 20 | config: 21 | global: 22 | slack_api_url: "{{ .DISCORD_ALERTMANAGER_WEBHOOK_URL }}" 23 | additionalScrapeConfigs.yaml: | 24 | - job_name: 'home-assistant' 25 | scrape_interval: 60s 26 | metrics_path: '/api/prometheus' 27 | authorization: 28 | credentials: "{{ .PROM_HASS_TOKEN }}" 29 | scheme: http 30 | static_configs: 31 | - targets: 32 | - home-assistant.default.svc:8123 33 | dataFrom: 34 | - extract: 35 | key: prometheus 36 | -------------------------------------------------------------------------------- /kubernetes/rook-ceph/operator/rook-ceph.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/helmrelease-helm-v2.json 3 | apiVersion: helm.toolkit.fluxcd.io/v2 4 | kind: HelmRelease 5 | metadata: 6 | name: rook-ceph 7 | namespace: rook-ceph 8 | spec: 9 | interval: 30m 10 | releaseName: rook-ceph 11 | chart: 12 | spec: 13 | chart: rook-ceph 14 | version: v1.17.4 15 | sourceRef: 16 | kind: HelmRepository 17 | name: rook-ceph 18 | namespace: flux-system 19 | values: 20 | crds: 21 | enabled: true 22 | csi: 23 | cephFSKernelMountOptions: ms_mode=prefer-crc 24 | enableCephfsDriver: false 25 | enableCephfsSnapshotter: false 26 | enableLiveness: true 27 | serviceMonitor: 28 | enabled: true 29 | enableDiscoveryDaemon: true 30 | monitoring: 31 | enabled: true 32 | resources: 33 | requests: 34 | memory: 128Mi # unchangable 35 | cpu: 100m # unchangable 36 | limits: {} 37 | -------------------------------------------------------------------------------- /kubernetes/system-upgrade/README.md: -------------------------------------------------------------------------------- 1 | # System Upgrade Controller 2 | 3 | This handles the automatic upgrade of the talos system and kubernetes cluster. See [system-upgrade-controller](https://github.com/rancher/system-upgrade-controller) for more details on the operation of this component. 4 | 5 | * [system-upgrade-controller.yaml](system-upgrade-controller.yaml) - This is the foundational YAML to deploy the controller to make this capability work 6 | * [talos-plan.yaml](talos-plan.yaml) - This Plan will automatically upgrade to the talos system to the defined version which is managed by renovate. 7 | * [kubernetes-plan.yaml](kubernetes-plan.yaml) - This Plan will automatically upgrade to the kubernetes system to the defined version which is managed by renovate. 8 | -------------------------------------------------------------------------------- /kubernetes/system-upgrade/kubernetes-plan.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/upgrade.cattle.io/plan_v1.json 3 | apiVersion: upgrade.cattle.io/v1 4 | kind: Plan 5 | metadata: 6 | name: kubernetes 7 | namespace: system-upgrade 8 | spec: 9 | # renovate: datasource=docker depName=ghcr.io/siderolabs/kubelet 10 | version: v1.33.1 11 | concurrency: 1 12 | postCompleteDelay: 30s 13 | exclusive: true 14 | serviceAccountName: system-upgrade-controller 15 | secrets: 16 | - name: system-upgrade-controller 17 | path: /var/run/secrets/talos.dev 18 | ignoreUpdates: true 19 | nodeSelector: 20 | matchExpressions: 21 | - key: node-role.kubernetes.io/control-plane 22 | operator: Exists 23 | tolerations: 24 | - {key: node-role.kubernetes.io/control-plane, effect: NoSchedule, operator: Exists} 25 | upgrade: 26 | # renovate: datasource=docker depName=ghcr.io/siderolabs/installer 27 | image: ghcr.io/siderolabs/talosctl:v1.10.3 28 | args: 29 | - --nodes=$(SYSTEM_UPGRADE_NODE_NAME) 30 | - upgrade-k8s 31 | - --to=$(SYSTEM_UPGRADE_PLAN_LATEST_VERSION) -------------------------------------------------------------------------------- /kubernetes/system-upgrade/namespace.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Namespace 4 | metadata: 5 | name: system-upgrade 6 | -------------------------------------------------------------------------------- /kubernetes/system-upgrade/system-upgrade-controller.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/helmrelease-helm-v2.json 3 | apiVersion: helm.toolkit.fluxcd.io/v2 4 | kind: HelmRelease 5 | metadata: 6 | name: system-upgrade-controller 7 | namespace: system-upgrade 8 | spec: 9 | interval: 15m 10 | chart: 11 | spec: 12 | chart: app-template 13 | version: 4.0.1 14 | sourceRef: 15 | kind: HelmRepository 16 | name: bjw-s 17 | namespace: flux-system 18 | maxHistory: 2 19 | values: 20 | controllers: 21 | system-upgrade-controller: 22 | strategy: RollingUpdate 23 | replicas: 1 24 | 25 | pod: 26 | securityContext: 27 | runAsNonRoot: true 28 | runAsUser: 65534 29 | runAsGroup: 65534 30 | tolerations: 31 | - key: CriticalAddonsOnly 32 | operator: Exists 33 | - key: node-role.kubernetes.io/control-plane 34 | operator: Exists 35 | effect: NoSchedule 36 | - key: node-role.kubernetes.io/master 37 | operator: Exists 38 | effect: NoSchedule 39 | 40 | containers: 41 | app: 42 | image: 43 | repository: docker.io/rancher/system-upgrade-controller 44 | tag: v0.15.2 45 | env: 46 | SYSTEM_UPGRADE_CONTROLLER_LEADER_ELECT: true 47 | SYSTEM_UPGRADE_CONTROLLER_NAME: system-upgrade-controller 48 | SYSTEM_UPGRADE_CONTROLLER_NAMESPACE: 49 | valueFrom: 50 | fieldRef: 51 | fieldPath: metadata.namespace 52 | SYSTEM_UPGRADE_CONTROLLER_NODE_NAME: 53 | valueFrom: 54 | fieldRef: 55 | fieldPath: spec.nodeName 56 | SYSTEM_UPGRADE_JOB_PRIVILEGED: false 57 | securityContext: 58 | allowPrivilegeEscalation: false 59 | readOnlyRootFilesystem: true 60 | capabilities: 61 | drop: 62 | - ALL 63 | seccompProfile: 64 | type: RuntimeDefault 65 | serviceAccount: 66 | identifier: system-upgrade-controller 67 | 68 | 69 | serviceAccount: 70 | system-upgrade-controller: {} 71 | 72 | rbac: 73 | bindings: 74 | system-upgrade-controller: 75 | type: ClusterRoleBinding 76 | roleRef: 77 | kind: ClusterRole 78 | name: cluster-admin 79 | subjects: 80 | - identifier: system-upgrade-controller 81 | 82 | rawResources: 83 | talosServiceAccount: 84 | apiVersion: talos.dev/v1alpha1 85 | kind: ServiceAccount 86 | spec: 87 | spec: 88 | roles: 89 | - os:admin 90 | -------------------------------------------------------------------------------- /kubernetes/system-upgrade/talos-plan.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/upgrade.cattle.io/plan_v1.json 3 | apiVersion: upgrade.cattle.io/v1 4 | kind: Plan 5 | metadata: 6 | name: talos 7 | namespace: system-upgrade 8 | spec: 9 | # renovate: datasource=docker depName=ghcr.io/siderolabs/installer 10 | version: v1.10.3 11 | concurrency: 1 12 | postCompleteDelay: 2m 13 | exclusive: true 14 | serviceAccountName: system-upgrade-controller 15 | secrets: 16 | - name: system-upgrade-controller 17 | path: /var/run/secrets/talos.dev 18 | ignoreUpdates: true 19 | nodeSelector: 20 | matchExpressions: 21 | - key: kubernetes.io/hostname 22 | operator: Exists 23 | tolerations: 24 | - {key: node-role.kubernetes.io/control-plane, effect: NoSchedule, operator: Exists} 25 | upgrade: 26 | image: ghcr.io/jfroy/tnu:0.4.3 27 | args: 28 | - --node=$(SYSTEM_UPGRADE_NODE_NAME) 29 | - --tag=$(SYSTEM_UPGRADE_PLAN_LATEST_VERSION) 30 | - --powercycle -------------------------------------------------------------------------------- /setup/README.md: -------------------------------------------------------------------------------- 1 | # cluster setup with talos 2 | 3 | ## Setup Directory Structure 4 | 5 | The `/setup` directory contains all the components needed to bootstrap the Kubernetes cluster: 6 | 7 | ### `/setup/bootstrap` 8 | 9 | Contains Helmfile configurations for initial cluster bootstrapping, including CNI, CRDs, and other essential components required to get the cluster up and running with flux. 10 | 11 | ### `/setup/crds` 12 | 13 | Custom Resource Definitions required before Flux can deploy applications. These are invoked during normal flux kustomization reconcilliation loops and are required to be housed outside the normal `kubernetes/` tree in order to ensure that the custom types are present before they are attempted to be used. It is structured this way so that unsightly proliferation of kustomization files throughout the repo is avoided. 14 | 15 | ### `/setup/flux` 16 | 17 | Flux GitOps configuration files which are the entrypoint for flux operating the cluster from this repo. It also contains all of the `HelmRepository` definitions used by various HelmReleases in the cluster. It is necessary to ensure that the Helm repositories are available before the HelmReleases are applied. 18 | 19 | ### `/setup/talos` 20 | 21 | Talos Linux configuration for all cluster nodes. See [talos/](talos/README.md) for details on the nodes and talos configuration 22 | 23 | ## talos setup & bootstrapping 24 | 25 | (run from the repo root) 26 | 27 | Use talhelper to generate the config files in the `clusterconfig` directory. 28 | 29 | ```shell 30 | task talos:generate-clusterconfig 31 | ``` 32 | 33 | Bootstrap the talos nodes. It may take some time for the cluster to be ready. 34 | 35 | ```shell 36 | task k8s-bootstrap:talos 37 | ``` 38 | 39 | ## kubernetes setup & bootstrapping 40 | 41 | Bootstrap the kubernetes cluster with required prerequisites (cilium CNI, CRDs, flux, etc). 42 | 43 | ```shell 44 | task k8s-bootstrap:apps 45 | ``` 46 | -------------------------------------------------------------------------------- /setup/bootstrap/helmfile.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://json.schemastore.org/helmfile 3 | 4 | helmDefaults: 5 | wait: true 6 | waitForJobs: true 7 | timeout: 600 8 | force: true 9 | 10 | repositories: 11 | - name: cilium 12 | url: https://helm.cilium.io 13 | - name: jetstack 14 | url: https://charts.jetstack.io 15 | 16 | releases: 17 | - name: prometheus-operator-crds 18 | namespace: monitoring 19 | chart: oci://ghcr.io/prometheus-community/charts/prometheus-operator-crds 20 | version: 20.0.1 21 | 22 | - name: cilium 23 | namespace: kube-system 24 | chart: cilium/cilium 25 | version: 1.17.4 26 | values: 27 | - templates/cilium-values.yaml.gotmpl 28 | needs: 29 | - monitoring/prometheus-operator-crds 30 | 31 | - name: coredns 32 | namespace: kube-system 33 | chart: oci://ghcr.io/coredns/charts/coredns 34 | version: 1.42.2 35 | values: 36 | - templates/coredns-values.yaml.gotmpl 37 | needs: 38 | - kube-system/cilium 39 | 40 | - name: cert-manager 41 | namespace: cert-manager 42 | chart: jetstack/cert-manager 43 | version: v1.17.2 44 | values: 45 | - templates/cert-manager-values.yaml.gotmpl 46 | needs: 47 | - kube-system/coredns 48 | 49 | - name: flux-operator 50 | namespace: flux-system 51 | chart: oci://ghcr.io/controlplaneio-fluxcd/charts/flux-operator 52 | version: 0.22.0 53 | values: 54 | - templates/flux-operator-values.yaml.gotmpl 55 | needs: 56 | - monitoring/prometheus-operator-crds 57 | 58 | - name: flux-instance 59 | namespace: flux-system 60 | chart: oci://ghcr.io/controlplaneio-fluxcd/charts/flux-instance 61 | version: 0.22.0 62 | wait: false 63 | values: 64 | - templates/flux-instance-values.yaml.gotmpl 65 | needs: 66 | - flux-system/flux-operator -------------------------------------------------------------------------------- /setup/bootstrap/templates/cert-manager-values.yaml.gotmpl: -------------------------------------------------------------------------------- 1 | {{ (fromYaml (readFile "../../../kubernetes/cert-manager/cert-manager.yaml")).spec.values | toYaml }} -------------------------------------------------------------------------------- /setup/bootstrap/templates/cilium-values.yaml.gotmpl: -------------------------------------------------------------------------------- 1 | {{ (fromYaml (readFile "../../../kubernetes/kube-system/cilium/cilium.yaml")).spec.values | toYaml }} -------------------------------------------------------------------------------- /setup/bootstrap/templates/coredns-values.yaml.gotmpl: -------------------------------------------------------------------------------- 1 | {{ (fromYaml (readFile "../../../kubernetes/kube-system/coredns/coredns.yaml")).spec.values | toYaml }} -------------------------------------------------------------------------------- /setup/bootstrap/templates/flux-instance-values.yaml.gotmpl: -------------------------------------------------------------------------------- 1 | {{ (fromYaml (readFile "../../../kubernetes/flux-system/flux-instance/flux-instance.yaml")).spec.values | toYaml }} -------------------------------------------------------------------------------- /setup/bootstrap/templates/flux-operator-values.yaml.gotmpl: -------------------------------------------------------------------------------- 1 | {{ (fromYaml (readFile "../../../kubernetes/flux-system/flux-operator/flux-operator.yaml")).spec.values | toYaml }} -------------------------------------------------------------------------------- /setup/bootstrap/templates/resources.yaml.j2: -------------------------------------------------------------------------------- 1 | {% for namespace in ["flux-system", "monitoring", "rook-ceph"] %} 2 | --- 3 | apiVersion: v1 4 | kind: Namespace 5 | metadata: 6 | name: {{ namespace }} 7 | {% endfor %} 8 | --- 9 | apiVersion: v1 10 | kind: Secret 11 | metadata: 12 | name: onepassword-secret 13 | namespace: kube-system 14 | stringData: 15 | 1password-credentials.json: op://Personal/52okh3ubjhdu5cgeqfvvldsj2u/credentials-json-base64 16 | token: op://Personal/bspprtu7bu7qlnodme2hbfuoh4/credential 17 | --- 18 | apiVersion: v1 19 | kind: Secret 20 | metadata: 21 | name: ghcr-auth 22 | namespace: flux-system 23 | stringData: 24 | username: billimek 25 | password: op://kubernetes/ghcr/password 26 | -------------------------------------------------------------------------------- /setup/crds/vendor/cloudnative-pg_cloudnative-pg/postgresql.cnpg.io_imagecatalogs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | annotations: 6 | controller-gen.kubebuilder.io/version: v0.17.3 7 | name: imagecatalogs.postgresql.cnpg.io 8 | spec: 9 | group: postgresql.cnpg.io 10 | names: 11 | kind: ImageCatalog 12 | listKind: ImageCatalogList 13 | plural: imagecatalogs 14 | singular: imagecatalog 15 | scope: Namespaced 16 | versions: 17 | - additionalPrinterColumns: 18 | - jsonPath: .metadata.creationTimestamp 19 | name: Age 20 | type: date 21 | name: v1 22 | schema: 23 | openAPIV3Schema: 24 | description: ImageCatalog is the Schema for the imagecatalogs API 25 | properties: 26 | apiVersion: 27 | description: |- 28 | APIVersion defines the versioned schema of this representation of an object. 29 | Servers should convert recognized schemas to the latest internal value, and 30 | may reject unrecognized values. 31 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources 32 | type: string 33 | kind: 34 | description: |- 35 | Kind is a string value representing the REST resource this object represents. 36 | Servers may infer this from the endpoint the client submits requests to. 37 | Cannot be updated. 38 | In CamelCase. 39 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds 40 | type: string 41 | metadata: 42 | type: object 43 | spec: 44 | description: |- 45 | Specification of the desired behavior of the ImageCatalog. 46 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status 47 | properties: 48 | images: 49 | description: List of CatalogImages available in the catalog 50 | items: 51 | description: CatalogImage defines the image and major version 52 | properties: 53 | image: 54 | description: The image reference 55 | type: string 56 | major: 57 | description: The PostgreSQL major version of the image. Must 58 | be unique within the catalog. 59 | minimum: 10 60 | type: integer 61 | required: 62 | - image 63 | - major 64 | type: object 65 | maxItems: 8 66 | minItems: 1 67 | type: array 68 | x-kubernetes-validations: 69 | - message: Images must have unique major versions 70 | rule: self.all(e, self.filter(f, f.major==e.major).size() == 1) 71 | required: 72 | - images 73 | type: object 74 | required: 75 | - metadata 76 | - spec 77 | type: object 78 | served: true 79 | storage: true 80 | subresources: {} 81 | -------------------------------------------------------------------------------- /setup/flux/cluster/cluster.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/kustomization-kustomize-v1.json 3 | apiVersion: kustomize.toolkit.fluxcd.io/v1 4 | kind: Kustomization 5 | metadata: 6 | name: flux-repositories 7 | namespace: flux-system 8 | spec: 9 | targetNamespace: flux-system 10 | interval: 30m 11 | path: ./setup/flux/repositories 12 | prune: true 13 | wait: false 14 | sourceRef: 15 | kind: GitRepository 16 | name: flux-system 17 | --- 18 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/kustomization-kustomize-v1.json 19 | apiVersion: kustomize.toolkit.fluxcd.io/v1 20 | kind: Kustomization 21 | metadata: 22 | name: core-crds 23 | namespace: flux-system 24 | spec: 25 | interval: 30m 26 | path: ./setup/crds 27 | prune: true 28 | wait: true 29 | sourceRef: 30 | kind: GitRepository 31 | name: flux-system 32 | --- 33 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/kustomization-kustomize-v1.json 34 | apiVersion: kustomize.toolkit.fluxcd.io/v1 35 | kind: Kustomization 36 | metadata: 37 | name: cluster-apps 38 | namespace: flux-system 39 | spec: 40 | interval: 30m 41 | path: ./kubernetes 42 | prune: true 43 | sourceRef: 44 | kind: GitRepository 45 | name: flux-system 46 | dependsOn: 47 | - name: flux-repositories 48 | - name: core-crds 49 | 50 | -------------------------------------------------------------------------------- /setup/flux/repositories/1password-charts.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/refs/heads/main/helmrepository-source-v1.json 3 | apiVersion: source.toolkit.fluxcd.io/v1 4 | kind: HelmRepository 5 | metadata: 6 | name: 1password-charts 7 | namespace: flux-system 8 | spec: 9 | interval: 30m 10 | url: https://raw.githubusercontent.com/1Password/connect-helm-charts/gh-pages/ 11 | -------------------------------------------------------------------------------- /setup/flux/repositories/backube.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/refs/heads/main/helmrepository-source-v1.json 3 | apiVersion: source.toolkit.fluxcd.io/v1 4 | kind: HelmRepository 5 | metadata: 6 | name: backube 7 | namespace: flux-system 8 | spec: 9 | interval: 30m 10 | url: https://backube.github.io/helm-charts/ 11 | -------------------------------------------------------------------------------- /setup/flux/repositories/bjw-s.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/refs/heads/main/helmrepository-source-v1.json 3 | apiVersion: source.toolkit.fluxcd.io/v1 4 | kind: HelmRepository 5 | metadata: 6 | name: bjw-s 7 | namespace: flux-system 8 | spec: 9 | type: "oci" 10 | interval: 30m 11 | url: oci://ghcr.io/bjw-s-labs/helm 12 | secretRef: 13 | name: ghcr-auth -------------------------------------------------------------------------------- /setup/flux/repositories/cilium.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/refs/heads/main/helmrepository-source-v1.json 3 | apiVersion: source.toolkit.fluxcd.io/v1 4 | kind: HelmRepository 5 | metadata: 6 | name: cilium 7 | namespace: flux-system 8 | spec: 9 | interval: 30m 10 | url: https://helm.cilium.io -------------------------------------------------------------------------------- /setup/flux/repositories/cloudnative-pg.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/refs/heads/main/helmrepository-source-v1.json 3 | apiVersion: source.toolkit.fluxcd.io/v1 4 | kind: HelmRepository 5 | metadata: 6 | name: cloudnative-pg 7 | namespace: flux-system 8 | spec: 9 | interval: 2h 10 | url: https://cloudnative-pg.github.io/charts 11 | -------------------------------------------------------------------------------- /setup/flux/repositories/controlplaneio-fluxcd.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/refs/heads/main/helmrepository-source-v1.json 3 | apiVersion: source.toolkit.fluxcd.io/v1 4 | kind: HelmRepository 5 | metadata: 6 | name: controlplaneio-fluxcd 7 | namespace: flux-system 8 | spec: 9 | type: "oci" 10 | interval: 30m 11 | url: oci://ghcr.io/controlplaneio-fluxcd/charts 12 | secretRef: 13 | name: ghcr-auth -------------------------------------------------------------------------------- /setup/flux/repositories/coredns.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/refs/heads/main/helmrepository-source-v1.json 3 | apiVersion: source.toolkit.fluxcd.io/v1 4 | kind: HelmRepository 5 | metadata: 6 | name: coredns 7 | namespace: flux-system 8 | spec: 9 | type: "oci" 10 | interval: 30m 11 | url: oci://ghcr.io/coredns/charts 12 | secretRef: 13 | name: ghcr-auth -------------------------------------------------------------------------------- /setup/flux/repositories/csi-driver-nfs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/refs/heads/main/helmrepository-source-v1.json 3 | apiVersion: source.toolkit.fluxcd.io/v1 4 | kind: HelmRepository 5 | metadata: 6 | name: csi-driver-nfs 7 | namespace: flux-system 8 | spec: 9 | interval: 30m 10 | url: https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/master/charts 11 | timeout: 5m 12 | -------------------------------------------------------------------------------- /setup/flux/repositories/emqx-charts.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/refs/heads/main/helmrepository-source-v1.json 3 | apiVersion: source.toolkit.fluxcd.io/v1 4 | kind: HelmRepository 5 | metadata: 6 | name: emqx-charts 7 | namespace: flux-system 8 | spec: 9 | interval: 10m 10 | url: https://repos.emqx.io/charts 11 | timeout: 3m 12 | -------------------------------------------------------------------------------- /setup/flux/repositories/external-secrets.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/refs/heads/main/helmrepository-source-v1.json 3 | apiVersion: source.toolkit.fluxcd.io/v1 4 | kind: HelmRepository 5 | metadata: 6 | name: external-secrets 7 | namespace: flux-system 8 | spec: 9 | type: "oci" 10 | interval: 30m 11 | url: oci://ghcr.io/external-secrets/charts 12 | secretRef: 13 | name: ghcr-auth -------------------------------------------------------------------------------- /setup/flux/repositories/grafana-charts.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/refs/heads/main/helmrepository-source-v1.json 3 | apiVersion: source.toolkit.fluxcd.io/v1 4 | kind: HelmRepository 5 | metadata: 6 | name: grafana-charts 7 | namespace: flux-system 8 | spec: 9 | type: "oci" 10 | interval: 30m 11 | url: oci://ghcr.io/grafana/helm-charts 12 | secretRef: 13 | name: ghcr-auth -------------------------------------------------------------------------------- /setup/flux/repositories/influxdata-charts.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/refs/heads/main/helmrepository-source-v1.json 3 | apiVersion: source.toolkit.fluxcd.io/v1 4 | kind: HelmRepository 5 | metadata: 6 | name: influxdata-charts 7 | namespace: flux-system 8 | spec: 9 | interval: 10m 10 | url: https://helm.influxdata.com/ 11 | timeout: 3m 12 | -------------------------------------------------------------------------------- /setup/flux/repositories/ingress-nginx-charts.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/refs/heads/main/helmrepository-source-v1.json 3 | apiVersion: source.toolkit.fluxcd.io/v1 4 | kind: HelmRepository 5 | metadata: 6 | name: ingress-nginx-charts 7 | namespace: flux-system 8 | spec: 9 | interval: 30m 10 | url: https://kubernetes.github.io/ingress-nginx 11 | timeout: 5m 12 | -------------------------------------------------------------------------------- /setup/flux/repositories/intel.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/refs/heads/main/helmrepository-source-v1.json 3 | apiVersion: source.toolkit.fluxcd.io/v1 4 | kind: HelmRepository 5 | metadata: 6 | name: intel 7 | namespace: flux-system 8 | spec: 9 | interval: 2h 10 | url: https://intel.github.io/helm-charts 11 | -------------------------------------------------------------------------------- /setup/flux/repositories/jetstack.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/refs/heads/main/helmrepository-source-v1.json 3 | apiVersion: source.toolkit.fluxcd.io/v1 4 | kind: HelmRepository 5 | metadata: 6 | name: jetstack 7 | namespace: flux-system 8 | spec: 9 | interval: 30m 10 | url: https://charts.jetstack.io -------------------------------------------------------------------------------- /setup/flux/repositories/kubernetes-sigs-descheduler-charts.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/refs/heads/main/helmrepository-source-v1.json 3 | apiVersion: source.toolkit.fluxcd.io/v1 4 | kind: HelmRepository 5 | metadata: 6 | name: kubernetes-sigs-descheduler-charts 7 | namespace: flux-system 8 | spec: 9 | interval: 30m 10 | url: https://kubernetes-sigs.github.io/descheduler 11 | timeout: 5m 12 | -------------------------------------------------------------------------------- /setup/flux/repositories/kubernetes-sigs-nfd-charts.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/refs/heads/main/helmrepository-source-v1.json 3 | apiVersion: source.toolkit.fluxcd.io/v1 4 | kind: HelmRepository 5 | metadata: 6 | name: kubernetes-sigs-nfd-charts 7 | namespace: flux-system 8 | spec: 9 | interval: 30m 10 | url: https://kubernetes-sigs.github.io/node-feature-discovery/charts 11 | timeout: 5m 12 | -------------------------------------------------------------------------------- /setup/flux/repositories/metrics-server.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/refs/heads/main/helmrepository-source-v1.json 3 | apiVersion: source.toolkit.fluxcd.io/v1 4 | kind: HelmRepository 5 | metadata: 6 | name: metrics-server 7 | namespace: flux-system 8 | spec: 9 | interval: 30m 10 | url: https://kubernetes-sigs.github.io/metrics-server/ -------------------------------------------------------------------------------- /setup/flux/repositories/minecraft-server-charts.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/refs/heads/main/helmrepository-source-v1.json 3 | apiVersion: source.toolkit.fluxcd.io/v1 4 | kind: HelmRepository 5 | metadata: 6 | name: minecraft-server-charts 7 | namespace: flux-system 8 | spec: 9 | interval: 10m 10 | url: https://itzg.github.io/minecraft-server-charts/ 11 | timeout: 3m 12 | -------------------------------------------------------------------------------- /setup/flux/repositories/piraeus.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/refs/heads/main/helmrepository-source-v1.json 3 | apiVersion: source.toolkit.fluxcd.io/v1 4 | kind: HelmRepository 5 | metadata: 6 | name: piraeus 7 | namespace: flux-system 8 | spec: 9 | interval: 2h 10 | url: https://piraeus.io/helm-charts/ 11 | -------------------------------------------------------------------------------- /setup/flux/repositories/rook-ceph.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/refs/heads/main/helmrepository-source-v1.json 3 | apiVersion: source.toolkit.fluxcd.io/v1 4 | kind: HelmRepository 5 | metadata: 6 | name: rook-ceph 7 | namespace: flux-system 8 | spec: 9 | interval: 10m 10 | url: https://charts.rook.io/release 11 | timeout: 3m 12 | -------------------------------------------------------------------------------- /setup/flux/repositories/spegel-org.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/refs/heads/main/helmrepository-source-v1.json 3 | apiVersion: source.toolkit.fluxcd.io/v1 4 | kind: HelmRepository 5 | metadata: 6 | name: spegel-org 7 | namespace: flux-system 8 | spec: 9 | type: oci 10 | interval: 30m 11 | url: oci://ghcr.io/spegel-org/helm-charts 12 | secretRef: 13 | name: ghcr-auth 14 | -------------------------------------------------------------------------------- /setup/flux/repositories/tailscale.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/refs/heads/main/helmrepository-source-v1.json 3 | apiVersion: source.toolkit.fluxcd.io/v1 4 | kind: HelmRepository 5 | metadata: 6 | name: tailscale 7 | namespace: flux-system 8 | spec: 9 | interval: 2h 10 | url: https://pkgs.tailscale.com/helmcharts 11 | -------------------------------------------------------------------------------- /setup/flux/repositories/victoriametrics-charts.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/refs/heads/main/helmrepository-source-v1.json 3 | apiVersion: source.toolkit.fluxcd.io/v1 4 | kind: HelmRepository 5 | metadata: 6 | name: victoriametrics-charts 7 | namespace: flux-system 8 | spec: 9 | type: oci 10 | interval: 2h 11 | url: oci://ghcr.io/victoriametrics/helm-charts 12 | -------------------------------------------------------------------------------- /setup/talos/clusterconfig/.gitignore: -------------------------------------------------------------------------------- 1 | home-k8s-0.yaml 2 | home-k8s-a.yaml 3 | talosconfig 4 | home-k8s-0.home.yaml 5 | home-k8s-a.home.yaml 6 | home-k8s-b.yaml 7 | home-k8s-c.yaml 8 | home-k8s-i.yaml 9 | home-k8s-h.yaml 10 | home-k8s-d.yaml 11 | home-k8s-e.yaml 12 | home-k8s-f.yaml 13 | home-k8s-g.yaml 14 | -------------------------------------------------------------------------------- /setup/talos/patches/controller/admission-controller-patch.yaml: -------------------------------------------------------------------------------- 1 | - op: remove 2 | path: /cluster/apiServer/admissionControl -------------------------------------------------------------------------------- /setup/talos/patches/controller/cluster.yaml: -------------------------------------------------------------------------------- 1 | cluster: 2 | allowSchedulingOnControlPlanes: false 3 | apiServer: 4 | extraArgs: 5 | enable-aggregator-routing: true 6 | feature-gates: MutatingAdmissionPolicy=true 7 | runtime-config: admissionregistration.k8s.io/v1alpha1=true 8 | controllerManager: 9 | extraArgs: 10 | bind-address: 0.0.0.0 11 | coreDNS: 12 | disabled: true 13 | # discovery: 14 | # enabled: true 15 | # registries: 16 | # kubernetes: 17 | # disabled: false 18 | # service: 19 | # disabled: true 20 | etcd: 21 | extraArgs: 22 | listen-metrics-urls: http://0.0.0.0:2381 23 | proxy: 24 | disabled: true 25 | scheduler: 26 | extraArgs: 27 | bind-address: 0.0.0.0 28 | config: 29 | apiVersion: kubescheduler.config.k8s.io/v1 30 | kind: KubeSchedulerConfiguration 31 | profiles: 32 | - schedulerName: default-scheduler 33 | plugins: 34 | score: 35 | disabled: 36 | - name: ImageLocality 37 | pluginConfig: 38 | - name: PodTopologySpread 39 | args: 40 | defaultingType: List 41 | defaultConstraints: 42 | - maxSkew: 1 43 | topologyKey: kubernetes.io/hostname 44 | whenUnsatisfiable: ScheduleAnyway -------------------------------------------------------------------------------- /setup/talos/patches/controller/machine-features.yaml: -------------------------------------------------------------------------------- 1 | machine: 2 | features: 3 | kubernetesTalosAPIAccess: 4 | enabled: true 5 | allowedRoles: 6 | - os:admin 7 | - os:etcd:backup 8 | allowedKubernetesNamespaces: 9 | - kube-system 10 | - system-upgrade -------------------------------------------------------------------------------- /setup/talos/patches/global/machine-dns.yaml: -------------------------------------------------------------------------------- 1 | machine: 2 | features: 3 | hostDNS: 4 | enabled: true 5 | resolveMemberNames: true 6 | forwardKubeDNSToHost: false -------------------------------------------------------------------------------- /setup/talos/patches/global/machine-files.yaml: -------------------------------------------------------------------------------- 1 | machine: 2 | files: 3 | - # Spegel 4 | op: create 5 | path: /etc/cri/conf.d/20-customization.part 6 | content: | 7 | [plugins."io.containerd.cri.v1.images"] 8 | discard_unpacked_layers = false 9 | 10 | - #NFS Mount 11 | op: overwrite 12 | path: /etc/nfsmount.conf 13 | permissions: 0o644 14 | content: | 15 | [ NFSMount_Global_Options ] 16 | nfsvers=4.2 17 | hard=True 18 | nconnect=16 19 | noatime=True -------------------------------------------------------------------------------- /setup/talos/patches/global/machine-install.yaml: -------------------------------------------------------------------------------- 1 | machine: 2 | install: 3 | extraKernelArgs: 4 | - intel_iommu=on # PCI Passthrough 5 | - iommu=pt # PCI Passthrough 6 | -------------------------------------------------------------------------------- /setup/talos/patches/global/machine-network.yaml: -------------------------------------------------------------------------------- 1 | machine: 2 | network: 3 | disableSearchDomain: true -------------------------------------------------------------------------------- /setup/talos/patches/global/machine-sysctls.yaml: -------------------------------------------------------------------------------- 1 | machine: 2 | sysctls: 3 | fs.inotify.max_user_instances: 8192 # Watchdog 4 | fs.inotify.max_user_watches: 1048576 # Watchdog 5 | user.max_user_namespaces: 11255 # User namespaces 6 | net.core.rmem_max: 67108864 # Cloudflared / QUIC 7 | net.core.wmem_max: 67108864 # Cloudflared / QUIC 8 | net.ipv4.tcp_fastopen: 3 # Send and accept data in the opening SYN packet 9 | vm.nr_hugepages: 1024 # PostgreSQL -------------------------------------------------------------------------------- /setup/talos/patches/global/machine-udev.yaml: -------------------------------------------------------------------------------- 1 | machine: 2 | udev: 3 | rules: 4 | # Intel GPU 5 | - SUBSYSTEM=="drm", KERNEL=="renderD*", GROUP="44", MODE="0660" 6 | # Coral Edge M.2 TPU 7 | - SUBSYSTEM=="apex", KERNEL=="apex*", GROUP="44", MODE="0660" -------------------------------------------------------------------------------- /setup/talos/talhelper-secrets.env: -------------------------------------------------------------------------------- 1 | CLUSTER_ID=op://kubernetes/talos/cluster_id 2 | CLUSTER_SECRET=op://kubernetes/talos/cluster_secret 3 | BOOTSTRAPTOKEN=op://kubernetes/talos/bootstraptoken 4 | SECRETBOXENCRYPTIONSECRET=op://kubernetes/talos/secretboxencryptionsecret 5 | TRUSTDINFO_TOKEN=op://kubernetes/talos/trustdinfo_token 6 | CERT_ETCD_CRT=op://kubernetes/talos/cert_etcd_crt 7 | CERT_ETCD_KEY=op://kubernetes/talos/cert_etcd_key 8 | CERT_K8S_CRT=op://kubernetes/talos/cert_k8s_crt 9 | CERT_K8S_KEY=op://kubernetes/talos/cert_k8s_key 10 | CERT_K8SAGGREGATOR_CRT=op://kubernetes/talos/cert_k8saggregator_crt 11 | CERT_K8SAGGREGATOR_KEY=op://kubernetes/talos/cert_k8saggregator_key 12 | CERT_K8SSERVICEACCOUNT_KEY=op://kubernetes/talos/cert_k8sserviceaccount_key 13 | CERT_OS_CRT=op://kubernetes/talos/cert_os_crt 14 | CERT_OS_KEY=op://kubernetes/talos/cert_os_key 15 | TS_AUTHKEY=op://kubernetes/talos/TS_AUTHKEY -------------------------------------------------------------------------------- /setup/talos/talsecret.yaml: -------------------------------------------------------------------------------- 1 | cluster: 2 | id: ${CLUSTER_ID} 3 | secret: ${CLUSTER_SECRET} 4 | secrets: 5 | bootstraptoken: ${BOOTSTRAPTOKEN} 6 | secretboxencryptionsecret: ${SECRETBOXENCRYPTIONSECRET} 7 | trustdinfo: 8 | token: ${TRUSTDINFO_TOKEN} 9 | certs: 10 | etcd: 11 | crt: ${CERT_ETCD_CRT} 12 | key: ${CERT_ETCD_KEY} 13 | k8s: 14 | crt: ${CERT_K8S_CRT} 15 | key: ${CERT_K8S_KEY} 16 | k8saggregator: 17 | crt: ${CERT_K8SAGGREGATOR_CRT} 18 | key: ${CERT_K8SAGGREGATOR_KEY} 19 | k8sserviceaccount: 20 | key: ${CERT_K8SSERVICEACCOUNT_KEY} 21 | os: 22 | crt: ${CERT_OS_CRT} 23 | key: ${CERT_OS_KEY} 24 | --------------------------------------------------------------------------------