Compare commits
13 Commits
4e6a84785a
...
feature/ka
| Author | SHA1 | Date | |
|---|---|---|---|
| 3f0f70699b | |||
| 06522b2f19 | |||
| 4c65035485 | |||
| 84f4bebc08 | |||
| 5394b2c714 | |||
| c4e586a7be | |||
| 1fa070b041 | |||
| 9c905355e3 | |||
| 6b1115ec28 | |||
| 2fb276a62c | |||
| 3efe1b68ef | |||
| 5df104beec | |||
| 0ecfee3cf8 |
@@ -34,7 +34,6 @@ 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
|
||||||
|
|||||||
@@ -4,4 +4,5 @@ resources:
|
|||||||
- dot-ai-stack.yaml
|
- dot-ai-stack.yaml
|
||||||
- mcp10x.yaml
|
- mcp10x.yaml
|
||||||
- musicman.yaml
|
- musicman.yaml
|
||||||
|
- ts-mcp.yaml
|
||||||
- argo-mcp.yaml
|
- argo-mcp.yaml
|
||||||
|
|||||||
40
apps/base/ts-mcp.yaml
Normal file
40
apps/base/ts-mcp.yaml
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: ts-mcp
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "11"
|
||||||
|
notifications.argoproj.io/subscribe.on-sync-succeeded.slack: ""
|
||||||
|
notifications.argoproj.io/subscribe.on-sync-failed.slack: ""
|
||||||
|
notifications.argoproj.io/subscribe.on-degraded.slack: ""
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: ts-mcp
|
||||||
|
app.kubernetes.io/part-of: apps
|
||||||
|
app.kubernetes.io/managed-by: argocd
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: default
|
||||||
|
sources:
|
||||||
|
- repoURL: ssh://git@git.forteapps.net:2222/Forte/forte-helm.git
|
||||||
|
path: forteapp
|
||||||
|
targetRevision: HEAD
|
||||||
|
helm:
|
||||||
|
valueFiles:
|
||||||
|
- $values/ts-mcp/values.yaml
|
||||||
|
|
||||||
|
- repoURL: ssh://git@git.forteapps.net:2222/Forte/helm-prod-values.git
|
||||||
|
targetRevision: HEAD
|
||||||
|
ref: values
|
||||||
|
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: ts-mcp
|
||||||
|
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
@@ -57,17 +57,17 @@ spec:
|
|||||||
- sh
|
- sh
|
||||||
- -c
|
- -c
|
||||||
- |
|
- |
|
||||||
mc alias set s3 "${S3_ENDPOINT}" "${AWS_ACCESS_KEY_ID}" "${AWS_SECRET_ACCESS_KEY}"
|
mc alias set upcloud "${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 "s3/${S3_BUCKET}/${KEY}" && \
|
mc cp /backup/gitea-dump.zip "upcloud/${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 "s3/${S3_BUCKET}/" 2>&1 || true
|
mc rm --older-than 7d --force "upcloud/${S3_BUCKET}/" 2>&1 || true
|
||||||
echo "Pruning complete."
|
echo "Pruning complete."
|
||||||
envFrom:
|
envFrom:
|
||||||
- secretRef:
|
- secretRef:
|
||||||
|
|||||||
@@ -962,6 +962,46 @@ User sees application (authenticated)
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### Accessing Authenticated User Information
|
||||||
|
|
||||||
|
The auth sidecar handles all authentication before requests reach your application. Your app never sees unauthenticated traffic — the sidecar returns 401 or redirects to the IdP first.
|
||||||
|
|
||||||
|
After successful authentication, the sidecar forwards the request to your application with user identity injected as HTTP headers:
|
||||||
|
|
||||||
|
| Header | Description | Available in |
|
||||||
|
|--------|-------------|-------------|
|
||||||
|
| `X-Auth-User` | Username or display name | Token, OIDC, MCP |
|
||||||
|
| `X-Auth-Email` | User email address | OIDC |
|
||||||
|
| `X-Auth-Subject` | OIDC `sub` claim (stable user ID) | OIDC, MCP |
|
||||||
|
| `X-Auth-Groups` | Comma-separated group memberships | OIDC (if scope includes `groups`) |
|
||||||
|
| `X-Auth-Token` | The validated access token | All modes |
|
||||||
|
|
||||||
|
**Your application reads these headers — no auth library needed:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Express.js example
|
||||||
|
app.get('/profile', (req, res) => {
|
||||||
|
const user = req.headers['x-auth-user'];
|
||||||
|
const email = req.headers['x-auth-email'];
|
||||||
|
res.json({ user, email });
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Flask example
|
||||||
|
@app.route('/profile')
|
||||||
|
def profile():
|
||||||
|
user = request.headers.get('X-Auth-User')
|
||||||
|
email = request.headers.get('X-Auth-Email')
|
||||||
|
return jsonify(user=user, email=email)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Why this is safe**: The Kyverno-generated NetworkPolicy restricts ingress to the sidecar port only. Traffic cannot bypass the sidecar to reach the application port directly, so the `X-Auth-*` headers can be trusted unconditionally.
|
||||||
|
|
||||||
|
**Key principle**: Your application is zero-trust-unaware by design. It reads headers and renders UI. All authentication complexity lives in the sidecar and Kyverno policy.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### Authentication Configuration Reference
|
### Authentication Configuration Reference
|
||||||
|
|
||||||
#### Helm Values Schema
|
#### Helm Values Schema
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
- [Kyverno Policies](#kyverno-policies)
|
- [Kyverno Policies](#kyverno-policies)
|
||||||
- [Configuration Reference](#configuration-reference)
|
- [Configuration Reference](#configuration-reference)
|
||||||
- [API Endpoints](#api-endpoints)
|
- [API Endpoints](#api-endpoints)
|
||||||
- [Cloud Overlay Pattern](#cloud-overlay-pattern)
|
|
||||||
- [Glossary](#glossary)
|
- [Glossary](#glossary)
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -93,34 +92,16 @@ launchpad/
|
|||||||
│ ├── sealedsecrets.yaml
|
│ ├── sealedsecrets.yaml
|
||||||
│ ├── secrets.yaml
|
│ ├── secrets.yaml
|
||||||
│ ├── renovate.yaml
|
│ ├── renovate.yaml
|
||||||
│ ├── base/ # ArgoCD Application manifests (Kustomize base)
|
|
||||||
│ │ ├── gitea.yaml
|
|
||||||
│ │ ├── opencost.yaml
|
|
||||||
│ │ ├── traefik-application.yaml
|
|
||||||
│ │ ├── keycloak.yaml
|
|
||||||
│ │ ├── grafana.yaml
|
|
||||||
│ │ └── ...
|
|
||||||
│ ├── overlays/
|
|
||||||
│ │ └── upc-prod/
|
|
||||||
│ │ └── kustomization.yaml # Patches upc-dev → upc-prod valueFile paths
|
|
||||||
│ └── values/
|
│ └── values/
|
||||||
│ ├── base/ # Cloud-agnostic Helm values
|
│ ├── argocd-values.yaml
|
||||||
│ │ ├── gitea-values.yaml
|
│ ├── prometheus-values.yaml
|
||||||
│ │ ├── opencost-values.yaml
|
|
||||||
│ │ ├── prometheus-values.yaml
|
|
||||||
│ │ └── ...
|
|
||||||
│ ├── upc-dev/ # UpCloud dev overlay values
|
|
||||||
│ │ ├── traefik-values.yaml
|
|
||||||
│ │ ├── keycloak-values.yaml
|
|
||||||
│ │ ├── grafana-values.yaml
|
|
||||||
│ │ ├── gitea-values.yaml
|
|
||||||
│ │ └── opencost-values.yaml
|
|
||||||
│ └── upc-prod/ # UpCloud prod overlay values
|
|
||||||
│ ├── traefik-values.yaml
|
|
||||||
│ ├── keycloak-values.yaml
|
|
||||||
│ ├── grafana-values.yaml
|
│ ├── grafana-values.yaml
|
||||||
|
│ ├── loki-values.yaml
|
||||||
|
│ ├── tempo-values.yaml
|
||||||
│ ├── gitea-values.yaml
|
│ ├── gitea-values.yaml
|
||||||
│ └── opencost-values.yaml
|
│ ├── gitea-actions-values.yaml
|
||||||
|
│ ├── fluent-bit-values.yaml
|
||||||
|
│ └── renovate-values.yaml
|
||||||
│
|
│
|
||||||
├── apps/ # Business applications
|
├── apps/ # Business applications
|
||||||
│ ├── mcp10x.yaml
|
│ ├── mcp10x.yaml
|
||||||
@@ -154,15 +135,6 @@ launchpad/
|
|||||||
│ ├── mcp10x-credentials-sealed.yaml
|
│ ├── mcp10x-credentials-sealed.yaml
|
||||||
│ └── musicman-credentials.yaml
|
│ └── musicman-credentials.yaml
|
||||||
│
|
│
|
||||||
├── scripts/ # Operational helper scripts
|
|
||||||
│ ├── gitea-backup.sh # S3 backup helper (list/download)
|
|
||||||
│ ├── gitea-restore.sh
|
|
||||||
│ └── backup/ # Per-cloud backup reference scripts
|
|
||||||
│ ├── s3-minio.sh # S3-compatible (UpCloud, MinIO, Wasabi)
|
|
||||||
│ ├── aws-s3.sh # Native AWS S3
|
|
||||||
│ ├── azure-blob.sh # Azure Blob Storage
|
|
||||||
│ └── gcp-gcs.sh # GCP Cloud Storage
|
|
||||||
│
|
|
||||||
├── private/ # Local-only (Git-ignored)
|
├── private/ # Local-only (Git-ignored)
|
||||||
│ ├── *.yaml
|
│ ├── *.yaml
|
||||||
│ └── *.sh
|
│ └── *.sh
|
||||||
@@ -630,6 +602,15 @@ retry:
|
|||||||
4. 40 seconds
|
4. 40 seconds
|
||||||
5. 80 seconds (capped at 3 minutes)
|
5. 80 seconds (capped at 3 minutes)
|
||||||
|
|
||||||
|
### Global Settings (`argocd-cm`)
|
||||||
|
|
||||||
|
| Setting | Value | Purpose |
|
||||||
|
|---------|-------|---------|
|
||||||
|
| `application.resourceTrackingMethod` | `annotation` | Track resources via annotations |
|
||||||
|
| `timeout.reconciliation` | `60s` | Reconciliation interval |
|
||||||
|
| `admin.enabled` | `true` | Enable admin account |
|
||||||
|
| `git.submodule.enabled` | `false` | Disable git submodule checkout — submodules are not needed for manifest generation |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Infrastructure Components
|
## Infrastructure Components
|
||||||
@@ -1097,6 +1078,33 @@ kubectl get secret keycloak-client-<app> -n keycloak -o jsonpath='{.metadata.ann
|
|||||||
|
|
||||||
**See**: [Developer Guide - Adding a New Keycloak Client](DEVELOPER-GUIDE.md#adding-a-new-keycloak-client)
|
**See**: [Developer Guide - Adding a New Keycloak Client](DEVELOPER-GUIDE.md#adding-a-new-keycloak-client)
|
||||||
|
|
||||||
|
### Karpor
|
||||||
|
|
||||||
|
**Chart**: `karpor` from `https://kusionstack.github.io/charts`
|
||||||
|
**Version**: 0.7.6 (app v0.6.4)
|
||||||
|
**Namespace**: `karpor`
|
||||||
|
**Sync Wave**: 1
|
||||||
|
|
||||||
|
**Purpose**: Kubernetes visualization and intelligence tool. Provides cross-cluster resource search, compliance checking, and topology visualization. Gives platform engineers a unified view of all cluster resources and their relationships.
|
||||||
|
|
||||||
|
**Architecture** (4 components):
|
||||||
|
- **Server** — main Karpor API/UI (port 7443)
|
||||||
|
- **Syncer** — syncs cluster state into the search index
|
||||||
|
- **ElasticSearch** — search backend for resource indexing
|
||||||
|
- **etcd** — persistent key-value store (10Gi PVC)
|
||||||
|
|
||||||
|
**Configuration** (`infra/values/base/karpor-values.yaml`):
|
||||||
|
- `namespaceEnabled: false` — ArgoCD manages namespace creation
|
||||||
|
- Default resource limits tuned for small clusters
|
||||||
|
- ElasticSearch: 2 CPU / 4Gi memory (the heaviest component)
|
||||||
|
- AI features available but not enabled (requires `server.ai.authToken` + backend config)
|
||||||
|
|
||||||
|
**Access**: Port-forward to reach the UI:
|
||||||
|
```bash
|
||||||
|
kubectl port-forward svc/karpor-release-server -n karpor 7443:7443
|
||||||
|
# Open https://localhost:7443
|
||||||
|
```
|
||||||
|
|
||||||
### Renovate
|
### Renovate
|
||||||
|
|
||||||
**Chart**: `renovate` (OCI: `ghcr.io/renovatebot/charts`)
|
**Chart**: `renovate` (OCI: `ghcr.io/renovatebot/charts`)
|
||||||
@@ -1544,7 +1552,23 @@ Forward to Application (localhost:3000)
|
|||||||
Application processes request
|
Application processes request
|
||||||
```
|
```
|
||||||
|
|
||||||
**See**: [Developer Guide - Enabling Authentication](DEVELOPER-GUIDE.md#enabling-authentication-for-applications) for usage examples.
|
#### Forwarded Headers
|
||||||
|
|
||||||
|
After successful authentication, the sidecar injects user identity as HTTP headers before forwarding the request to the application container:
|
||||||
|
|
||||||
|
| Header | Description | Auth Modes |
|
||||||
|
|--------|-------------|------------|
|
||||||
|
| `X-Auth-User` | Username or display name | Token, OIDC, MCP |
|
||||||
|
| `X-Auth-Email` | User email address | OIDC |
|
||||||
|
| `X-Auth-Subject` | OIDC `sub` claim (stable user ID) | OIDC, MCP |
|
||||||
|
| `X-Auth-Groups` | Comma-separated group memberships | OIDC (if `groups` scope) |
|
||||||
|
| `X-Auth-Token` | The validated access token | All modes |
|
||||||
|
|
||||||
|
These headers are trustworthy because the auto-generated `NetworkPolicy` restricts pod ingress to the sidecar port only — external traffic cannot reach the application container directly, so headers cannot be spoofed.
|
||||||
|
|
||||||
|
Applications should read these headers to obtain authenticated user information (e.g. for display, authorisation decisions, or audit logging) instead of implementing their own authentication.
|
||||||
|
|
||||||
|
**See**: [Developer Guide - Accessing Authenticated User Information](DEVELOPER-GUIDE.md#accessing-authenticated-user-information) for code examples.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -1649,79 +1673,6 @@ POST /loki/api/v1/push
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Cloud Overlay Pattern
|
|
||||||
|
|
||||||
### Overview
|
|
||||||
|
|
||||||
Cloud-specific configuration (StorageClass, LoadBalancer annotations, pricing models, etc.) lives in per-cloud overlay value files, **not** in `base/`. This means adding a new cloud provider (AKS, EKS, GKE) only requires a new overlay directory — no base changes.
|
|
||||||
|
|
||||||
### How It Works
|
|
||||||
|
|
||||||
Each ArgoCD Application uses **multi-source Helm values** with two value files:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
# infra/base/gitea.yaml (example)
|
|
||||||
helm:
|
|
||||||
valueFiles:
|
|
||||||
- $values/infra/values/base/gitea-values.yaml # [0] cloud-agnostic
|
|
||||||
- $values/infra/values/upc-dev/gitea-values.yaml # [1] cloud-specific (default: upc-dev)
|
|
||||||
```
|
|
||||||
|
|
||||||
The `upc-prod` Kustomize overlay patches index `[1]` to swap the cloud-specific file:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
# infra/overlays/upc-prod/kustomization.yaml
|
|
||||||
- target:
|
|
||||||
kind: Application
|
|
||||||
name: gitea
|
|
||||||
patch: |
|
|
||||||
- op: replace
|
|
||||||
path: /spec/sources/0/helm/valueFiles/1
|
|
||||||
value: $values/infra/values/upc-prod/gitea-values.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
### Components Using Cloud Overlays
|
|
||||||
|
|
||||||
| Component | Cloud-specific config | Overlay value file |
|
|
||||||
|-----------|----------------------|-------------------|
|
|
||||||
| **Traefik** | LB annotations, proxy protocol IPs | `traefik-values.yaml` |
|
|
||||||
| **Keycloak** | Hostname, TLS settings | `keycloak-values.yaml` |
|
|
||||||
| **Grafana** | Hostname, datasource URLs | `grafana-values.yaml` |
|
|
||||||
| **Gitea** | StorageClass (persistence + PostgreSQL) | `gitea-values.yaml` |
|
|
||||||
| **OpenCost** | Custom pricing model (CPU/RAM/storage rates) | `opencost-values.yaml` |
|
|
||||||
|
|
||||||
### Backup CronJob
|
|
||||||
|
|
||||||
The `gitea-backup` CronJob uses a generic `s3` alias for `minio/mc`. The actual endpoint and credentials come from the `gitea-backup-s3` Sealed Secret, which is per-cloud. Reference scripts for different cloud providers are in `scripts/backup/`:
|
|
||||||
|
|
||||||
| Script | Provider | Tool |
|
|
||||||
|--------|----------|------|
|
|
||||||
| `s3-minio.sh` | S3-compatible (UpCloud, MinIO, Wasabi) | `minio/mc` |
|
|
||||||
| `aws-s3.sh` | AWS S3 | `aws` CLI |
|
|
||||||
| `azure-blob.sh` | Azure Blob Storage | `az` CLI |
|
|
||||||
| `gcp-gcs.sh` | GCP Cloud Storage | `gsutil` |
|
|
||||||
|
|
||||||
### Adding a New Cloud Provider
|
|
||||||
|
|
||||||
To add support for a new cloud (e.g., `aks-dev`):
|
|
||||||
|
|
||||||
1. **Create overlay value directory**: `infra/values/aks-dev/`
|
|
||||||
2. **Add cloud-specific value files** for each component that needs one:
|
|
||||||
- `traefik-values.yaml` — LB annotations, proxy protocol config
|
|
||||||
- `keycloak-values.yaml` — hostname/TLS if different
|
|
||||||
- `grafana-values.yaml` — hostname/datasources if different
|
|
||||||
- `gitea-values.yaml` — `storageClass` for persistence + PostgreSQL
|
|
||||||
- `opencost-values.yaml` — `customPricing` cost model for your cloud
|
|
||||||
3. **Create a Kustomize overlay** (if needed): `infra/overlays/aks-prod/kustomization.yaml`
|
|
||||||
- Patch each Application's `valueFiles[1]` to point to `aks-prod/` files
|
|
||||||
4. **Create a root Application**: `_app-of-apps-aks-dev.yaml` pointing to the overlay
|
|
||||||
5. **Create Sealed Secrets** for the new cluster:
|
|
||||||
- `secrets/aks-dev/` — TLS certs, credentials, backup S3 config
|
|
||||||
6. **Update `gitea-backup-s3` secret** with the new cloud's S3-compatible endpoint
|
|
||||||
7. **Bootstrap**: `kubectl apply -f _app-of-apps-aks-dev.yaml -n argocd`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Glossary
|
## Glossary
|
||||||
|
|
||||||
### Terms
|
### Terms
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ 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
|
||||||
|
|||||||
42
infra/base/karpor.yaml
Normal file
42
infra/base/karpor.yaml
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: karpor
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "1"
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: karpor
|
||||||
|
app.kubernetes.io/part-of: developer-portal
|
||||||
|
app.kubernetes.io/managed-by: argocd
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: default
|
||||||
|
|
||||||
|
sources:
|
||||||
|
- repoURL: https://kusionstack.github.io/charts
|
||||||
|
chart: karpor
|
||||||
|
targetRevision: "0.7.6"
|
||||||
|
helm:
|
||||||
|
releaseName: karpor
|
||||||
|
valueFiles:
|
||||||
|
- $values/infra/values/base/karpor-values.yaml
|
||||||
|
|
||||||
|
- repoURL: ssh://git@git.forteapps.net:2222/Forte/launchpad.git
|
||||||
|
targetRevision: HEAD
|
||||||
|
ref: values
|
||||||
|
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: karpor
|
||||||
|
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
allowEmpty: false
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- Validate=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -22,3 +22,4 @@ resources:
|
|||||||
- tempo.yaml
|
- tempo.yaml
|
||||||
- grafana-dashboards.yaml
|
- grafana-dashboards.yaml
|
||||||
- network-policies-application.yaml
|
- network-policies-application.yaml
|
||||||
|
- karpor.yaml
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ 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: git@github.com:fortedigital/sturdy-adventure.git
|
||||||
targetRevision: HEAD
|
targetRevision: HEAD
|
||||||
|
|||||||
@@ -31,24 +31,6 @@ patches:
|
|||||||
path: /spec/sources/0/helm/valueFiles/1
|
path: /spec/sources/0/helm/valueFiles/1
|
||||||
value: $values/infra/values/upc-prod/grafana-values.yaml
|
value: $values/infra/values/upc-prod/grafana-values.yaml
|
||||||
|
|
||||||
# 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
|
|
||||||
|
|
||||||
# Secrets: change path to upc-prod
|
# Secrets: change path to upc-prod
|
||||||
- target:
|
- target:
|
||||||
kind: Application
|
kind: Application
|
||||||
|
|||||||
@@ -2,12 +2,21 @@ configs:
|
|||||||
secret:
|
secret:
|
||||||
createSecret: true
|
createSecret: true
|
||||||
argocdServerAdminPassword: "$2b$12$Tmb1jH7ADvwWoUoNPXXsfOf6JqEluqhq8mL06a8DGT2AP1GzbNsCm"
|
argocdServerAdminPassword: "$2b$12$Tmb1jH7ADvwWoUoNPXXsfOf6JqEluqhq8mL06a8DGT2AP1GzbNsCm"
|
||||||
|
ssh:
|
||||||
|
knownHosts: |
|
||||||
|
[git.forteapps.net]:2222 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDTwi40de8yTGUuRT0i/XGicQ672BLhYR6D/lDquJrp/tdrWoZhVVPy0wxSkWsq1V92iiAUuQnXagOGsLBGZT9uDLWKvEmNDnCfjzTMq3J1iA3vk2rQ8WBlCzhvmeCV/r0ufl6vsgfwxSRomLZeqa2UkLHx69gy2Njb1S2/aZK1Q53f466hCUfDULZrTn2Nn5Sj8cEbJ8EyvVN2YG9HYBxQdzKRPZEmS1vyzmn8YrYIkZseIRQElabzWGh86owuaaqnwJhTJj1j2sEUeIet04sGKJcnxx2UL4H90N66LKMldmMiuli+ve/CjJmMwDl0zGkjIniT3XR8CyEXYHli7B1hR8Z+dbK6DBgjz+28lFgMIRY70KkZJNsJcBNZLZ5fHwCI13a9U3Uhg3Pu/6s0zlosM4CrAQNQCRe95ZPtCpdFhlGrOl4m1rdSK2meL6rND0TBBuZbaFF6Py7TawLCAiO2KRaVqhu9OFVjwJ/nifgLzFGwWj+WcYmpuR+DwozrF/Hl7QYsz1x4GO1SONY07KbIFkUCHOMAh0AELY5YE4eGI4mtG6SecdPaAdLREGZYK4IcyP5i1QW9g0wmfRSsV9jy+r0ivBxixxh4yJiNpkg6NXak40gQtGIme9EJ+DxrRLruNsfDILWcdSuH/wvuorv56NpQFGB0FzB6LXMloSYptQ==
|
||||||
cm:
|
cm:
|
||||||
application.resourceTrackingMethod: annotation
|
application.resourceTrackingMethod: annotation
|
||||||
timeout.reconciliation: 60s
|
timeout.reconciliation: 60s
|
||||||
admin.enabled: "true"
|
admin.enabled: "true"
|
||||||
params:
|
params:
|
||||||
"server.insecure": true
|
"server.insecure": true
|
||||||
|
repoServer:
|
||||||
|
env:
|
||||||
|
# Disable git submodule checkout - submodules (e.g. shared-prompts)
|
||||||
|
# are not needed for K8s manifest generation
|
||||||
|
- name: ARGOCD_GIT_MODULES_ENABLED
|
||||||
|
value: "false"
|
||||||
server:
|
server:
|
||||||
ingress:
|
ingress:
|
||||||
enabled: false
|
enabled: false
|
||||||
|
|||||||
@@ -130,6 +130,7 @@ 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:
|
||||||
@@ -155,6 +156,7 @@ postgresql:
|
|||||||
persistence:
|
persistence:
|
||||||
enabled: true
|
enabled: true
|
||||||
size: 8Gi
|
size: 8Gi
|
||||||
|
storageClass: upcloud-block-storage-maxiops
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
cpu: 100m
|
cpu: 100m
|
||||||
|
|||||||
44
infra/values/base/karpor-values.yaml
Normal file
44
infra/values/base/karpor-values.yaml
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
# Karpor - Kubernetes Visualization & Intelligence Tool
|
||||||
|
# Helm chart: https://github.com/KusionStack/charts/tree/master/charts/karpor
|
||||||
|
|
||||||
|
# Let the ArgoCD Application manage the namespace
|
||||||
|
namespaceEnabled: false
|
||||||
|
|
||||||
|
server:
|
||||||
|
replicas: 1
|
||||||
|
port: 7443
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 250m
|
||||||
|
memory: 256Mi
|
||||||
|
limits:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 1Gi
|
||||||
|
|
||||||
|
syncer:
|
||||||
|
replicas: 1
|
||||||
|
port: 7443
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 250m
|
||||||
|
memory: 256Mi
|
||||||
|
limits:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 1Gi
|
||||||
|
|
||||||
|
elasticsearch:
|
||||||
|
replicas: 1
|
||||||
|
port: 9200
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 2Gi
|
||||||
|
limits:
|
||||||
|
cpu: "2"
|
||||||
|
memory: 4Gi
|
||||||
|
|
||||||
|
etcd:
|
||||||
|
replicas: 1
|
||||||
|
port: 2379
|
||||||
|
persistence:
|
||||||
|
size: 5Gi
|
||||||
@@ -10,6 +10,18 @@ opencost:
|
|||||||
serviceName: prometheus-server
|
serviceName: prometheus-server
|
||||||
namespaceName: monitoring
|
namespaceName: monitoring
|
||||||
port: 80
|
port: 80
|
||||||
|
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"
|
||||||
ui:
|
ui:
|
||||||
enabled: false
|
enabled: false
|
||||||
service:
|
service:
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
# UpCloud-specific: block storage class for Gitea + PostgreSQL
|
|
||||||
persistence:
|
|
||||||
storageClass: upcloud-block-storage-maxiops
|
|
||||||
postgresql:
|
|
||||||
primary:
|
|
||||||
persistence:
|
|
||||||
storageClass: upcloud-block-storage-maxiops
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# UpCloud-specific: custom pricing model
|
|
||||||
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"
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
# UpCloud-specific: block storage class for Gitea + PostgreSQL
|
|
||||||
persistence:
|
|
||||||
storageClass: upcloud-block-storage-maxiops
|
|
||||||
postgresql:
|
|
||||||
primary:
|
|
||||||
persistence:
|
|
||||||
storageClass: upcloud-block-storage-maxiops
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# UpCloud-specific: custom pricing model
|
|
||||||
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"
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
# AWS S3 backup upload (native AWS CLI)
|
|
||||||
# Uses: aws cli v2
|
|
||||||
# Env: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION, S3_BUCKET
|
|
||||||
|
|
||||||
BACKUP_FILE="${1:?Usage: $0 <backup-file>}"
|
|
||||||
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
|
|
||||||
KEY="gitea-dump-${TIMESTAMP}.zip"
|
|
||||||
|
|
||||||
echo "Uploading ${KEY}..."
|
|
||||||
aws s3 cp "$BACKUP_FILE" "s3://${S3_BUCKET}/${KEY}"
|
|
||||||
echo "Upload complete."
|
|
||||||
|
|
||||||
# Prune backups older than 7 days
|
|
||||||
echo "Pruning backups older than 7 days..."
|
|
||||||
CUTOFF=$(date -d '7 days ago' +%Y-%m-%dT%H:%M:%S 2>/dev/null || date -v-7d +%Y-%m-%dT%H:%M:%S)
|
|
||||||
aws s3api list-objects-v2 --bucket "${S3_BUCKET}" --query "Contents[?LastModified<'${CUTOFF}'].Key" --output text \
|
|
||||||
| tr '\t' '\n' \
|
|
||||||
| while read -r key; do
|
|
||||||
[ -n "$key" ] && aws s3 rm "s3://${S3_BUCKET}/${key}" && echo "Deleted: ${key}"
|
|
||||||
done
|
|
||||||
echo "Pruning complete."
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
# Azure Blob Storage backup upload
|
|
||||||
# Uses: az cli
|
|
||||||
# Env: AZURE_STORAGE_ACCOUNT, AZURE_STORAGE_KEY, AZURE_CONTAINER
|
|
||||||
|
|
||||||
BACKUP_FILE="${1:?Usage: $0 <backup-file>}"
|
|
||||||
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
|
|
||||||
KEY="gitea-dump-${TIMESTAMP}.zip"
|
|
||||||
|
|
||||||
echo "Uploading ${KEY}..."
|
|
||||||
az storage blob upload \
|
|
||||||
--account-name "${AZURE_STORAGE_ACCOUNT}" \
|
|
||||||
--account-key "${AZURE_STORAGE_KEY}" \
|
|
||||||
--container-name "${AZURE_CONTAINER}" \
|
|
||||||
--name "${KEY}" \
|
|
||||||
--file "$BACKUP_FILE" \
|
|
||||||
--overwrite
|
|
||||||
echo "Upload complete."
|
|
||||||
|
|
||||||
# Prune backups older than 7 days
|
|
||||||
echo "Pruning backups older than 7 days..."
|
|
||||||
CUTOFF=$(date -d '7 days ago' +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -v-7d +%Y-%m-%dT%H:%M:%SZ)
|
|
||||||
az storage blob list \
|
|
||||||
--account-name "${AZURE_STORAGE_ACCOUNT}" \
|
|
||||||
--account-key "${AZURE_STORAGE_KEY}" \
|
|
||||||
--container-name "${AZURE_CONTAINER}" \
|
|
||||||
--query "[?properties.lastModified<'${CUTOFF}'].name" -o tsv \
|
|
||||||
| while read -r name; do
|
|
||||||
[ -n "$name" ] && az storage blob delete \
|
|
||||||
--account-name "${AZURE_STORAGE_ACCOUNT}" \
|
|
||||||
--account-key "${AZURE_STORAGE_KEY}" \
|
|
||||||
--container-name "${AZURE_CONTAINER}" \
|
|
||||||
--name "$name" && echo "Deleted: ${name}"
|
|
||||||
done
|
|
||||||
echo "Pruning complete."
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
# GCP Cloud Storage backup upload
|
|
||||||
# Uses: gsutil (gcloud SDK)
|
|
||||||
# Env: GCS_BUCKET (e.g. gs://my-bucket)
|
|
||||||
|
|
||||||
BACKUP_FILE="${1:?Usage: $0 <backup-file>}"
|
|
||||||
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
|
|
||||||
KEY="gitea-dump-${TIMESTAMP}.zip"
|
|
||||||
|
|
||||||
echo "Uploading ${KEY}..."
|
|
||||||
gsutil cp "$BACKUP_FILE" "${GCS_BUCKET}/${KEY}"
|
|
||||||
echo "Upload complete."
|
|
||||||
|
|
||||||
# Prune backups older than 7 days — GCS lifecycle rules are preferred,
|
|
||||||
# but this works as a manual fallback
|
|
||||||
echo "Pruning backups older than 7 days..."
|
|
||||||
CUTOFF=$(date -d '7 days ago' +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -v-7d +%Y-%m-%dT%H:%M:%SZ)
|
|
||||||
gsutil ls -l "${GCS_BUCKET}/" \
|
|
||||||
| grep 'gitea-dump-' \
|
|
||||||
| while read -r size date name; do
|
|
||||||
if [[ "$date" < "$CUTOFF" ]]; then
|
|
||||||
gsutil rm "$name" && echo "Deleted: ${name}"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
echo "Pruning complete."
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
# S3-compatible backup upload (UpCloud Objects, MinIO, Wasabi, etc.)
|
|
||||||
# Uses: minio/mc
|
|
||||||
# Env: S3_ENDPOINT, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, S3_BUCKET
|
|
||||||
|
|
||||||
BACKUP_FILE="${1:?Usage: $0 <backup-file>}"
|
|
||||||
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
|
|
||||||
KEY="gitea-dump-${TIMESTAMP}.zip"
|
|
||||||
|
|
||||||
mc alias set s3 "${S3_ENDPOINT}" "${AWS_ACCESS_KEY_ID}" "${AWS_SECRET_ACCESS_KEY}"
|
|
||||||
|
|
||||||
echo "Uploading ${KEY}..."
|
|
||||||
mc cp "$BACKUP_FILE" "s3/${S3_BUCKET}/${KEY}"
|
|
||||||
echo "Upload complete."
|
|
||||||
|
|
||||||
# Prune backups older than 7 days
|
|
||||||
echo "Pruning backups older than 7 days..."
|
|
||||||
mc rm --older-than 7d --force "s3/${S3_BUCKET}/" 2>&1 || true
|
|
||||||
echo "Pruning complete."
|
|
||||||
@@ -13,7 +13,7 @@ NAMESPACE="gitea"
|
|||||||
SECRET="gitea-backup-s3"
|
SECRET="gitea-backup-s3"
|
||||||
IMAGE="minio/mc:latest"
|
IMAGE="minio/mc:latest"
|
||||||
POD_NAME="gitea-backup-helper"
|
POD_NAME="gitea-backup-helper"
|
||||||
ALIAS_CMD='mc alias set s3 ${S3_ENDPOINT} ${AWS_ACCESS_KEY_ID} ${AWS_SECRET_ACCESS_KEY} > /dev/null'
|
ALIAS_CMD='mc alias set upcloud ${S3_ENDPOINT} ${AWS_ACCESS_KEY_ID} ${AWS_SECRET_ACCESS_KEY} > /dev/null'
|
||||||
|
|
||||||
cleanup() {
|
cleanup() {
|
||||||
kubectl -n "$NAMESPACE" delete pod "$POD_NAME" --ignore-not-found --grace-period=0 > /dev/null 2>&1 || true
|
kubectl -n "$NAMESPACE" delete pod "$POD_NAME" --ignore-not-found --grace-period=0 > /dev/null 2>&1 || true
|
||||||
@@ -41,7 +41,7 @@ mc_run() {
|
|||||||
case "${1:-help}" in
|
case "${1:-help}" in
|
||||||
list)
|
list)
|
||||||
echo "Listing backups..."
|
echo "Listing backups..."
|
||||||
mc_run 'mc ls s3/${S3_BUCKET}/'
|
mc_run 'mc ls upcloud/${S3_BUCKET}/'
|
||||||
;;
|
;;
|
||||||
|
|
||||||
download)
|
download)
|
||||||
@@ -49,7 +49,7 @@ case "${1:-help}" in
|
|||||||
|
|
||||||
if [ "$FILE" = "latest" ]; then
|
if [ "$FILE" = "latest" ]; then
|
||||||
echo "Finding latest backup..."
|
echo "Finding latest backup..."
|
||||||
FILE=$(mc_run 'mc ls s3/${S3_BUCKET}/' | sort | tail -1 | awk '{print $NF}' | tr -d '[:space:]')
|
FILE=$(mc_run 'mc ls upcloud/${S3_BUCKET}/' | sort | tail -1 | awk '{print $NF}' | tr -d '[:space:]')
|
||||||
if [ -z "$FILE" ]; then
|
if [ -z "$FILE" ]; then
|
||||||
echo "No backups found."
|
echo "No backups found."
|
||||||
exit 1
|
exit 1
|
||||||
@@ -74,7 +74,7 @@ case "${1:-help}" in
|
|||||||
kubectl -n "$NAMESPACE" wait --for=condition=Ready "pod/$POD_NAME" --timeout=60s > /dev/null 2>&1
|
kubectl -n "$NAMESPACE" wait --for=condition=Ready "pod/$POD_NAME" --timeout=60s > /dev/null 2>&1
|
||||||
|
|
||||||
echo "Saving to ./$FILE ..."
|
echo "Saving to ./$FILE ..."
|
||||||
kubectl -n "$NAMESPACE" exec "$POD_NAME" -- sh -c "${ALIAS_CMD} && mc cat s3/\${S3_BUCKET}/$FILE" > "./$FILE"
|
kubectl -n "$NAMESPACE" exec "$POD_NAME" -- sh -c "${ALIAS_CMD} && mc cat upcloud/\${S3_BUCKET}/$FILE" > "./$FILE"
|
||||||
cleanup
|
cleanup
|
||||||
|
|
||||||
echo "Downloaded: ./$FILE"
|
echo "Downloaded: ./$FILE"
|
||||||
|
|||||||
Submodule shared-prompts updated: 4ec0c926c7...c5bc55b3d7
Reference in New Issue
Block a user