diff --git a/hosts b/hosts index 7fe25d98e..69136b8cf 100644 --- a/hosts +++ b/hosts @@ -1,3 +1,4 @@ +127.0.0.1 budget.platform.lan 127.0.0.1 dex.platform.lan 127.0.0.1 fleetdm.platform.lan 127.0.0.1 flux.platform.lan diff --git a/k8s/bases/apps/actual-budget/helm-release.yaml b/k8s/bases/apps/actual-budget/helm-release.yaml new file mode 100644 index 000000000..79ca023be --- /dev/null +++ b/k8s/bases/apps/actual-budget/helm-release.yaml @@ -0,0 +1,65 @@ +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: actual-budget + namespace: actual-budget + labels: + helm.toolkit.fluxcd.io/remediation: enabled +spec: + interval: 2m + install: + remediation: + retries: -1 + upgrade: + remediation: + retries: -1 + remediateLastFailure: true + chart: + spec: + chart: actualbudget + version: 1.8.7 + sourceRef: + kind: HelmRepository + name: actual-budget + postRenderers: + - kustomize: + patches: + - target: + kind: Deployment + name: actual-budget-actualbudget + patch: | + - op: add + path: /spec/strategy + value: + type: RollingUpdate + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 + - op: add + path: /spec/template/spec/topologySpreadConstraints + value: + - maxSkew: 1 + topologyKey: kubernetes.io/hostname + whenUnsatisfiable: ScheduleAnyway + labelSelector: + matchLabels: + app.kubernetes.io/name: actualbudget + app.kubernetes.io/instance: actual-budget + # https://github.com/community-charts/helm-charts/blob/main/charts/actualbudget/values.yaml + values: + replicaCount: ${actual_budget_replicas:=1} + ingress: + enabled: false + persistence: + enabled: true + size: 10Gi + login: + method: "openid" + openid: + enforce: true + providerName: "Dex" + discoveryUrl: "https://dex.${domain}/.well-known/openid-configuration" + clientId: "public-client" + clientSecret: "${dex_client_secret}" + authMethod: "openid" + tokenExpiration: "never" diff --git a/k8s/bases/apps/actual-budget/helm-repository.yaml b/k8s/bases/apps/actual-budget/helm-repository.yaml new file mode 100644 index 000000000..b8016f6c7 --- /dev/null +++ b/k8s/bases/apps/actual-budget/helm-repository.yaml @@ -0,0 +1,8 @@ +apiVersion: source.toolkit.fluxcd.io/v1 +kind: HelmRepository +metadata: + name: actual-budget + namespace: actual-budget +spec: + url: https://community-charts.github.io/helm-charts + interval: 60m diff --git a/k8s/bases/apps/actual-budget/http-scaled-object.yaml b/k8s/bases/apps/actual-budget/http-scaled-object.yaml new file mode 100644 index 000000000..ac6cd89e0 --- /dev/null +++ b/k8s/bases/apps/actual-budget/http-scaled-object.yaml @@ -0,0 +1,22 @@ +--- +apiVersion: http.keda.sh/v1alpha1 +kind: HTTPScaledObject +metadata: + name: actual-budget + namespace: actual-budget +spec: + hosts: + - budget.${domain} + scaleTargetRef: + name: actual-budget-actualbudget + service: actual-budget-actualbudget + port: 5006 + replicas: + min: 0 + max: 1 + scaledownPeriod: 300 + scalingMetric: + requestRate: + granularity: 1s + targetValue: 100 + window: 1m diff --git a/k8s/bases/apps/actual-budget/httproute.yaml b/k8s/bases/apps/actual-budget/httproute.yaml new file mode 100644 index 000000000..f2904c238 --- /dev/null +++ b/k8s/bases/apps/actual-budget/httproute.yaml @@ -0,0 +1,25 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: actual-budget + namespace: actual-budget + annotations: + gethomepage.dev/enabled: "true" + gethomepage.dev/name: Actual Budget + gethomepage.dev/description: Local-first personal finance and budgeting. + gethomepage.dev/group: Finance + gethomepage.dev/icon: si-actualbudget + gethomepage.dev/href: https://budget.${domain} + gethomepage.dev/pod-selector: app.kubernetes.io/name=actualbudget +spec: + parentRefs: + - name: platform + namespace: kube-system + sectionName: https + hostnames: + - budget.${domain} + rules: + - backendRefs: + - name: keda-add-ons-http-interceptor-proxy + namespace: keda + port: 8080 diff --git a/k8s/bases/apps/actual-budget/kustomization.yaml b/k8s/bases/apps/actual-budget/kustomization.yaml new file mode 100644 index 000000000..55de23346 --- /dev/null +++ b/k8s/bases/apps/actual-budget/kustomization.yaml @@ -0,0 +1,8 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - namespace.yaml + - helm-release.yaml + - helm-repository.yaml + - httproute.yaml + - http-scaled-object.yaml diff --git a/k8s/bases/apps/actual-budget/namespace.yaml b/k8s/bases/apps/actual-budget/namespace.yaml new file mode 100644 index 000000000..71a6a9987 --- /dev/null +++ b/k8s/bases/apps/actual-budget/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: actual-budget diff --git a/k8s/bases/apps/kustomization.yaml b/k8s/bases/apps/kustomization.yaml index 87f87d6cd..5ab65e116 100644 --- a/k8s/bases/apps/kustomization.yaml +++ b/k8s/bases/apps/kustomization.yaml @@ -1,6 +1,7 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: +- actual-budget/ - fleetdm/ - headlamp/ - homepage/ diff --git a/k8s/bases/infrastructure/controllers/dex/helm-release.yaml b/k8s/bases/infrastructure/controllers/dex/helm-release.yaml index 1849ec395..564a71bd8 100644 --- a/k8s/bases/infrastructure/controllers/dex/helm-release.yaml +++ b/k8s/bases/infrastructure/controllers/dex/helm-release.yaml @@ -60,6 +60,7 @@ spec: redirectURIs: - "https://oauth2-proxy.${domain}/oauth2/callback" - "https://headlamp.${domain}/oidc-callback" + - "https://budget.${domain}/oidc/callback" trustedPeers: - kubectl - name: kubectl diff --git a/k8s/clusters/prod/variables/variables-cluster-config-map.yaml b/k8s/clusters/prod/variables/variables-cluster-config-map.yaml index 6a7f3637e..4874c108d 100644 --- a/k8s/clusters/prod/variables/variables-cluster-config-map.yaml +++ b/k8s/clusters/prod/variables/variables-cluster-config-map.yaml @@ -36,9 +36,11 @@ data: # saves memory until the first KEDA reconciliation. # headlamp: min 0, max 1 (OIDC state in-memory — must stay single-pod) # whoami/fleetdm: min 0, max 2 + # actual-budget: min 0, max 1 (SQLite — single-pod only) headlamp_replicas: "1" whoami_replicas: "1" fleetdm_replicas: "1" + actual_budget_replicas: "1" # Auth chain: single replica is sufficient on cx23 nodes; prevents OOM # cascade that makes both replicas flap simultaneously. dex_replicas: "1" diff --git a/k8s/providers/docker/apps/actual-budget/patches/helm-release-patch.yaml b/k8s/providers/docker/apps/actual-budget/patches/helm-release-patch.yaml new file mode 100644 index 000000000..5df8bce25 --- /dev/null +++ b/k8s/providers/docker/apps/actual-budget/patches/helm-release-patch.yaml @@ -0,0 +1,9 @@ +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: actual-budget + namespace: actual-budget +spec: + values: + persistence: + size: 2Gi diff --git a/k8s/providers/docker/apps/kustomization.yaml b/k8s/providers/docker/apps/kustomization.yaml index 16a452bfc..31cec14fc 100644 --- a/k8s/providers/docker/apps/kustomization.yaml +++ b/k8s/providers/docker/apps/kustomization.yaml @@ -4,6 +4,11 @@ kind: Kustomization resources: - ../../../bases/apps/ patches: + - target: + kind: HelmRelease + name: actual-budget + namespace: actual-budget + path: actual-budget/patches/helm-release-patch.yaml - target: kind: HelmRelease name: headlamp