feature/cloud-agnostic #12
@@ -34,6 +34,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
token: ${{ secrets.AI_REVIEW_TOKEN }}
|
||||||
|
|
||||||
- name: Run inline review
|
- name: Run inline review
|
||||||
uses: docker://nikitafilonov/ai-review:v0.64.0
|
uses: docker://nikitafilonov/ai-review:v0.64.0
|
||||||
|
|||||||
40
README.md
40
README.md
@@ -1,9 +1,9 @@
|
|||||||
# Kubernetes Cluster - GitOps Configuration
|
# Kubernetes Cluster - GitOps Configuration
|
||||||
|
|
||||||
> **Kubernetes cluster bootstrapping and GitOps configuration repository** using ArgoCD for UpCloud Managed Kubernetes
|
> **Kubernetes cluster bootstrapping and GitOps configuration repository** using ArgoCD for multi-cloud Kubernetes (UpCloud, AWS EKS, Azure AKS, GCP GKE)
|
||||||
|
|
||||||
[](https://argoproj.github.io/cd/)
|
[](https://argoproj.github.io/cd/)
|
||||||
[](https://upcloud.com/)
|
[]()
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -95,14 +95,26 @@ This repository contains the complete GitOps configuration for our Kubernetes cl
|
|||||||
│ │ ├── renovate.yaml
|
│ │ ├── renovate.yaml
|
||||||
│ │ ├── ... # All other Application manifests
|
│ │ ├── ... # All other Application manifests
|
||||||
│ │ └── secrets.yaml
|
│ │ └── secrets.yaml
|
||||||
│ ├── overlays/ # Per-cluster overrides
|
│ ├── overlays/ # Per-cluster overrides (Kustomize)
|
||||||
│ │ ├── upc-dev/ # UpCloud Dev cluster (uses base as-is)
|
│ │ ├── upc-dev/ # UpCloud Dev (uses base as-is)
|
||||||
│ │ └── upc-prod/ # UpCloud Prod cluster (patches value paths)
|
│ │ ├── upc-prod/ # UpCloud Prod (patches value paths)
|
||||||
|
│ │ ├── eks-dev/ # AWS EKS Dev
|
||||||
|
│ │ ├── eks-prod/ # AWS EKS Prod
|
||||||
|
│ │ ├── aks-dev/ # Azure AKS Dev
|
||||||
|
│ │ ├── aks-prod/ # Azure AKS Prod
|
||||||
|
│ │ ├── gke-dev/ # GCP GKE Dev
|
||||||
|
│ │ └── gke-prod/ # GCP GKE Prod
|
||||||
│ ├── dashboards/ # Grafana dashboard ConfigMaps
|
│ ├── dashboards/ # Grafana dashboard ConfigMaps
|
||||||
│ └── values/ # Helm value overrides
|
│ └── values/ # Helm value overrides
|
||||||
│ ├── base/ # Shared values (all clusters)
|
│ ├── base/ # Shared cloud-agnostic values
|
||||||
│ ├── upc-dev/ # UpCloud Dev-specific values
|
│ ├── upc-dev/ # UpCloud Dev (storage, LB, pricing)
|
||||||
│ └── upc-prod/ # UpCloud Prod-specific values
|
│ ├── upc-prod/ # UpCloud Prod
|
||||||
|
│ ├── eks-dev/ # AWS EKS Dev
|
||||||
|
│ ├── eks-prod/ # AWS EKS Prod
|
||||||
|
│ ├── aks-dev/ # Azure AKS Dev
|
||||||
|
│ ├── aks-prod/ # Azure AKS Prod
|
||||||
|
│ ├── gke-dev/ # GCP GKE Dev
|
||||||
|
│ └── gke-prod/ # GCP GKE Prod
|
||||||
│
|
│
|
||||||
├── apps/ # Business Applications
|
├── apps/ # Business Applications
|
||||||
│ ├── mcp10x.yaml
|
│ ├── mcp10x.yaml
|
||||||
@@ -361,7 +373,7 @@ kubectl patch application myapp -n argocd \
|
|||||||
## 📖 Key Concepts
|
## 📖 Key Concepts
|
||||||
|
|
||||||
### App-of-Apps Pattern
|
### App-of-Apps Pattern
|
||||||
`_app-of-apps.yaml` is the root Application that manages all other Applications in `infra/`. Kustomize overlays in `infra/overlays/{upc-dev,upc-prod}/` render the base Applications with per-cluster patches (e.g., swapping value file paths from `upc-dev` to `upc-prod`).
|
`_app-of-apps-{cluster}.yaml` is the root Application that manages all other Applications in `infra/`. Kustomize overlays in `infra/overlays/{cluster}/` render the base Applications with per-cluster patches (e.g., swapping value file paths). Supported clusters: `upc-dev`, `upc-prod`, `eks-dev`, `eks-prod`, `aks-dev`, `aks-prod`, `gke-dev`, `gke-prod`.
|
||||||
|
|
||||||
### Multi-Source Pattern
|
### Multi-Source Pattern
|
||||||
Applications reference both:
|
Applications reference both:
|
||||||
@@ -458,16 +470,14 @@ Documentation lives in `docs/`. To update:
|
|||||||
## 📝 Notes
|
## 📝 Notes
|
||||||
|
|
||||||
### Current Environment
|
### Current Environment
|
||||||
- **Provider**: UpCloud Managed Kubernetes
|
- **Provider**: Multi-cloud (UpCloud, AWS EKS, Azure AKS, GCP GKE)
|
||||||
|
- **Active clusters**: UpCloud (upc-dev, upc-prod)
|
||||||
- **Environment**: Production (internal use only)
|
- **Environment**: Production (internal use only)
|
||||||
- **Clusters**: Multi-cluster (upc-dev, upc-prod) via Kustomize overlays
|
|
||||||
- **Auth**: Disabled for ArgoCD (internal access)
|
- **Auth**: Disabled for ArgoCD (internal access)
|
||||||
- **Backup**: None (cluster rebuildable via GitOps)
|
- **Backup**: Gitea daily backup to S3-compatible storage
|
||||||
|
|
||||||
### Known Limitations
|
### Known Limitations
|
||||||
- No automated backups (yet)
|
|
||||||
- Secret rotation not automated
|
- Secret rotation not automated
|
||||||
- Multi-cluster limited to upc-dev and upc-prod environments
|
|
||||||
- DNS management is manual
|
- DNS management is manual
|
||||||
|
|
||||||
**Future improvements**: See [Operations Runbook - Disaster Recovery](docs/OPERATIONS-RUNBOOK.md#disaster-recovery)
|
**Future improvements**: See [Operations Runbook - Disaster Recovery](docs/OPERATIONS-RUNBOOK.md#disaster-recovery)
|
||||||
@@ -504,7 +514,7 @@ Internal use only. Not for public distribution.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**Last Updated**: 2026-03-16
|
**Last Updated**: 2026-04-22
|
||||||
**Documentation Version**: 1.0.0
|
**Documentation Version**: 1.0.0
|
||||||
|
|
||||||
**🚀 Ready to get started? Check out the [Documentation Index](docs/README.md)!**
|
**🚀 Ready to get started? Check out the [Documentation Index](docs/README.md)!**
|
||||||
|
|||||||
32
_app-of-apps-aks-dev.yaml
Normal file
32
_app-of-apps-aks-dev.yaml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: monitoring
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "-1"
|
||||||
|
---
|
||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: infrastructure-apps
|
||||||
|
namespace: argocd
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: infrastructure-apps
|
||||||
|
app.kubernetes.io/part-of: platform
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: default
|
||||||
|
source:
|
||||||
|
repoURL: ssh://git@git.forteapps.net:2222/Forte/launchpad.git
|
||||||
|
targetRevision: HEAD
|
||||||
|
path: infra/overlays/aks-dev
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: default
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
32
_app-of-apps-aks-prod.yaml
Normal file
32
_app-of-apps-aks-prod.yaml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: monitoring
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "-1"
|
||||||
|
---
|
||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: infrastructure-apps
|
||||||
|
namespace: argocd
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: infrastructure-apps
|
||||||
|
app.kubernetes.io/part-of: platform
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: default
|
||||||
|
source:
|
||||||
|
repoURL: ssh://git@git.forteapps.net:2222/Forte/launchpad.git
|
||||||
|
targetRevision: HEAD
|
||||||
|
path: infra/overlays/aks-prod
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: default
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
32
_app-of-apps-eks-dev.yaml
Normal file
32
_app-of-apps-eks-dev.yaml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: monitoring
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "-1"
|
||||||
|
---
|
||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: infrastructure-apps
|
||||||
|
namespace: argocd
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: infrastructure-apps
|
||||||
|
app.kubernetes.io/part-of: platform
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: default
|
||||||
|
source:
|
||||||
|
repoURL: ssh://git@git.forteapps.net:2222/Forte/launchpad.git
|
||||||
|
targetRevision: HEAD
|
||||||
|
path: infra/overlays/eks-dev
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: default
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
32
_app-of-apps-eks-prod.yaml
Normal file
32
_app-of-apps-eks-prod.yaml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: monitoring
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "-1"
|
||||||
|
---
|
||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: infrastructure-apps
|
||||||
|
namespace: argocd
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: infrastructure-apps
|
||||||
|
app.kubernetes.io/part-of: platform
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: default
|
||||||
|
source:
|
||||||
|
repoURL: ssh://git@git.forteapps.net:2222/Forte/launchpad.git
|
||||||
|
targetRevision: HEAD
|
||||||
|
path: infra/overlays/eks-prod
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: default
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
32
_app-of-apps-gke-dev.yaml
Normal file
32
_app-of-apps-gke-dev.yaml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: monitoring
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "-1"
|
||||||
|
---
|
||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: infrastructure-apps
|
||||||
|
namespace: argocd
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: infrastructure-apps
|
||||||
|
app.kubernetes.io/part-of: platform
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: default
|
||||||
|
source:
|
||||||
|
repoURL: ssh://git@git.forteapps.net:2222/Forte/launchpad.git
|
||||||
|
targetRevision: HEAD
|
||||||
|
path: infra/overlays/gke-dev
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: default
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
32
_app-of-apps-gke-prod.yaml
Normal file
32
_app-of-apps-gke-prod.yaml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: monitoring
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "-1"
|
||||||
|
---
|
||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: infrastructure-apps
|
||||||
|
namespace: argocd
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: infrastructure-apps
|
||||||
|
app.kubernetes.io/part-of: platform
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: default
|
||||||
|
source:
|
||||||
|
repoURL: ssh://git@git.forteapps.net:2222/Forte/launchpad.git
|
||||||
|
targetRevision: HEAD
|
||||||
|
path: infra/overlays/gke-prod
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: default
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
@@ -18,7 +18,7 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
project: default
|
project: default
|
||||||
source:
|
source:
|
||||||
repoURL: git@github.com:fortedigital/sturdy-adventure.git
|
repoURL: ssh://git@git.forteapps.net:2222/Forte/launchpad.git
|
||||||
targetRevision: HEAD
|
targetRevision: HEAD
|
||||||
path: infra/overlays/upc-prod
|
path: infra/overlays/upc-prod
|
||||||
destination:
|
destination:
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ spec:
|
|||||||
- $values/infra/values/base/dot-ai-stack-values.yaml
|
- $values/infra/values/base/dot-ai-stack-values.yaml
|
||||||
- $values/infra/values/upc-dev/dot-ai-stack-values.yaml
|
- $values/infra/values/upc-dev/dot-ai-stack-values.yaml
|
||||||
|
|
||||||
- repoURL: git@github.com:fortedigital/sturdy-adventure.git
|
- repoURL: ssh://git@git.forteapps.net:2222/Forte/launchpad.git
|
||||||
targetRevision: HEAD
|
targetRevision: HEAD
|
||||||
ref: values
|
ref: values
|
||||||
|
|
||||||
|
|||||||
@@ -57,17 +57,17 @@ spec:
|
|||||||
- sh
|
- sh
|
||||||
- -c
|
- -c
|
||||||
- |
|
- |
|
||||||
mc alias set upcloud "${S3_ENDPOINT}" "${AWS_ACCESS_KEY_ID}" "${AWS_SECRET_ACCESS_KEY}"
|
mc alias set s3 "${S3_ENDPOINT}" "${AWS_ACCESS_KEY_ID}" "${AWS_SECRET_ACCESS_KEY}"
|
||||||
|
|
||||||
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
|
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
|
||||||
KEY="gitea-dump-${TIMESTAMP}.zip"
|
KEY="gitea-dump-${TIMESTAMP}.zip"
|
||||||
echo "Uploading ${KEY}..."
|
echo "Uploading ${KEY}..."
|
||||||
mc cp /backup/gitea-dump.zip "upcloud/${S3_BUCKET}/${KEY}" && \
|
mc cp /backup/gitea-dump.zip "s3/${S3_BUCKET}/${KEY}" && \
|
||||||
echo "Upload complete."
|
echo "Upload complete."
|
||||||
|
|
||||||
# Prune backups older than 7 days
|
# Prune backups older than 7 days
|
||||||
echo "Pruning backups older than 7 days..."
|
echo "Pruning backups older than 7 days..."
|
||||||
mc rm --older-than 7d --force "upcloud/${S3_BUCKET}/" 2>&1 || true
|
mc rm --older-than 7d --force "s3/${S3_BUCKET}/" 2>&1 || true
|
||||||
echo "Pruning complete."
|
echo "Pruning complete."
|
||||||
envFrom:
|
envFrom:
|
||||||
- secretRef:
|
- secretRef:
|
||||||
|
|||||||
10
clusters/aks-dev.yaml
Normal file
10
clusters/aks-dev.yaml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
clusterName: dev-aks # <- adjust to your AKS cluster name
|
||||||
|
domain: example.com # <- adjust to your domain
|
||||||
|
argocdDomain: argocd.example.com
|
||||||
|
grafanaDomain: grafana.example.com
|
||||||
|
keycloakDomain: id.example.com
|
||||||
|
dotaiDomain: kubemcp.example.com
|
||||||
|
dotaiUiDomain: kubemcpui.example.com
|
||||||
|
letsencryptEmail: admin@example.com # <- adjust
|
||||||
|
trustedIPs: "10.0.0.0/8,168.63.129.16/32" # <- VNet CIDR + Azure health probe
|
||||||
|
cloudProvider: azure
|
||||||
10
clusters/aks-prod.yaml
Normal file
10
clusters/aks-prod.yaml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
clusterName: prod-aks # <- adjust to your AKS cluster name
|
||||||
|
domain: example.com # <- adjust to your domain
|
||||||
|
argocdDomain: argocd.example.com
|
||||||
|
grafanaDomain: grafana.example.com
|
||||||
|
keycloakDomain: id.example.com
|
||||||
|
dotaiDomain: kubemcp.example.com
|
||||||
|
dotaiUiDomain: kubemcpui.example.com
|
||||||
|
letsencryptEmail: admin@example.com # <- adjust
|
||||||
|
trustedIPs: "10.0.0.0/8,168.63.129.16/32" # <- VNet CIDR + Azure health probe
|
||||||
|
cloudProvider: azure
|
||||||
10
clusters/eks-dev.yaml
Normal file
10
clusters/eks-dev.yaml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
clusterName: dev-eks # <- adjust to your EKS cluster name
|
||||||
|
domain: example.com # <- adjust to your domain
|
||||||
|
argocdDomain: argocd.example.com
|
||||||
|
grafanaDomain: grafana.example.com
|
||||||
|
keycloakDomain: id.example.com
|
||||||
|
dotaiDomain: kubemcp.example.com
|
||||||
|
dotaiUiDomain: kubemcpui.example.com
|
||||||
|
letsencryptEmail: admin@example.com # <- adjust
|
||||||
|
trustedIPs: "10.0.0.0/8" # <- adjust to your VPC CIDR
|
||||||
|
cloudProvider: eks
|
||||||
10
clusters/eks-prod.yaml
Normal file
10
clusters/eks-prod.yaml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
clusterName: prod-eks # <- adjust to your EKS cluster name
|
||||||
|
domain: example.com # <- adjust to your domain
|
||||||
|
argocdDomain: argocd.example.com
|
||||||
|
grafanaDomain: grafana.example.com
|
||||||
|
keycloakDomain: id.example.com
|
||||||
|
dotaiDomain: kubemcp.example.com
|
||||||
|
dotaiUiDomain: kubemcpui.example.com
|
||||||
|
letsencryptEmail: admin@example.com # <- adjust
|
||||||
|
trustedIPs: "10.0.0.0/8" # <- adjust to your VPC CIDR
|
||||||
|
cloudProvider: eks
|
||||||
10
clusters/gke-dev.yaml
Normal file
10
clusters/gke-dev.yaml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
clusterName: dev-gke # <- adjust to your GKE cluster name
|
||||||
|
domain: example.com # <- adjust to your domain
|
||||||
|
argocdDomain: argocd.example.com
|
||||||
|
grafanaDomain: grafana.example.com
|
||||||
|
keycloakDomain: id.example.com
|
||||||
|
dotaiDomain: kubemcp.example.com
|
||||||
|
dotaiUiDomain: kubemcpui.example.com
|
||||||
|
letsencryptEmail: admin@example.com # <- adjust
|
||||||
|
trustedIPs: "10.0.0.0/8,35.191.0.0/16,130.211.0.0/22" # <- subnet CIDR + GCP health checks
|
||||||
|
cloudProvider: gke
|
||||||
10
clusters/gke-prod.yaml
Normal file
10
clusters/gke-prod.yaml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
clusterName: prod-gke # <- adjust to your GKE cluster name
|
||||||
|
domain: example.com # <- adjust to your domain
|
||||||
|
argocdDomain: argocd.example.com
|
||||||
|
grafanaDomain: grafana.example.com
|
||||||
|
keycloakDomain: id.example.com
|
||||||
|
dotaiDomain: kubemcp.example.com
|
||||||
|
dotaiUiDomain: kubemcpui.example.com
|
||||||
|
letsencryptEmail: admin@example.com # <- adjust
|
||||||
|
trustedIPs: "10.0.0.0/8,35.191.0.0/16,130.211.0.0/22" # <- subnet CIDR + GCP health checks
|
||||||
|
cloudProvider: gke
|
||||||
@@ -12,11 +12,11 @@
|
|||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
This Kubernetes cluster uses a **GitOps approach** powered by **ArgoCD**, where Git repositories serve as the single source of truth for both infrastructure and application deployments. The cluster is running on **UpCloud Managed Kubernetes** but is designed to be cloud-agnostic.
|
This Kubernetes cluster uses a **GitOps approach** powered by **ArgoCD**, where Git repositories serve as the single source of truth for both infrastructure and application deployments. The cluster setup is **cloud-agnostic**, with ready-to-use configurations for **UpCloud**, **AWS EKS**, **Azure AKS**, and **GCP GKE**.
|
||||||
|
|
||||||
### Key Characteristics
|
### Key Characteristics
|
||||||
- **Environment**: Production (internal use only)
|
- **Environment**: Production (internal use only)
|
||||||
- **Cluster Type**: Multi-cluster (upc-dev, upc-prod) via Kustomize overlays
|
- **Cluster Type**: Multi-cloud, multi-cluster via Kustomize overlays (UpCloud, AWS, Azure, GCP)
|
||||||
- **GitOps Tool**: ArgoCD
|
- **GitOps Tool**: ArgoCD
|
||||||
- **Deployment Pattern**: App-of-Apps
|
- **Deployment Pattern**: App-of-Apps
|
||||||
- **Secret Management**: Sealed Secrets (kubeseal)
|
- **Secret Management**: Sealed Secrets (kubeseal)
|
||||||
@@ -63,7 +63,7 @@ This Kubernetes cluster uses a **GitOps approach** powered by **ArgoCD**, where
|
|||||||
▼
|
▼
|
||||||
┌────────────────────────────────┐
|
┌────────────────────────────────┐
|
||||||
│ Kubernetes Clusters │
|
│ Kubernetes Clusters │
|
||||||
│ (UpCloud: upc-dev, upc-prod) │
|
│ (UpCloud, AWS, Azure, GCP) │
|
||||||
│ │
|
│ │
|
||||||
│ ┌──────────────────────────┐ │
|
│ ┌──────────────────────────┐ │
|
||||||
│ │ ArgoCD │ │
|
│ │ ArgoCD │ │
|
||||||
@@ -131,26 +131,22 @@ launchpad/
|
|||||||
│ │ ├── renovate.yaml
|
│ │ ├── renovate.yaml
|
||||||
│ │ ├── ... # All other Application manifests
|
│ │ ├── ... # All other Application manifests
|
||||||
│ │ └── secrets.yaml
|
│ │ └── secrets.yaml
|
||||||
│ ├── overlays/ # Per-cluster overrides
|
│ ├── overlays/ # Per-cluster Kustomize overrides
|
||||||
│ │ ├── upc-dev/ # UpCloud Dev (uses base as-is)
|
│ │ ├── upc-dev/ # UpCloud Dev (uses base as-is)
|
||||||
│ │ └── upc-prod/ # UpCloud Prod (patches value paths)
|
│ │ ├── upc-prod/ # UpCloud Prod (patches value paths)
|
||||||
|
│ │ ├── eks-dev/ # AWS EKS Dev
|
||||||
|
│ │ ├── eks-prod/ # AWS EKS Prod
|
||||||
|
│ │ ├── aks-dev/ # Azure AKS Dev
|
||||||
|
│ │ ├── aks-prod/ # Azure AKS Prod
|
||||||
|
│ │ ├── gke-dev/ # GCP GKE Dev
|
||||||
|
│ │ └── gke-prod/ # GCP GKE Prod
|
||||||
│ ├── dashboards/ # Grafana dashboard ConfigMaps
|
│ ├── dashboards/ # Grafana dashboard ConfigMaps
|
||||||
│ └── values/ # Helm value overrides for infra
|
│ └── values/ # Helm value overrides for infra
|
||||||
│ ├── base/ # Shared values (all clusters)
|
│ ├── base/ # Cloud-agnostic shared values
|
||||||
│ │ ├── traefik-values.yaml
|
│ ├── upc-{dev,prod}/ # UpCloud: storage class, LB, pricing
|
||||||
│ │ ├── keycloak-values.yaml
|
│ ├── aws-{dev,prod}/ # AWS: gp3, NLB, CUR pricing
|
||||||
│ │ ├── grafana-values.yaml
|
│ ├── aks-{dev,prod}/ # Azure: managed-csi-premium, Standard LB
|
||||||
│ │ ├── prometheus-values.yaml
|
│ └── gcp-{dev,prod}/ # GCP: premium-rwo, L4 LB
|
||||||
│ │ ├── gitea-values.yaml
|
|
||||||
│ │ └── ...
|
|
||||||
│ ├── upc-dev/ # upc-dev cluster-specific values
|
|
||||||
│ │ ├── traefik-values.yaml
|
|
||||||
│ │ ├── keycloak-values.yaml
|
|
||||||
│ │ └── grafana-values.yaml
|
|
||||||
│ └── upc-prod/ # upc-prod cluster-specific values
|
|
||||||
│ ├── traefik-values.yaml
|
|
||||||
│ ├── keycloak-values.yaml
|
|
||||||
│ └── grafana-values.yaml
|
|
||||||
│
|
│
|
||||||
├── apps/ # Business Application ArgoCD manifests (Kustomize)
|
├── apps/ # Business Application ArgoCD manifests (Kustomize)
|
||||||
│ ├── base/ # Base app manifests
|
│ ├── base/ # Base app manifests
|
||||||
@@ -287,7 +283,7 @@ app-repository/
|
|||||||
### The App-of-Apps Pattern
|
### The App-of-Apps Pattern
|
||||||
|
|
||||||
```
|
```
|
||||||
_app-of-apps-{upc-dev,upc-prod}.yaml (Root, per cluster)
|
_app-of-apps-{cluster}.yaml (Root, per cluster — e.g. upc-dev, eks-prod, gke-dev)
|
||||||
│
|
│
|
||||||
├── infrastructure-apps (manages infra/)
|
├── infrastructure-apps (manages infra/)
|
||||||
│ ├── cluster-resources-application
|
│ ├── cluster-resources-application
|
||||||
@@ -377,6 +373,15 @@ patches:
|
|||||||
value: $values/infra/values/upc-prod/traefik-values.yaml
|
value: $values/infra/values/upc-prod/traefik-values.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Cloud-specific values (storage classes, load balancer annotations, cost model) are isolated in per-cluster value files. Base values are fully cloud-agnostic:
|
||||||
|
|
||||||
|
| Cloud | Storage Class | Load Balancer | OpenCost Provider |
|
||||||
|
|-------|--------------|---------------|-------------------|
|
||||||
|
| **UpCloud** | `upcloud-block-storage-maxiops` | UpCloud LB (ProxyProtocol v2) | Custom pricing |
|
||||||
|
| **AWS EKS** | `gp3` (EBS CSI) | NLB (ProxyProtocol v2) | AWS CUR |
|
||||||
|
| **Azure AKS** | `managed-csi-premium` | Standard LB (`externalTrafficPolicy: Local`) | Azure Billing API |
|
||||||
|
| **GCP GKE** | `premium-rwo` (PD CSI) | L4 passthrough NLB | GCP Cloud Billing |
|
||||||
|
|
||||||
**Benefits**:
|
**Benefits**:
|
||||||
- Single source of truth for Application definitions
|
- Single source of truth for Application definitions
|
||||||
- Cluster-specific values isolated per overlay
|
- Cluster-specific values isolated per overlay
|
||||||
@@ -658,6 +663,6 @@ Notifications include:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**Last Updated**: 2026-03-16
|
**Last Updated**: 2026-04-22
|
||||||
**Maintained By**: Platform Team
|
**Maintained By**: Platform Team
|
||||||
**Questions?**: Contact #platform-support on Slack
|
**Questions?**: Contact #platform-support on Slack
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ Bootstrap a new cluster from scratch:
|
|||||||
|
|
||||||
#### Prerequisites
|
#### Prerequisites
|
||||||
|
|
||||||
1. **Kubernetes cluster running** (UpCloud or any K8s cluster)
|
1. **Kubernetes cluster running** (UpCloud, AWS EKS, Azure AKS, GCP GKE, or any K8s cluster)
|
||||||
2. **kubectl configured** with admin access
|
2. **kubectl configured** with admin access
|
||||||
3. **Repositories cloned** locally
|
3. **Repositories cloned** locally
|
||||||
|
|
||||||
@@ -54,11 +54,13 @@ kubectl get nodes
|
|||||||
git clone https://git.forteapps.net/Forte/launchpad
|
git clone https://git.forteapps.net/Forte/launchpad
|
||||||
cd launchpad
|
cd launchpad
|
||||||
|
|
||||||
# 2. Set cluster name (optional)
|
# 2. Run bootstrap script with cluster target
|
||||||
export CLUSTER_NAME="prod-cluster-01"
|
# Available clusters: upc-dev, upc-prod, eks-dev, eks-prod,
|
||||||
|
# aks-dev, aks-prod, gke-dev, gke-prod
|
||||||
|
./bootstrap.sh upc-dev
|
||||||
|
|
||||||
# 3. Run bootstrap script
|
# Cluster config is loaded from clusters/<cluster>.yaml
|
||||||
./bootstrap.sh
|
# (cloudProvider, trustedIPs, domain, etc.)
|
||||||
```
|
```
|
||||||
|
|
||||||
**What Happens:**
|
**What Happens:**
|
||||||
@@ -1262,13 +1264,21 @@ spec:
|
|||||||
|
|
||||||
### Backup Strategy
|
### Backup Strategy
|
||||||
|
|
||||||
**Current State**: No automated backups
|
**Current State**: Gitea daily backups to S3-compatible storage
|
||||||
|
|
||||||
**What Needs Backup**:
|
**What Is Backed Up**:
|
||||||
- ❌ Cluster state (not backed up - recreate via GitOps)
|
- ✅ Gitea repositories + database: Daily CronJob (`cluster-resources/gitea-backup-cronjob.yaml`) uploads to S3-compatible storage with 7-day retention
|
||||||
- ❌ Persistent volumes (currently not critical)
|
- ✅ Git repositories: Full cluster config recoverable from Git
|
||||||
- ✅ Git repositories (Gitea provides backup)
|
- ⚠️ Secrets: Sealed secrets in Git; unseal keys need safekeeping
|
||||||
- ⚠️ Secrets (sealed secrets in Git, unseal keys need safekeeping)
|
|
||||||
|
**What Is NOT Backed Up**:
|
||||||
|
- ❌ Cluster state (recreate via GitOps)
|
||||||
|
- ❌ Other persistent volumes (Prometheus, Loki, Tempo data)
|
||||||
|
|
||||||
|
**Per-cloud backup scripts** (manual restore helpers):
|
||||||
|
- UpCloud/AWS: `scripts/gitea-backup.sh` / `scripts/gitea-backup-eks.sh` (MinIO CLI, S3-compatible)
|
||||||
|
- Azure: `scripts/gitea-backup-aks.sh` (Azure CLI + Blob Storage)
|
||||||
|
- GCP: `scripts/gitea-backup-gke.sh` (gsutil + GCS)
|
||||||
|
|
||||||
### Cluster Rebuild
|
### Cluster Rebuild
|
||||||
|
|
||||||
@@ -1370,6 +1380,9 @@ kubectl get pods -n argocd
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# UpCloud: Upgrade via control panel or CLI
|
# UpCloud: Upgrade via control panel or CLI
|
||||||
|
# AWS EKS: eksctl upgrade cluster / AWS Console
|
||||||
|
# Azure AKS: az aks upgrade / Azure Portal
|
||||||
|
# GCP GKE: gcloud container clusters upgrade / Cloud Console
|
||||||
|
|
||||||
# After upgrade, verify cluster
|
# After upgrade, verify cluster
|
||||||
kubectl version
|
kubectl version
|
||||||
@@ -1507,18 +1520,35 @@ git push
|
|||||||
|
|
||||||
### Multi-Cluster Setup
|
### Multi-Cluster Setup
|
||||||
|
|
||||||
The repository supports multiple clusters via Kustomize overlays:
|
The repository supports multiple clusters across multiple clouds via Kustomize overlays:
|
||||||
|
|
||||||
|
**Active clusters:**
|
||||||
- **upc-dev** (default): `infra/overlays/upc-dev/` — uses base Applications as-is
|
- **upc-dev** (default): `infra/overlays/upc-dev/` — uses base Applications as-is
|
||||||
- **upc-prod**: `infra/overlays/upc-prod/` — patches value file paths from `upc-dev` to `upc-prod`
|
- **upc-prod**: `infra/overlays/upc-prod/` — patches value file paths from `upc-dev` to `upc-prod`
|
||||||
|
|
||||||
Each cluster has its own:
|
**Cloud-ready templates (fill in `clusters/*.yaml` before use):**
|
||||||
- Root app-of-apps file: `_app-of-apps-upc-dev.yaml` / `_app-of-apps-upc-prod.yaml`
|
- **eks-dev** / **eks-prod**: AWS EKS with NLB, gp3 storage, AWS CUR pricing
|
||||||
- Cluster-specific Helm values: `infra/values/upc-dev/` / `infra/values/upc-prod/`
|
- **aks-dev** / **aks-prod**: Azure AKS with Standard LB, managed-csi-premium storage
|
||||||
- Sealed secrets: `secrets/upc-dev/` (others as needed)
|
- **gke-dev** / **gke-prod**: GCP GKE with L4 LB, premium-rwo storage
|
||||||
- Apps overlay: `apps/overlays/upc-dev/` / `apps/overlays/upc-prod/`
|
|
||||||
|
|
||||||
To add a new cluster, create a new overlay directory (e.g., `infra/overlays/upc-staging/`) with patches that swap the value file paths.
|
Each cluster has its own:
|
||||||
|
- Root app-of-apps: `_app-of-apps-{cluster}.yaml`
|
||||||
|
- Cluster config: `clusters/{cluster}.yaml` (domain, trustedIPs, cloudProvider)
|
||||||
|
- Kustomize overlay: `infra/overlays/{cluster}/kustomization.yaml`
|
||||||
|
- Helm value overrides: `infra/values/{cluster}/` (traefik, gitea, opencost)
|
||||||
|
- Sealed secrets: `secrets/{cluster}/` (as needed)
|
||||||
|
- Apps overlay: `apps/overlays/{cluster}/`
|
||||||
|
|
||||||
|
Cloud-specific values handled per-cluster:
|
||||||
|
|
||||||
|
| Concern | UpCloud | AWS EKS | Azure AKS | GCP GKE |
|
||||||
|
|---------|---------|---------|-----------|---------|
|
||||||
|
| **Storage class** | `upcloud-block-storage-maxiops` | `gp3` | `managed-csi-premium` | `premium-rwo` |
|
||||||
|
| **Load balancer** | UpCloud LB + ProxyProtocol v2 | NLB + ProxyProtocol v2 | Standard LB + `externalTrafficPolicy: Local` | L4 passthrough NLB |
|
||||||
|
| **Cost monitoring** | Custom pricing | AWS CUR | Azure Billing API | GCP Cloud Billing |
|
||||||
|
| **Backup storage** | UpCloud S3-compat | AWS S3 (native) | Azure Blob Storage | GCS |
|
||||||
|
|
||||||
|
To add a new cluster, create a new overlay directory (e.g., `infra/overlays/eks-staging/`) with patches that swap the value file paths, and a matching `clusters/eks-staging.yaml`.
|
||||||
|
|
||||||
### Blue-Green Deployments
|
### Blue-Green Deployments
|
||||||
|
|
||||||
@@ -1661,6 +1691,6 @@ echo "Remember to delete: $SECRET_FILE"
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**Last Updated**: 2026-03-16
|
**Last Updated**: 2026-04-22
|
||||||
**Maintained By**: Platform Team
|
**Maintained By**: Platform Team
|
||||||
**Emergency Contact**: #platform-support on Slack
|
**Emergency Contact**: #platform-support on Slack
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ Reference for:
|
|||||||
│
|
│
|
||||||
▼
|
▼
|
||||||
┌──────────────────────────────────────────────────────────────┐
|
┌──────────────────────────────────────────────────────────────┐
|
||||||
│ Kubernetes Clusters (UpCloud: upc-dev, upc-prod) │
|
│ Kubernetes Clusters (UpCloud, AWS, Azure, GCP) │
|
||||||
│ ┌──────────────────────────────────────────────────────┐ │
|
│ ┌──────────────────────────────────────────────────────┐ │
|
||||||
│ │ Infrastructure: Traefik, Cert-Manager, Kyverno │ │
|
│ │ Infrastructure: Traefik, Cert-Manager, Kyverno │ │
|
||||||
│ ├──────────────────────────────────────────────────────┤ │
|
│ ├──────────────────────────────────────────────────────┤ │
|
||||||
@@ -194,7 +194,7 @@ Reference for:
|
|||||||
### Key Technologies
|
### Key Technologies
|
||||||
|
|
||||||
- **GitOps**: ArgoCD
|
- **GitOps**: ArgoCD
|
||||||
- **Kubernetes**: UpCloud Managed Kubernetes (multi-cluster: upc-dev, upc-prod)
|
- **Kubernetes**: Multi-cloud (UpCloud, AWS EKS, Azure AKS, GCP GKE)
|
||||||
- **Ingress**: Traefik v2
|
- **Ingress**: Traefik v2
|
||||||
- **Certificates**: Cert-Manager + Let's Encrypt
|
- **Certificates**: Cert-Manager + Let's Encrypt
|
||||||
- **Policies**: Kyverno
|
- **Policies**: Kyverno
|
||||||
@@ -299,11 +299,16 @@ docs/
|
|||||||
## 🔄 Documentation Versions
|
## 🔄 Documentation Versions
|
||||||
|
|
||||||
**Current Version**: 1.0.0
|
**Current Version**: 1.0.0
|
||||||
**Last Updated**: 2026-03-16
|
**Last Updated**: 2026-04-22
|
||||||
**Maintained By**: Platform Team
|
**Maintained By**: Platform Team
|
||||||
|
|
||||||
### Changelog
|
### Changelog
|
||||||
|
|
||||||
|
- **v1.1.0 (2026-04-22)**: Multi-cloud support
|
||||||
|
- Cloud-agnostic base values (storage, LB, pricing moved to per-cluster overlays)
|
||||||
|
- Added AWS EKS, Azure AKS, GCP GKE configurations
|
||||||
|
- Per-cloud backup scripts
|
||||||
|
- Updated all documentation
|
||||||
- **v1.0.0 (2026-03-16)**: Initial comprehensive documentation release
|
- **v1.0.0 (2026-03-16)**: Initial comprehensive documentation release
|
||||||
- GitOps Architecture guide
|
- GitOps Architecture guide
|
||||||
- Developer Onboarding guide
|
- Developer Onboarding guide
|
||||||
|
|||||||
@@ -19,9 +19,9 @@
|
|||||||
|
|
||||||
| Component | Value |
|
| Component | Value |
|
||||||
|-----------|-------|
|
|-----------|-------|
|
||||||
| **Provider** | UpCloud Managed Kubernetes |
|
| **Provider** | Multi-cloud (UpCloud, AWS EKS, Azure AKS, GCP GKE) |
|
||||||
| **Environment** | Production (internal use) |
|
| **Active clusters** | UpCloud (upc-dev, upc-prod) |
|
||||||
| **Cluster Count** | Multi-cluster (upc-dev, upc-prod) |
|
| **Cloud-ready templates** | EKS, AKS, GKE (dev + prod each) |
|
||||||
| **GitOps Tool** | ArgoCD |
|
| **GitOps Tool** | ArgoCD |
|
||||||
| **Ingress Controller** | Traefik v2 |
|
| **Ingress Controller** | Traefik v2 |
|
||||||
| **Certificate Management** | Cert-Manager + Let's Encrypt |
|
| **Certificate Management** | Cert-Manager + Let's Encrypt |
|
||||||
@@ -42,7 +42,7 @@ Internet
|
|||||||
[DNS: *.forteapps.net]
|
[DNS: *.forteapps.net]
|
||||||
│
|
│
|
||||||
▼
|
▼
|
||||||
[UpCloud LoadBalancer]
|
[Cloud Load Balancer]
|
||||||
│
|
│
|
||||||
▼
|
▼
|
||||||
[Traefik Ingress Controller]
|
[Traefik Ingress Controller]
|
||||||
@@ -1550,14 +1550,22 @@ Recommended resource allocation:
|
|||||||
|
|
||||||
### Storage Classes
|
### Storage Classes
|
||||||
|
|
||||||
Default storage class used: **UpCloud default** (varies by provider)
|
Storage classes are cloud-specific and configured in per-cluster value overrides (`infra/values/{cluster}/gitea-values.yaml`):
|
||||||
|
|
||||||
|
| Cloud | Storage Class | Driver |
|
||||||
|
|-------|--------------|--------|
|
||||||
|
| **UpCloud** | `upcloud-block-storage-maxiops` | UpCloud CSI |
|
||||||
|
| **AWS EKS** | `gp3` | EBS CSI |
|
||||||
|
| **Azure AKS** | `managed-csi-premium` | Azure Disk CSI |
|
||||||
|
| **GCP GKE** | `premium-rwo` | PD CSI |
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
|
# Example: base values omit storageClass (set in per-cluster overlay)
|
||||||
persistence:
|
persistence:
|
||||||
enabled: true
|
enabled: true
|
||||||
storageClass: "" # Uses default
|
|
||||||
accessMode: ReadWriteOnce
|
accessMode: ReadWriteOnce
|
||||||
size: 5Gi
|
size: 5Gi
|
||||||
|
# storageClass set by infra/values/{cluster}/gitea-values.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -1753,6 +1761,6 @@ team: platform
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**Last Updated**: 2026-04-16
|
**Last Updated**: 2026-04-22
|
||||||
**Maintained By**: Platform Team
|
**Maintained By**: Platform Team
|
||||||
**Version**: 1.0.0
|
**Version**: 1.0.0
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ spec:
|
|||||||
releaseName: gitea
|
releaseName: gitea
|
||||||
valueFiles:
|
valueFiles:
|
||||||
- $values/infra/values/base/gitea-values.yaml
|
- $values/infra/values/base/gitea-values.yaml
|
||||||
|
- $values/infra/values/upc-dev/gitea-values.yaml
|
||||||
|
|
||||||
- repoURL: ssh://git@git.forteapps.net:2222/Forte/launchpad.git
|
- repoURL: ssh://git@git.forteapps.net:2222/Forte/launchpad.git
|
||||||
targetRevision: HEAD
|
targetRevision: HEAD
|
||||||
|
|||||||
@@ -22,8 +22,9 @@ spec:
|
|||||||
releaseName: opencost
|
releaseName: opencost
|
||||||
valueFiles:
|
valueFiles:
|
||||||
- $values/infra/values/base/opencost-values.yaml
|
- $values/infra/values/base/opencost-values.yaml
|
||||||
|
- $values/infra/values/upc-dev/opencost-values.yaml
|
||||||
|
|
||||||
- repoURL: git@github.com:fortedigital/sturdy-adventure.git
|
- repoURL: ssh://git@git.forteapps.net:2222/Forte/launchpad.git
|
||||||
targetRevision: HEAD
|
targetRevision: HEAD
|
||||||
ref: values
|
ref: values
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ spec:
|
|||||||
- $values/infra/values/base/traefik-values.yaml
|
- $values/infra/values/base/traefik-values.yaml
|
||||||
- $values/infra/values/upc-dev/traefik-values.yaml
|
- $values/infra/values/upc-dev/traefik-values.yaml
|
||||||
|
|
||||||
- repoURL: git@github.com:fortedigital/sturdy-adventure.git
|
- repoURL: ssh://git@git.forteapps.net:2222/Forte/launchpad.git
|
||||||
targetRevision: HEAD
|
targetRevision: HEAD
|
||||||
ref: values
|
ref: values
|
||||||
|
|
||||||
|
|||||||
68
infra/overlays/aks-dev/kustomization.yaml
Normal file
68
infra/overlays/aks-dev/kustomization.yaml
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
resources:
|
||||||
|
- ../../base
|
||||||
|
|
||||||
|
patches:
|
||||||
|
# Traefik: swap upc-dev → aks-dev
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: traefik
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/sources/0/helm/valueFiles/1
|
||||||
|
value: $values/infra/values/aks-dev/traefik-values.yaml
|
||||||
|
|
||||||
|
# Keycloak: swap upc-dev → aks-dev
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: keycloak
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/sources/0/helm/valueFiles/1
|
||||||
|
value: $values/infra/values/aks-dev/keycloak-values.yaml
|
||||||
|
|
||||||
|
# Grafana: swap upc-dev → aks-dev
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: grafana
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/sources/0/helm/valueFiles/1
|
||||||
|
value: $values/infra/values/aks-dev/grafana-values.yaml
|
||||||
|
|
||||||
|
# Gitea: swap upc-dev → aks-dev
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: gitea
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/sources/0/helm/valueFiles/1
|
||||||
|
value: $values/infra/values/aks-dev/gitea-values.yaml
|
||||||
|
|
||||||
|
# OpenCost: swap upc-dev → aks-dev
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: opencost
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/sources/0/helm/valueFiles/1
|
||||||
|
value: $values/infra/values/aks-dev/opencost-values.yaml
|
||||||
|
|
||||||
|
# Secrets: change path to aks-dev
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: secrets
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/source/path
|
||||||
|
value: secrets/aks-dev
|
||||||
|
|
||||||
|
# Enterprise-apps: point to aks-dev overlay
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: enterprise-apps
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/source/path
|
||||||
|
value: apps/overlays/aks-dev
|
||||||
68
infra/overlays/aks-prod/kustomization.yaml
Normal file
68
infra/overlays/aks-prod/kustomization.yaml
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
resources:
|
||||||
|
- ../../base
|
||||||
|
|
||||||
|
patches:
|
||||||
|
# Traefik: swap upc-dev → aks-prod
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: traefik
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/sources/0/helm/valueFiles/1
|
||||||
|
value: $values/infra/values/aks-prod/traefik-values.yaml
|
||||||
|
|
||||||
|
# Keycloak: swap upc-dev → aks-prod
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: keycloak
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/sources/0/helm/valueFiles/1
|
||||||
|
value: $values/infra/values/aks-prod/keycloak-values.yaml
|
||||||
|
|
||||||
|
# Grafana: swap upc-dev → aks-prod
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: grafana
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/sources/0/helm/valueFiles/1
|
||||||
|
value: $values/infra/values/aks-prod/grafana-values.yaml
|
||||||
|
|
||||||
|
# Gitea: swap upc-dev → aks-prod
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: gitea
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/sources/0/helm/valueFiles/1
|
||||||
|
value: $values/infra/values/aks-prod/gitea-values.yaml
|
||||||
|
|
||||||
|
# OpenCost: swap upc-dev → aks-prod
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: opencost
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/sources/0/helm/valueFiles/1
|
||||||
|
value: $values/infra/values/aks-prod/opencost-values.yaml
|
||||||
|
|
||||||
|
# Secrets: change path to aks-prod
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: secrets
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/source/path
|
||||||
|
value: secrets/aks-prod
|
||||||
|
|
||||||
|
# Enterprise-apps: point to aks-prod overlay
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: enterprise-apps
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/source/path
|
||||||
|
value: apps/overlays/aks-prod
|
||||||
68
infra/overlays/eks-dev/kustomization.yaml
Normal file
68
infra/overlays/eks-dev/kustomization.yaml
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
resources:
|
||||||
|
- ../../base
|
||||||
|
|
||||||
|
patches:
|
||||||
|
# Traefik: swap upc-dev → eks-dev
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: traefik
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/sources/0/helm/valueFiles/1
|
||||||
|
value: $values/infra/values/eks-dev/traefik-values.yaml
|
||||||
|
|
||||||
|
# Keycloak: swap upc-dev → eks-dev
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: keycloak
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/sources/0/helm/valueFiles/1
|
||||||
|
value: $values/infra/values/eks-dev/keycloak-values.yaml
|
||||||
|
|
||||||
|
# Grafana: swap upc-dev → eks-dev
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: grafana
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/sources/0/helm/valueFiles/1
|
||||||
|
value: $values/infra/values/eks-dev/grafana-values.yaml
|
||||||
|
|
||||||
|
# Gitea: swap upc-dev → eks-dev
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: gitea
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/sources/0/helm/valueFiles/1
|
||||||
|
value: $values/infra/values/eks-dev/gitea-values.yaml
|
||||||
|
|
||||||
|
# OpenCost: swap upc-dev → eks-dev
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: opencost
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/sources/0/helm/valueFiles/1
|
||||||
|
value: $values/infra/values/eks-dev/opencost-values.yaml
|
||||||
|
|
||||||
|
# Secrets: change path to eks-dev
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: secrets
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/source/path
|
||||||
|
value: secrets/eks-dev
|
||||||
|
|
||||||
|
# Enterprise-apps: point to eks-dev overlay
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: enterprise-apps
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/source/path
|
||||||
|
value: apps/overlays/eks-dev
|
||||||
68
infra/overlays/eks-prod/kustomization.yaml
Normal file
68
infra/overlays/eks-prod/kustomization.yaml
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
resources:
|
||||||
|
- ../../base
|
||||||
|
|
||||||
|
patches:
|
||||||
|
# Traefik: swap upc-dev → eks-prod
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: traefik
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/sources/0/helm/valueFiles/1
|
||||||
|
value: $values/infra/values/eks-prod/traefik-values.yaml
|
||||||
|
|
||||||
|
# Keycloak: swap upc-dev → eks-prod
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: keycloak
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/sources/0/helm/valueFiles/1
|
||||||
|
value: $values/infra/values/eks-prod/keycloak-values.yaml
|
||||||
|
|
||||||
|
# Grafana: swap upc-dev → eks-prod
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: grafana
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/sources/0/helm/valueFiles/1
|
||||||
|
value: $values/infra/values/eks-prod/grafana-values.yaml
|
||||||
|
|
||||||
|
# Gitea: swap upc-dev → eks-prod
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: gitea
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/sources/0/helm/valueFiles/1
|
||||||
|
value: $values/infra/values/eks-prod/gitea-values.yaml
|
||||||
|
|
||||||
|
# OpenCost: swap upc-dev → eks-prod
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: opencost
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/sources/0/helm/valueFiles/1
|
||||||
|
value: $values/infra/values/eks-prod/opencost-values.yaml
|
||||||
|
|
||||||
|
# Secrets: change path to eks-prod
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: secrets
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/source/path
|
||||||
|
value: secrets/eks-prod
|
||||||
|
|
||||||
|
# Enterprise-apps: point to eks-prod overlay
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: enterprise-apps
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/source/path
|
||||||
|
value: apps/overlays/eks-prod
|
||||||
68
infra/overlays/gke-dev/kustomization.yaml
Normal file
68
infra/overlays/gke-dev/kustomization.yaml
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
resources:
|
||||||
|
- ../../base
|
||||||
|
|
||||||
|
patches:
|
||||||
|
# Traefik: swap upc-dev → gke-dev
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: traefik
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/sources/0/helm/valueFiles/1
|
||||||
|
value: $values/infra/values/gke-dev/traefik-values.yaml
|
||||||
|
|
||||||
|
# Keycloak: swap upc-dev → gke-dev
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: keycloak
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/sources/0/helm/valueFiles/1
|
||||||
|
value: $values/infra/values/gke-dev/keycloak-values.yaml
|
||||||
|
|
||||||
|
# Grafana: swap upc-dev → gke-dev
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: grafana
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/sources/0/helm/valueFiles/1
|
||||||
|
value: $values/infra/values/gke-dev/grafana-values.yaml
|
||||||
|
|
||||||
|
# Gitea: swap upc-dev → gke-dev
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: gitea
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/sources/0/helm/valueFiles/1
|
||||||
|
value: $values/infra/values/gke-dev/gitea-values.yaml
|
||||||
|
|
||||||
|
# OpenCost: swap upc-dev → gke-dev
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: opencost
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/sources/0/helm/valueFiles/1
|
||||||
|
value: $values/infra/values/gke-dev/opencost-values.yaml
|
||||||
|
|
||||||
|
# Secrets: change path to gke-dev
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: secrets
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/source/path
|
||||||
|
value: secrets/gke-dev
|
||||||
|
|
||||||
|
# Enterprise-apps: point to gke-dev overlay
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: enterprise-apps
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/source/path
|
||||||
|
value: apps/overlays/gke-dev
|
||||||
68
infra/overlays/gke-prod/kustomization.yaml
Normal file
68
infra/overlays/gke-prod/kustomization.yaml
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
resources:
|
||||||
|
- ../../base
|
||||||
|
|
||||||
|
patches:
|
||||||
|
# Traefik: swap upc-dev → gke-prod
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: traefik
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/sources/0/helm/valueFiles/1
|
||||||
|
value: $values/infra/values/gke-prod/traefik-values.yaml
|
||||||
|
|
||||||
|
# Keycloak: swap upc-dev → gke-prod
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: keycloak
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/sources/0/helm/valueFiles/1
|
||||||
|
value: $values/infra/values/gke-prod/keycloak-values.yaml
|
||||||
|
|
||||||
|
# Grafana: swap upc-dev → gke-prod
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: grafana
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/sources/0/helm/valueFiles/1
|
||||||
|
value: $values/infra/values/gke-prod/grafana-values.yaml
|
||||||
|
|
||||||
|
# Gitea: swap upc-dev → gke-prod
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: gitea
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/sources/0/helm/valueFiles/1
|
||||||
|
value: $values/infra/values/gke-prod/gitea-values.yaml
|
||||||
|
|
||||||
|
# OpenCost: swap upc-dev → gke-prod
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: opencost
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/sources/0/helm/valueFiles/1
|
||||||
|
value: $values/infra/values/gke-prod/opencost-values.yaml
|
||||||
|
|
||||||
|
# Secrets: change path to gke-prod
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: secrets
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/source/path
|
||||||
|
value: secrets/gke-prod
|
||||||
|
|
||||||
|
# Enterprise-apps: point to gke-prod overlay
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: enterprise-apps
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/source/path
|
||||||
|
value: apps/overlays/gke-prod
|
||||||
@@ -48,3 +48,21 @@ patches:
|
|||||||
- op: replace
|
- op: replace
|
||||||
path: /spec/source/path
|
path: /spec/source/path
|
||||||
value: apps/overlays/upc-prod
|
value: apps/overlays/upc-prod
|
||||||
|
|
||||||
|
# Gitea: swap upc-dev → upc-prod
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: gitea
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/sources/0/helm/valueFiles/1
|
||||||
|
value: $values/infra/values/upc-prod/gitea-values.yaml
|
||||||
|
|
||||||
|
# OpenCost: swap upc-dev → upc-prod
|
||||||
|
- target:
|
||||||
|
kind: Application
|
||||||
|
name: opencost
|
||||||
|
patch: |
|
||||||
|
- op: replace
|
||||||
|
path: /spec/sources/0/helm/valueFiles/1
|
||||||
|
value: $values/infra/values/upc-prod/opencost-values.yaml
|
||||||
|
|||||||
7
infra/values/aks-dev/gitea-values.yaml
Normal file
7
infra/values/aks-dev/gitea-values.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# AKS-specific: Azure managed disk storage class
|
||||||
|
persistence:
|
||||||
|
storageClass: managed-csi-premium
|
||||||
|
postgresql:
|
||||||
|
primary:
|
||||||
|
persistence:
|
||||||
|
storageClass: managed-csi-premium
|
||||||
4
infra/values/aks-dev/grafana-values.yaml
Normal file
4
infra/values/aks-dev/grafana-values.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# AKS-specific: Grafana hostname
|
||||||
|
ingress:
|
||||||
|
hosts:
|
||||||
|
- grafana.forteapps.net
|
||||||
3
infra/values/aks-dev/keycloak-values.yaml
Normal file
3
infra/values/aks-dev/keycloak-values.yaml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# AKS-specific: Keycloak hostname
|
||||||
|
ingress:
|
||||||
|
hostname: id.forteapps.net
|
||||||
8
infra/values/aks-dev/opencost-values.yaml
Normal file
8
infra/values/aks-dev/opencost-values.yaml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# AKS-specific: Azure pricing via Cloud Billing API
|
||||||
|
opencost:
|
||||||
|
exporter:
|
||||||
|
cloudProviderApiKey: ""
|
||||||
|
customPricing:
|
||||||
|
enabled: false
|
||||||
|
azure:
|
||||||
|
secretName: opencost-azure-billing
|
||||||
11
infra/values/aks-dev/traefik-values.yaml
Normal file
11
infra/values/aks-dev/traefik-values.yaml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# AKS-specific: Azure Load Balancer for Traefik
|
||||||
|
service:
|
||||||
|
annotations:
|
||||||
|
service.beta.kubernetes.io/azure-load-balancer-health-probe-request-path: /ping
|
||||||
|
ports:
|
||||||
|
web:
|
||||||
|
forwardedHeaders:
|
||||||
|
trustedIPs: "10.0.0.0/8"
|
||||||
|
websecure:
|
||||||
|
forwardedHeaders:
|
||||||
|
trustedIPs: "10.0.0.0/8"
|
||||||
7
infra/values/aks-prod/gitea-values.yaml
Normal file
7
infra/values/aks-prod/gitea-values.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# AKS-specific: Azure managed disk storage class (prod)
|
||||||
|
persistence:
|
||||||
|
storageClass: managed-csi-premium
|
||||||
|
postgresql:
|
||||||
|
primary:
|
||||||
|
persistence:
|
||||||
|
storageClass: managed-csi-premium
|
||||||
4
infra/values/aks-prod/grafana-values.yaml
Normal file
4
infra/values/aks-prod/grafana-values.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# AKS-specific: Grafana hostname (prod)
|
||||||
|
ingress:
|
||||||
|
hosts:
|
||||||
|
- grafana.fortedigital.com
|
||||||
3
infra/values/aks-prod/keycloak-values.yaml
Normal file
3
infra/values/aks-prod/keycloak-values.yaml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# AKS-specific: Keycloak hostname (prod)
|
||||||
|
ingress:
|
||||||
|
hostname: id.fortedigital.com
|
||||||
8
infra/values/aks-prod/opencost-values.yaml
Normal file
8
infra/values/aks-prod/opencost-values.yaml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# AKS-specific: Azure pricing via Cloud Billing API (prod)
|
||||||
|
opencost:
|
||||||
|
exporter:
|
||||||
|
cloudProviderApiKey: ""
|
||||||
|
customPricing:
|
||||||
|
enabled: false
|
||||||
|
azure:
|
||||||
|
secretName: opencost-azure-billing
|
||||||
12
infra/values/aks-prod/traefik-values.yaml
Normal file
12
infra/values/aks-prod/traefik-values.yaml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# AKS-specific: Azure Load Balancer for Traefik (prod)
|
||||||
|
service:
|
||||||
|
annotations:
|
||||||
|
service.beta.kubernetes.io/azure-load-balancer-health-probe-request-path: /ping
|
||||||
|
service.beta.kubernetes.io/azure-load-balancer-internal: "false"
|
||||||
|
ports:
|
||||||
|
web:
|
||||||
|
forwardedHeaders:
|
||||||
|
trustedIPs: "10.0.0.0/8"
|
||||||
|
websecure:
|
||||||
|
forwardedHeaders:
|
||||||
|
trustedIPs: "10.0.0.0/8"
|
||||||
@@ -130,7 +130,6 @@ persistence:
|
|||||||
size: 10Gi
|
size: 10Gi
|
||||||
accessModes:
|
accessModes:
|
||||||
- ReadWriteOnce
|
- ReadWriteOnce
|
||||||
storageClass: upcloud-block-storage-maxiops
|
|
||||||
|
|
||||||
# -- Recreate strategy to avoid Multi-Attach errors with RWO volumes
|
# -- Recreate strategy to avoid Multi-Attach errors with RWO volumes
|
||||||
strategy:
|
strategy:
|
||||||
@@ -156,7 +155,6 @@ postgresql:
|
|||||||
persistence:
|
persistence:
|
||||||
enabled: true
|
enabled: true
|
||||||
size: 8Gi
|
size: 8Gi
|
||||||
storageClass: upcloud-block-storage-maxiops
|
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
cpu: 100m
|
cpu: 100m
|
||||||
|
|||||||
@@ -10,18 +10,8 @@ opencost:
|
|||||||
serviceName: prometheus-server
|
serviceName: prometheus-server
|
||||||
namespaceName: monitoring
|
namespaceName: monitoring
|
||||||
port: 80
|
port: 80
|
||||||
customPricing:
|
# Cloud-specific pricing is in per-cluster value overrides
|
||||||
enabled: true
|
# (e.g. infra/values/upc-dev/opencost-values.yaml)
|
||||||
provider: custom
|
|
||||||
costModel:
|
|
||||||
description: "UpCloud 4-node cluster pricing"
|
|
||||||
CPU: "5.86"
|
|
||||||
RAM: "1.46"
|
|
||||||
GPU: "0"
|
|
||||||
storage: "0.34"
|
|
||||||
zoneNetworkEgress: "0"
|
|
||||||
regionNetworkEgress: "0"
|
|
||||||
internetNetworkEgress: "0"
|
|
||||||
ui:
|
ui:
|
||||||
enabled: false
|
enabled: false
|
||||||
service:
|
service:
|
||||||
|
|||||||
7
infra/values/eks-dev/gitea-values.yaml
Normal file
7
infra/values/eks-dev/gitea-values.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# EKS-specific: gp3 storage class
|
||||||
|
persistence:
|
||||||
|
storageClass: gp3
|
||||||
|
postgresql:
|
||||||
|
primary:
|
||||||
|
persistence:
|
||||||
|
storageClass: gp3
|
||||||
4
infra/values/eks-dev/grafana-values.yaml
Normal file
4
infra/values/eks-dev/grafana-values.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# EKS-specific: Grafana hostname
|
||||||
|
ingress:
|
||||||
|
hosts:
|
||||||
|
- grafana.forteapps.net
|
||||||
3
infra/values/eks-dev/keycloak-values.yaml
Normal file
3
infra/values/eks-dev/keycloak-values.yaml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# EKS-specific: Keycloak hostname
|
||||||
|
ingress:
|
||||||
|
hostname: id.forteapps.net
|
||||||
11
infra/values/eks-dev/opencost-values.yaml
Normal file
11
infra/values/eks-dev/opencost-values.yaml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# EKS-specific: AWS pricing via Cost and Usage Report
|
||||||
|
opencost:
|
||||||
|
exporter:
|
||||||
|
cloudProviderApiKey: ""
|
||||||
|
customPricing:
|
||||||
|
enabled: false
|
||||||
|
aws:
|
||||||
|
spot_data_region: ""
|
||||||
|
spot_data_bucket: ""
|
||||||
|
spot_data_prefix: ""
|
||||||
|
account_id: ""
|
||||||
17
infra/values/eks-dev/traefik-values.yaml
Normal file
17
infra/values/eks-dev/traefik-values.yaml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# EKS-specific: AWS NLB for Traefik
|
||||||
|
service:
|
||||||
|
annotations:
|
||||||
|
service.beta.kubernetes.io/aws-load-balancer-type: nlb
|
||||||
|
service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
|
||||||
|
service.beta.kubernetes.io/aws-load-balancer-proxy-protocol: "*"
|
||||||
|
ports:
|
||||||
|
web:
|
||||||
|
proxyProtocol:
|
||||||
|
trustedIPs: "10.0.0.0/8"
|
||||||
|
forwardedHeaders:
|
||||||
|
trustedIPs: "10.0.0.0/8"
|
||||||
|
websecure:
|
||||||
|
proxyProtocol:
|
||||||
|
trustedIPs: "10.0.0.0/8"
|
||||||
|
forwardedHeaders:
|
||||||
|
trustedIPs: "10.0.0.0/8"
|
||||||
7
infra/values/eks-prod/gitea-values.yaml
Normal file
7
infra/values/eks-prod/gitea-values.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# EKS-specific: gp3 storage class (prod)
|
||||||
|
persistence:
|
||||||
|
storageClass: gp3
|
||||||
|
postgresql:
|
||||||
|
primary:
|
||||||
|
persistence:
|
||||||
|
storageClass: gp3
|
||||||
4
infra/values/eks-prod/grafana-values.yaml
Normal file
4
infra/values/eks-prod/grafana-values.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# EKS-specific: Grafana hostname (prod)
|
||||||
|
ingress:
|
||||||
|
hosts:
|
||||||
|
- grafana.fortedigital.com
|
||||||
3
infra/values/eks-prod/keycloak-values.yaml
Normal file
3
infra/values/eks-prod/keycloak-values.yaml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# EKS-specific: Keycloak hostname (prod)
|
||||||
|
ingress:
|
||||||
|
hostname: id.fortedigital.com
|
||||||
11
infra/values/eks-prod/opencost-values.yaml
Normal file
11
infra/values/eks-prod/opencost-values.yaml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# EKS-specific: AWS pricing via Cost and Usage Report (prod)
|
||||||
|
opencost:
|
||||||
|
exporter:
|
||||||
|
cloudProviderApiKey: ""
|
||||||
|
customPricing:
|
||||||
|
enabled: false
|
||||||
|
aws:
|
||||||
|
spot_data_region: ""
|
||||||
|
spot_data_bucket: ""
|
||||||
|
spot_data_prefix: ""
|
||||||
|
account_id: ""
|
||||||
18
infra/values/eks-prod/traefik-values.yaml
Normal file
18
infra/values/eks-prod/traefik-values.yaml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# EKS-specific: AWS NLB for Traefik (prod)
|
||||||
|
service:
|
||||||
|
annotations:
|
||||||
|
service.beta.kubernetes.io/aws-load-balancer-type: nlb
|
||||||
|
service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
|
||||||
|
service.beta.kubernetes.io/aws-load-balancer-proxy-protocol: "*"
|
||||||
|
service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true"
|
||||||
|
ports:
|
||||||
|
web:
|
||||||
|
proxyProtocol:
|
||||||
|
trustedIPs: "10.0.0.0/8"
|
||||||
|
forwardedHeaders:
|
||||||
|
trustedIPs: "10.0.0.0/8"
|
||||||
|
websecure:
|
||||||
|
proxyProtocol:
|
||||||
|
trustedIPs: "10.0.0.0/8"
|
||||||
|
forwardedHeaders:
|
||||||
|
trustedIPs: "10.0.0.0/8"
|
||||||
7
infra/values/gke-dev/gitea-values.yaml
Normal file
7
infra/values/gke-dev/gitea-values.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# GKE-specific: SSD persistent disk storage class
|
||||||
|
persistence:
|
||||||
|
storageClass: premium-rwo
|
||||||
|
postgresql:
|
||||||
|
primary:
|
||||||
|
persistence:
|
||||||
|
storageClass: premium-rwo
|
||||||
4
infra/values/gke-dev/grafana-values.yaml
Normal file
4
infra/values/gke-dev/grafana-values.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# GKE-specific: Grafana hostname
|
||||||
|
ingress:
|
||||||
|
hosts:
|
||||||
|
- grafana.forteapps.net
|
||||||
3
infra/values/gke-dev/keycloak-values.yaml
Normal file
3
infra/values/gke-dev/keycloak-values.yaml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# GKE-specific: Keycloak hostname
|
||||||
|
ingress:
|
||||||
|
hostname: id.forteapps.net
|
||||||
10
infra/values/gke-dev/opencost-values.yaml
Normal file
10
infra/values/gke-dev/opencost-values.yaml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# GKE-specific: GCP pricing via BigQuery billing export
|
||||||
|
opencost:
|
||||||
|
exporter:
|
||||||
|
cloudProviderApiKey: ""
|
||||||
|
customPricing:
|
||||||
|
enabled: false
|
||||||
|
google:
|
||||||
|
key: ""
|
||||||
|
project_id: ""
|
||||||
|
billing_account: ""
|
||||||
12
infra/values/gke-dev/traefik-values.yaml
Normal file
12
infra/values/gke-dev/traefik-values.yaml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# GKE-specific: Google Cloud Load Balancer for Traefik
|
||||||
|
service:
|
||||||
|
annotations:
|
||||||
|
cloud.google.com/neg: '{"ingress":true}'
|
||||||
|
networking.gke.io/load-balancer-type: External
|
||||||
|
ports:
|
||||||
|
web:
|
||||||
|
forwardedHeaders:
|
||||||
|
trustedIPs: "10.0.0.0/8"
|
||||||
|
websecure:
|
||||||
|
forwardedHeaders:
|
||||||
|
trustedIPs: "10.0.0.0/8"
|
||||||
7
infra/values/gke-prod/gitea-values.yaml
Normal file
7
infra/values/gke-prod/gitea-values.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# GKE-specific: SSD persistent disk storage class (prod)
|
||||||
|
persistence:
|
||||||
|
storageClass: premium-rwo
|
||||||
|
postgresql:
|
||||||
|
primary:
|
||||||
|
persistence:
|
||||||
|
storageClass: premium-rwo
|
||||||
4
infra/values/gke-prod/grafana-values.yaml
Normal file
4
infra/values/gke-prod/grafana-values.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# GKE-specific: Grafana hostname (prod)
|
||||||
|
ingress:
|
||||||
|
hosts:
|
||||||
|
- grafana.fortedigital.com
|
||||||
3
infra/values/gke-prod/keycloak-values.yaml
Normal file
3
infra/values/gke-prod/keycloak-values.yaml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# GKE-specific: Keycloak hostname (prod)
|
||||||
|
ingress:
|
||||||
|
hostname: id.fortedigital.com
|
||||||
10
infra/values/gke-prod/opencost-values.yaml
Normal file
10
infra/values/gke-prod/opencost-values.yaml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# GKE-specific: GCP pricing via BigQuery billing export (prod)
|
||||||
|
opencost:
|
||||||
|
exporter:
|
||||||
|
cloudProviderApiKey: ""
|
||||||
|
customPricing:
|
||||||
|
enabled: false
|
||||||
|
google:
|
||||||
|
key: ""
|
||||||
|
project_id: ""
|
||||||
|
billing_account: ""
|
||||||
12
infra/values/gke-prod/traefik-values.yaml
Normal file
12
infra/values/gke-prod/traefik-values.yaml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# GKE-specific: Google Cloud Load Balancer for Traefik (prod)
|
||||||
|
service:
|
||||||
|
annotations:
|
||||||
|
cloud.google.com/neg: '{"ingress":true}'
|
||||||
|
networking.gke.io/load-balancer-type: External
|
||||||
|
ports:
|
||||||
|
web:
|
||||||
|
forwardedHeaders:
|
||||||
|
trustedIPs: "10.0.0.0/8"
|
||||||
|
websecure:
|
||||||
|
forwardedHeaders:
|
||||||
|
trustedIPs: "10.0.0.0/8"
|
||||||
7
infra/values/upc-dev/gitea-values.yaml
Normal file
7
infra/values/upc-dev/gitea-values.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# UpCloud storage class for Gitea and its embedded PostgreSQL
|
||||||
|
persistence:
|
||||||
|
storageClass: upcloud-block-storage-maxiops
|
||||||
|
postgresql:
|
||||||
|
primary:
|
||||||
|
persistence:
|
||||||
|
storageClass: upcloud-block-storage-maxiops
|
||||||
15
infra/values/upc-dev/opencost-values.yaml
Normal file
15
infra/values/upc-dev/opencost-values.yaml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# UpCloud custom pricing (no native OpenCost integration)
|
||||||
|
opencost:
|
||||||
|
exporter:
|
||||||
|
customPricing:
|
||||||
|
enabled: true
|
||||||
|
provider: custom
|
||||||
|
costModel:
|
||||||
|
description: "UpCloud 4-node cluster pricing"
|
||||||
|
CPU: "5.86"
|
||||||
|
RAM: "1.46"
|
||||||
|
GPU: "0"
|
||||||
|
storage: "0.34"
|
||||||
|
zoneNetworkEgress: "0"
|
||||||
|
regionNetworkEgress: "0"
|
||||||
|
internetNetworkEgress: "0"
|
||||||
7
infra/values/upc-prod/gitea-values.yaml
Normal file
7
infra/values/upc-prod/gitea-values.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# UpCloud storage class for Gitea and its embedded PostgreSQL
|
||||||
|
persistence:
|
||||||
|
storageClass: upcloud-block-storage-maxiops
|
||||||
|
postgresql:
|
||||||
|
primary:
|
||||||
|
persistence:
|
||||||
|
storageClass: upcloud-block-storage-maxiops
|
||||||
15
infra/values/upc-prod/opencost-values.yaml
Normal file
15
infra/values/upc-prod/opencost-values.yaml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# UpCloud custom pricing (no native OpenCost integration)
|
||||||
|
opencost:
|
||||||
|
exporter:
|
||||||
|
customPricing:
|
||||||
|
enabled: true
|
||||||
|
provider: custom
|
||||||
|
costModel:
|
||||||
|
description: "UpCloud 4-node cluster pricing"
|
||||||
|
CPU: "5.86"
|
||||||
|
RAM: "1.46"
|
||||||
|
GPU: "0"
|
||||||
|
storage: "0.34"
|
||||||
|
zoneNetworkEgress: "0"
|
||||||
|
regionNetworkEgress: "0"
|
||||||
|
internetNetworkEgress: "0"
|
||||||
100
scripts/gitea-backup-aks.sh
Normal file
100
scripts/gitea-backup-aks.sh
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Gitea backup helper for Azure Blob Storage
|
||||||
|
# Uses the gitea-backup-aks secret in the gitea namespace
|
||||||
|
# Required secret keys:
|
||||||
|
# AZURE_STORAGE_ACCOUNT — storage account name
|
||||||
|
# AZURE_STORAGE_KEY — storage account key
|
||||||
|
# AZURE_CONTAINER — blob container name
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# ./scripts/gitea-backup-aks.sh list # list all backups
|
||||||
|
# ./scripts/gitea-backup-aks.sh download <filename> # download a backup
|
||||||
|
# ./scripts/gitea-backup-aks.sh download latest # download the most recent backup
|
||||||
|
|
||||||
|
NAMESPACE="gitea"
|
||||||
|
SECRET="gitea-backup-aks"
|
||||||
|
IMAGE="mcr.microsoft.com/azure-cli:latest"
|
||||||
|
POD_NAME="gitea-backup-helper"
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
kubectl -n "$NAMESPACE" delete pod "$POD_NAME" --ignore-not-found --grace-period=0 > /dev/null 2>&1 || true
|
||||||
|
}
|
||||||
|
|
||||||
|
az_run() {
|
||||||
|
cleanup
|
||||||
|
kubectl -n "$NAMESPACE" run "$POD_NAME" --restart=Never \
|
||||||
|
--image="$IMAGE" \
|
||||||
|
--overrides="{
|
||||||
|
\"spec\":{\"containers\":[{
|
||||||
|
\"name\":\"$POD_NAME\",
|
||||||
|
\"image\":\"$IMAGE\",
|
||||||
|
\"env\":[{\"name\":\"HOME\",\"value\":\"/tmp\"}],
|
||||||
|
\"command\":[\"sh\",\"-c\",\"$1\"],
|
||||||
|
\"envFrom\":[{\"secretRef\":{\"name\":\"$SECRET\"}}]
|
||||||
|
}]}
|
||||||
|
}" > /dev/null 2>&1
|
||||||
|
|
||||||
|
kubectl -n "$NAMESPACE" wait --for=jsonpath='{.status.phase}'=Succeeded "pod/$POD_NAME" --timeout=120s > /dev/null 2>&1
|
||||||
|
kubectl -n "$NAMESPACE" logs "$POD_NAME"
|
||||||
|
cleanup
|
||||||
|
}
|
||||||
|
|
||||||
|
case "${1:-help}" in
|
||||||
|
list)
|
||||||
|
echo "Listing backups..."
|
||||||
|
az_run 'az storage blob list --account-name ${AZURE_STORAGE_ACCOUNT} --account-key ${AZURE_STORAGE_KEY} --container-name ${AZURE_CONTAINER} --output table --query "[].{Name:name, Size:properties.contentLength, Modified:properties.lastModified}"'
|
||||||
|
;;
|
||||||
|
|
||||||
|
download)
|
||||||
|
FILE="${2:?Usage: $0 download <filename|latest>}"
|
||||||
|
|
||||||
|
if [ "$FILE" = "latest" ]; then
|
||||||
|
echo "Finding latest backup..."
|
||||||
|
FILE=$(az_run 'az storage blob list --account-name ${AZURE_STORAGE_ACCOUNT} --account-key ${AZURE_STORAGE_KEY} --container-name ${AZURE_CONTAINER} --query "sort_by([], &properties.lastModified)[-1].name" -o tsv' | tr -d '[:space:]')
|
||||||
|
if [ -z "$FILE" ]; then
|
||||||
|
echo "No backups found."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Latest: $FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Downloading $FILE..."
|
||||||
|
cleanup
|
||||||
|
kubectl -n "$NAMESPACE" run "$POD_NAME" --restart=Never \
|
||||||
|
--image="$IMAGE" \
|
||||||
|
--overrides="{
|
||||||
|
\"spec\":{\"containers\":[{
|
||||||
|
\"name\":\"$POD_NAME\",
|
||||||
|
\"image\":\"$IMAGE\",
|
||||||
|
\"env\":[{\"name\":\"HOME\",\"value\":\"/tmp\"}],
|
||||||
|
\"command\":[\"sh\",\"-c\",\"sleep 300\"],
|
||||||
|
\"envFrom\":[{\"secretRef\":{\"name\":\"$SECRET\"}}]
|
||||||
|
}]}
|
||||||
|
}" > /dev/null 2>&1
|
||||||
|
|
||||||
|
kubectl -n "$NAMESPACE" wait --for=condition=Ready "pod/$POD_NAME" --timeout=60s > /dev/null 2>&1
|
||||||
|
|
||||||
|
echo "Saving to ./$FILE ..."
|
||||||
|
kubectl -n "$NAMESPACE" exec "$POD_NAME" -- \
|
||||||
|
az storage blob download \
|
||||||
|
--account-name "\${AZURE_STORAGE_ACCOUNT}" \
|
||||||
|
--account-key "\${AZURE_STORAGE_KEY}" \
|
||||||
|
--container-name "\${AZURE_CONTAINER}" \
|
||||||
|
--name "$FILE" \
|
||||||
|
--file /dev/stdout 2>/dev/null > "./$FILE"
|
||||||
|
cleanup
|
||||||
|
|
||||||
|
echo "Downloaded: ./$FILE"
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
echo "Gitea backup helper (Azure Blob Storage)"
|
||||||
|
echo ""
|
||||||
|
echo "Usage:"
|
||||||
|
echo " $0 list List all backups in Azure Blob"
|
||||||
|
echo " $0 download <filename> Download a specific backup"
|
||||||
|
echo " $0 download latest Download the most recent backup"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
94
scripts/gitea-backup-eks.sh
Normal file
94
scripts/gitea-backup-eks.sh
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Gitea backup helper for AWS S3
|
||||||
|
# Uses the gitea-backup-s3 secret in the gitea namespace
|
||||||
|
# (same secret schema: S3_ENDPOINT, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, S3_BUCKET)
|
||||||
|
#
|
||||||
|
# For AWS, S3_ENDPOINT is typically https://s3.<region>.amazonaws.com
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# ./scripts/gitea-backup-eks.sh list # list all backups
|
||||||
|
# ./scripts/gitea-backup-eks.sh download <filename> # download a backup to current dir
|
||||||
|
# ./scripts/gitea-backup-eks.sh download latest # download the most recent backup
|
||||||
|
|
||||||
|
NAMESPACE="gitea"
|
||||||
|
SECRET="gitea-backup-s3"
|
||||||
|
IMAGE="minio/mc:latest"
|
||||||
|
POD_NAME="gitea-backup-helper"
|
||||||
|
ALIAS_CMD='mc alias set s3 ${S3_ENDPOINT} ${AWS_ACCESS_KEY_ID} ${AWS_SECRET_ACCESS_KEY} > /dev/null'
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
kubectl -n "$NAMESPACE" delete pod "$POD_NAME" --ignore-not-found --grace-period=0 > /dev/null 2>&1 || true
|
||||||
|
}
|
||||||
|
|
||||||
|
mc_run() {
|
||||||
|
cleanup
|
||||||
|
kubectl -n "$NAMESPACE" run "$POD_NAME" --restart=Never \
|
||||||
|
--image="$IMAGE" \
|
||||||
|
--overrides="{
|
||||||
|
\"spec\":{\"containers\":[{
|
||||||
|
\"name\":\"$POD_NAME\",
|
||||||
|
\"image\":\"$IMAGE\",
|
||||||
|
\"env\":[{\"name\":\"HOME\",\"value\":\"/tmp\"}],
|
||||||
|
\"command\":[\"sh\",\"-c\",\"${ALIAS_CMD}; $1\"],
|
||||||
|
\"envFrom\":[{\"secretRef\":{\"name\":\"$SECRET\"}}]
|
||||||
|
}]}
|
||||||
|
}" > /dev/null 2>&1
|
||||||
|
|
||||||
|
kubectl -n "$NAMESPACE" wait --for=jsonpath='{.status.phase}'=Succeeded "pod/$POD_NAME" --timeout=120s > /dev/null 2>&1
|
||||||
|
kubectl -n "$NAMESPACE" logs "$POD_NAME"
|
||||||
|
cleanup
|
||||||
|
}
|
||||||
|
|
||||||
|
case "${1:-help}" in
|
||||||
|
list)
|
||||||
|
echo "Listing backups..."
|
||||||
|
mc_run 'mc ls s3/${S3_BUCKET}/'
|
||||||
|
;;
|
||||||
|
|
||||||
|
download)
|
||||||
|
FILE="${2:?Usage: $0 download <filename|latest>}"
|
||||||
|
|
||||||
|
if [ "$FILE" = "latest" ]; then
|
||||||
|
echo "Finding latest backup..."
|
||||||
|
FILE=$(mc_run 'mc ls s3/${S3_BUCKET}/' | sort | tail -1 | awk '{print $NF}' | tr -d '[:space:]')
|
||||||
|
if [ -z "$FILE" ]; then
|
||||||
|
echo "No backups found."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Latest: $FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Downloading $FILE..."
|
||||||
|
cleanup
|
||||||
|
kubectl -n "$NAMESPACE" run "$POD_NAME" --restart=Never \
|
||||||
|
--image="$IMAGE" \
|
||||||
|
--overrides="{
|
||||||
|
\"spec\":{\"containers\":[{
|
||||||
|
\"name\":\"$POD_NAME\",
|
||||||
|
\"image\":\"$IMAGE\",
|
||||||
|
\"env\":[{\"name\":\"HOME\",\"value\":\"/tmp\"}],
|
||||||
|
\"command\":[\"sh\",\"-c\",\"sleep 300\"],
|
||||||
|
\"envFrom\":[{\"secretRef\":{\"name\":\"$SECRET\"}}]
|
||||||
|
}]}
|
||||||
|
}" > /dev/null 2>&1
|
||||||
|
|
||||||
|
kubectl -n "$NAMESPACE" wait --for=condition=Ready "pod/$POD_NAME" --timeout=60s > /dev/null 2>&1
|
||||||
|
|
||||||
|
echo "Saving to ./$FILE ..."
|
||||||
|
kubectl -n "$NAMESPACE" exec "$POD_NAME" -- sh -c "${ALIAS_CMD} && mc cat s3/\${S3_BUCKET}/$FILE" > "./$FILE"
|
||||||
|
cleanup
|
||||||
|
|
||||||
|
echo "Downloaded: ./$FILE"
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
echo "Gitea backup helper (AWS S3)"
|
||||||
|
echo ""
|
||||||
|
echo "Usage:"
|
||||||
|
echo " $0 list List all backups in S3"
|
||||||
|
echo " $0 download <filename> Download a specific backup"
|
||||||
|
echo " $0 download latest Download the most recent backup"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
95
scripts/gitea-backup-gke.sh
Normal file
95
scripts/gitea-backup-gke.sh
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Gitea backup helper for Google Cloud Storage
|
||||||
|
# Uses the gitea-backup-gcs secret in the gitea namespace
|
||||||
|
# Required secret keys:
|
||||||
|
# GCS_BUCKET — bucket name (without gs:// prefix)
|
||||||
|
# GOOGLE_APPLICATION_CREDENTIALS_JSON — service account key JSON
|
||||||
|
# (alternatively, use Workload Identity and omit the key)
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# ./scripts/gitea-backup-gke.sh list # list all backups
|
||||||
|
# ./scripts/gitea-backup-gke.sh download <filename> # download a backup
|
||||||
|
# ./scripts/gitea-backup-gke.sh download latest # download the most recent backup
|
||||||
|
|
||||||
|
NAMESPACE="gitea"
|
||||||
|
SECRET="gitea-backup-gcs"
|
||||||
|
IMAGE="gcr.io/google.com/cloudsdktool/google-cloud-cli:slim"
|
||||||
|
POD_NAME="gitea-backup-helper"
|
||||||
|
AUTH_CMD='if [ -n "${GOOGLE_APPLICATION_CREDENTIALS_JSON:-}" ]; then echo "${GOOGLE_APPLICATION_CREDENTIALS_JSON}" > /tmp/gcs-key.json && gcloud auth activate-service-account --key-file=/tmp/gcs-key.json > /dev/null 2>&1; fi'
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
kubectl -n "$NAMESPACE" delete pod "$POD_NAME" --ignore-not-found --grace-period=0 > /dev/null 2>&1 || true
|
||||||
|
}
|
||||||
|
|
||||||
|
gcs_run() {
|
||||||
|
cleanup
|
||||||
|
kubectl -n "$NAMESPACE" run "$POD_NAME" --restart=Never \
|
||||||
|
--image="$IMAGE" \
|
||||||
|
--overrides="{
|
||||||
|
\"spec\":{\"containers\":[{
|
||||||
|
\"name\":\"$POD_NAME\",
|
||||||
|
\"image\":\"$IMAGE\",
|
||||||
|
\"env\":[{\"name\":\"HOME\",\"value\":\"/tmp\"}],
|
||||||
|
\"command\":[\"sh\",\"-c\",\"${AUTH_CMD}; $1\"],
|
||||||
|
\"envFrom\":[{\"secretRef\":{\"name\":\"$SECRET\"}}]
|
||||||
|
}]}
|
||||||
|
}" > /dev/null 2>&1
|
||||||
|
|
||||||
|
kubectl -n "$NAMESPACE" wait --for=jsonpath='{.status.phase}'=Succeeded "pod/$POD_NAME" --timeout=120s > /dev/null 2>&1
|
||||||
|
kubectl -n "$NAMESPACE" logs "$POD_NAME"
|
||||||
|
cleanup
|
||||||
|
}
|
||||||
|
|
||||||
|
case "${1:-help}" in
|
||||||
|
list)
|
||||||
|
echo "Listing backups..."
|
||||||
|
gcs_run 'gsutil ls -l gs://${GCS_BUCKET}/'
|
||||||
|
;;
|
||||||
|
|
||||||
|
download)
|
||||||
|
FILE="${2:?Usage: $0 download <filename|latest>}"
|
||||||
|
|
||||||
|
if [ "$FILE" = "latest" ]; then
|
||||||
|
echo "Finding latest backup..."
|
||||||
|
FILE=$(gcs_run 'gsutil ls gs://${GCS_BUCKET}/' | grep -v '^$' | grep -v 'TOTAL' | sort | tail -1 | xargs -I{} basename {} | tr -d '[:space:]')
|
||||||
|
if [ -z "$FILE" ]; then
|
||||||
|
echo "No backups found."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Latest: $FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Downloading $FILE..."
|
||||||
|
cleanup
|
||||||
|
kubectl -n "$NAMESPACE" run "$POD_NAME" --restart=Never \
|
||||||
|
--image="$IMAGE" \
|
||||||
|
--overrides="{
|
||||||
|
\"spec\":{\"containers\":[{
|
||||||
|
\"name\":\"$POD_NAME\",
|
||||||
|
\"image\":\"$IMAGE\",
|
||||||
|
\"env\":[{\"name\":\"HOME\",\"value\":\"/tmp\"}],
|
||||||
|
\"command\":[\"sh\",\"-c\",\"sleep 300\"],
|
||||||
|
\"envFrom\":[{\"secretRef\":{\"name\":\"$SECRET\"}}]
|
||||||
|
}]}
|
||||||
|
}" > /dev/null 2>&1
|
||||||
|
|
||||||
|
kubectl -n "$NAMESPACE" wait --for=condition=Ready "pod/$POD_NAME" --timeout=60s > /dev/null 2>&1
|
||||||
|
|
||||||
|
echo "Saving to ./$FILE ..."
|
||||||
|
kubectl -n "$NAMESPACE" exec "$POD_NAME" -- sh -c "${AUTH_CMD} && gsutil cat gs://\${GCS_BUCKET}/$FILE" > "./$FILE"
|
||||||
|
cleanup
|
||||||
|
|
||||||
|
echo "Downloaded: ./$FILE"
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
echo "Gitea backup helper (Google Cloud Storage)"
|
||||||
|
echo ""
|
||||||
|
echo "Usage:"
|
||||||
|
echo " $0 list List all backups in GCS"
|
||||||
|
echo " $0 download <filename> Download a specific backup"
|
||||||
|
echo " $0 download latest Download the most recent backup"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
Reference in New Issue
Block a user