Internal Developer Platform (IDP)¶
Minnova's approach to developer self-service for application deployment.
Last updated: 2025-12-28
Problem Statement¶
Current state: DevOps writes K8s manifests, manually provisions databases, handles all deployments.
Target state: Developers self-service deploy applications with databases, preview environments auto-created on PRs.
Chosen Approach: GitOps-Native IDP¶
After evaluating external tools (Devtron, Kubero, Backstage), we chose to build a lightweight internal IDP using existing infrastructure:
| Component | Solution |
|---|---|
| App Deployment | ArgoCD ApplicationSet + minnova-app Helm chart |
| Database Provisioning | CloudNative-PG via Helm chart |
| Preview Environments | ArgoCD Pull Request Generator |
| Configuration | Simple YAML in app repos |
| Secrets | SOPS in app repos (shared key) |
Why Not External Tools?¶
| Tool | Issue |
|---|---|
| Devtron | Conflicts with existing ArgoCD, complex SSO, heavy dependencies |
| Kubero | CRD-based (not Git-centric), own database addons (not CNPG) |
| Backstage | Too complex for small teams |
ArgoCD Git Authentication¶
Each deployment has its own ArgoCD instance with its own credentials. This ensures: - Client credentials stay in client's deployment - No cross-client secret sharing - Client can revoke access independently
| Git Provider | Recommended Auth |
|---|---|
| GitHub | GitHub App (single credential for all org repos) |
| Forgejo/Gitea | Deploy Keys (SSH key per repo) |
| GitLab | Project Access Token |
Onboarding flow: 1. Client creates GitHub App in their org (Contents: Read) 2. Credentials stored in their deployment's secrets 3. Their ArgoCD uses their credentials
See ArgoCD docs: GitHub App
How It Works¶
1. App Registry¶
Each app has a simple YAML file in the infra repo:
# deployments/minnova/apps/oracle.yaml
name: oracle
repo: https://github.com/minnova-io/oracle.git
To add a new app: Developer opens PR to add a new file apps/<name>.yaml. Platform team reviews and merges.
2. App Configuration¶
Each app has a .minnova/app.yaml in its repo:
# .minnova/app.yaml
name: oracle
image:
repository: registry.minnova.io/oracle
port: 4000
database:
enabled: true
size: 5Gi
environments:
dev:
replicas: 1
host: oracle.dev.minnova.io
prod:
replicas: 3
host: oracle.minnova.io
env:
LOG_LEVEL: info
Developers own this config. Changes trigger redeployment.
3. Secrets¶
App secrets live in the app repo, encrypted with SOPS:
# .minnova/secrets/prod.enc.yaml
apiVersion: v1
kind: Secret
metadata:
name: oracle-secrets
stringData:
SECRET_KEY_BASE: ENC[AES256_GCM,data:...,type:str]
API_KEY: ENC[AES256_GCM,data:...,type:str]
Apps use the platform's SOPS Age key for encryption. This allows:
- Secrets version-controlled with code
- Developers manage their own secrets
- Platform team controls the key
4. ArgoCD Generates Deployments¶
The ApplicationSet reads registry + app configs and generates:
- One ArgoCD Application per app per environment
- Each uses the
minnova-appHelm chart - Secrets are decrypted by SOPS operator in cluster
Preview Environments¶
When a PR is opened, ArgoCD automatically:
- Creates a preview namespace
- Deploys the app with PR-specific config
- Creates preview database (if enabled)
- Exposes at
app-pr-123.preview.minnova.io
When PR is closed/merged:
- Namespace and all resources are deleted
Developer Workflow¶
Adding a New App¶
- Create
.minnova/app.yamlin your repo - Add secrets to
.minnova/secrets/(encrypted withsops) - Open PR to platform registry to register the app
- Once merged, ArgoCD deploys automatically
Updating an App¶
- Update
.minnova/app.yamlor push new image tag - ArgoCD detects change and syncs
Adding Secrets¶
# Encrypt with platform's Age key
sops --encrypt --age age1... secret.yaml > .minnova/secrets/prod.enc.yaml
git add .minnova/secrets/
git commit -m "add production secrets"
Database Provisioning¶
When database.enabled: true, the platform:
- Creates a CloudNative-PG Cluster
- Configures automated backups to R2
- Injects
DATABASE_URLinto the app
Developers just set:
database:
enabled: true
size: 5Gi
Implementation Status¶
-
minnova-appHelm chart structure - ArgoCD ApplicationSet for registry
- Preview environment ApplicationSet
- Test with first app (oracle)
- Document SOPS key sharing process