multi-user access: fix template memory default, add storage quota, add CONTRIBUTING.md [ci skip]
- Template: bump default memory from 128Mi to 256Mi (matches deploy-app skill guidance) - ResourceQuota: add requests.storage (20Gi) and persistentvolumeclaims (5) defaults - CONTRIBUTING.md: agent-friendly contributor guide for namespace-owners
This commit is contained in:
parent
8dccf4f5ef
commit
b3c9c45a17
3 changed files with 139 additions and 10 deletions
125
CONTRIBUTING.md
Normal file
125
CONTRIBUTING.md
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
# Contributing to the Infrastructure Repo
|
||||||
|
|
||||||
|
This guide covers the namespace-owner workflow for deploying apps on the cluster. For admin operations, see `AGENTS.md`.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
1. You are listed in `k8s_users` (Vault KV `secret/platform`) with `role: "namespace-owner"`
|
||||||
|
2. Your namespace exists (auto-created by the vault stack)
|
||||||
|
3. You have Vault CLI access: `vault login -method=oidc`
|
||||||
|
4. You have cluster access: `kubectl get namespaces` (uses OIDC via kubelogin)
|
||||||
|
|
||||||
|
## Deploy Your App (5 Steps)
|
||||||
|
|
||||||
|
### 1. Copy the Template
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp -r stacks/_template stacks/myapp
|
||||||
|
mv stacks/myapp/main.tf.example stacks/myapp/main.tf
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Customize `main.tf`
|
||||||
|
|
||||||
|
Replace all `<placeholders>`:
|
||||||
|
|
||||||
|
| Placeholder | Example |
|
||||||
|
|-------------|---------|
|
||||||
|
| `<your-namespace>` | `anca` |
|
||||||
|
| `<app-name>` | `my-webapp` |
|
||||||
|
| `<dockerhub-user>/<app-name>:<tag>` | `jdoe/my-webapp:abc12345` |
|
||||||
|
|
||||||
|
Set resources explicitly on every container:
|
||||||
|
|
||||||
|
```hcl
|
||||||
|
resources {
|
||||||
|
requests = { cpu = "10m", memory = "256Mi" }
|
||||||
|
limits = { memory = "256Mi" }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Store Secrets in Vault
|
||||||
|
|
||||||
|
```bash
|
||||||
|
vault login -method=oidc
|
||||||
|
vault kv put secret/<your-username>/myapp DB_PASSWORD=xxx API_KEY=yyy
|
||||||
|
```
|
||||||
|
|
||||||
|
Your Vault path is `secret/<your-username>/*` — full CRUD access there only.
|
||||||
|
|
||||||
|
### 4. Submit a PR
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git checkout -b feat/myapp
|
||||||
|
git add stacks/myapp/
|
||||||
|
git commit -m "add myapp stack"
|
||||||
|
git push -u origin feat/myapp
|
||||||
|
```
|
||||||
|
|
||||||
|
Open a PR. Admin reviews and runs `terragrunt apply`.
|
||||||
|
|
||||||
|
### 5. Set Up CI/CD (Optional)
|
||||||
|
|
||||||
|
For automated deploys on push, create `.woodpecker/deploy.yml` in your app repo:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
steps:
|
||||||
|
- name: deploy
|
||||||
|
image: bitnami/kubectl:latest
|
||||||
|
commands:
|
||||||
|
- kubectl set image deployment/<app-name> <app-name>=<image>:${CI_COMMIT_SHA:0:8} -n <namespace>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Resource Constraints
|
||||||
|
|
||||||
|
Your namespace has hard limits enforced by ResourceQuota:
|
||||||
|
|
||||||
|
| Resource | Default |
|
||||||
|
|----------|---------|
|
||||||
|
| CPU requests | 2 cores |
|
||||||
|
| Memory requests | 4Gi |
|
||||||
|
| Memory limits | 8Gi |
|
||||||
|
| Pods | 20 |
|
||||||
|
| Storage | 20Gi |
|
||||||
|
| PVCs | 5 |
|
||||||
|
|
||||||
|
- Pods run at **tier-4-aux** priority — they never preempt platform services.
|
||||||
|
- Kyverno injects default limits (256Mi) for containers without explicit resources.
|
||||||
|
- Always set explicit `resources {}` to avoid surprises.
|
||||||
|
|
||||||
|
## Vault Secret Paths
|
||||||
|
|
||||||
|
| Path | Access |
|
||||||
|
|------|--------|
|
||||||
|
| `secret/<your-username>/*` | Full CRUD (your secrets) |
|
||||||
|
| `kubernetes/creds/<namespace>-deployer` | Read (dynamic K8s deploy tokens) |
|
||||||
|
| `transit/encrypt/sops-state-<namespace>` | Encrypt (state encryption) |
|
||||||
|
| `transit/decrypt/sops-state-<namespace>` | Decrypt (state encryption) |
|
||||||
|
|
||||||
|
## What NOT to Do
|
||||||
|
|
||||||
|
- **No kubectl mutations**: Never `kubectl apply/edit/patch/delete` for persistent changes. Read-only kubectl is fine for debugging.
|
||||||
|
- **No secrets in code**: Use Vault KV or Sealed Secrets. Never commit plaintext secrets.
|
||||||
|
- **No `:latest` tags**: The pull-through cache serves stale `:latest` manifests. Use 8-char git SHA tags (e.g., `abc12345`).
|
||||||
|
- **No resources outside your namespace**: RBAC prevents it. Don't try.
|
||||||
|
- **No `terragrunt apply`**: Admin-only. Submit a PR instead.
|
||||||
|
- **No unbounded resource specs**: Always set `resources {}` with explicit CPU/memory.
|
||||||
|
|
||||||
|
## AI Agent Instructions
|
||||||
|
|
||||||
|
If you're an AI agent helping a namespace-owner:
|
||||||
|
|
||||||
|
1. Read this file and `AGENTS.md` before making changes
|
||||||
|
2. Check `stacks/_template/` for the canonical starting point
|
||||||
|
3. Always set explicit `resources {}` (256Mi memory minimum)
|
||||||
|
4. Store secrets at `secret/<username>/<app>` in Vault
|
||||||
|
5. Never run `terragrunt apply` — create a PR for admin review
|
||||||
|
6. Use versioned image tags, never `:latest`
|
||||||
|
7. Interactive setup: `curl -fsSL https://k8s-portal.viktorbarzin.me/setup/script?os=mac`
|
||||||
|
8. Agent bootstrap doc: `curl -fsSL https://k8s-portal.viktorbarzin.me/agent`
|
||||||
|
|
||||||
|
## Further Reading
|
||||||
|
|
||||||
|
- [Onboarding guide](https://k8s-portal.viktorbarzin.me/onboarding)
|
||||||
|
- [Agent bootstrap doc](https://k8s-portal.viktorbarzin.me/agent)
|
||||||
|
- Template: `stacks/_template/main.tf.example`
|
||||||
|
- Full agent instructions: `AGENTS.md`
|
||||||
|
|
@ -55,8 +55,8 @@ resource "kubernetes_deployment" "app" {
|
||||||
container_port = 8080 # Change to your app's port
|
container_port = 8080 # Change to your app's port
|
||||||
}
|
}
|
||||||
resources {
|
resources {
|
||||||
requests = { cpu = "10m", memory = "128Mi" }
|
requests = { cpu = "10m", memory = "256Mi" }
|
||||||
limits = { memory = "128Mi" }
|
limits = { memory = "256Mi" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,12 @@ variable "k8s_users" {
|
||||||
namespaces = optional(list(string), []) # for namespace-owners
|
namespaces = optional(list(string), []) # for namespace-owners
|
||||||
domains = optional(list(string), []) # subdomains for user apps
|
domains = optional(list(string), []) # subdomains for user apps
|
||||||
quota = optional(object({
|
quota = optional(object({
|
||||||
cpu_requests = optional(string, "2")
|
cpu_requests = optional(string, "2")
|
||||||
memory_requests = optional(string, "4Gi")
|
memory_requests = optional(string, "4Gi")
|
||||||
memory_limits = optional(string, "8Gi")
|
memory_limits = optional(string, "8Gi")
|
||||||
pods = optional(string, "20")
|
pods = optional(string, "20")
|
||||||
|
storage_requests = optional(string, "20Gi")
|
||||||
|
persistentvolumeclaims = optional(string, "5")
|
||||||
}), {})
|
}), {})
|
||||||
}))
|
}))
|
||||||
default = {}
|
default = {}
|
||||||
|
|
@ -223,10 +225,12 @@ resource "kubernetes_resource_quota" "user_namespace_quota" {
|
||||||
|
|
||||||
spec {
|
spec {
|
||||||
hard = {
|
hard = {
|
||||||
"requests.cpu" = each.value.quota.cpu_requests
|
"requests.cpu" = each.value.quota.cpu_requests
|
||||||
"requests.memory" = each.value.quota.memory_requests
|
"requests.memory" = each.value.quota.memory_requests
|
||||||
"limits.memory" = each.value.quota.memory_limits
|
"limits.memory" = each.value.quota.memory_limits
|
||||||
"pods" = each.value.quota.pods
|
"pods" = each.value.quota.pods
|
||||||
|
"requests.storage" = each.value.quota.storage_requests
|
||||||
|
"persistentvolumeclaims" = each.value.quota.persistentvolumeclaims
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue