204 lines
7.5 KiB
Markdown
204 lines
7.5 KiB
Markdown
# Skill — `onboard-app`
|
||
|
||
> **Layer:** Layer 1 — agent generates diff(s) and opens PR(s); humans review and Sync.
|
||
> **Scope:** the slice that lives in `devops-infra-helm-charts`. The matching Argo `Application` slice is in `github.com/Meesho/devops-infra-argo-config` and is paired but separate.
|
||
|
||
This skill is the agent-callable form of [docs/platform/procedures/onboard-app-to-cluster.md](../../docs/platform/procedures/onboard-app-to-cluster.md).
|
||
|
||
---
|
||
|
||
## When to use
|
||
|
||
Triggers like:
|
||
|
||
- "Onboard `<app>` to `<cluster>`."
|
||
- "Add a `kube-state-metrics` override for `k8s-foo-prd-ase1`."
|
||
- "Bring up `external-dns` on the new cluster."
|
||
|
||
Do **not** use this skill for:
|
||
|
||
- Adding a brand-new cluster (use the `onboard-new-cluster` procedure).
|
||
- Bumping a chart's version (use `bump-chart-version`).
|
||
- Migrating a chart blue-green (use the `blue-green-chart-migration` procedure directly).
|
||
|
||
---
|
||
|
||
## Input
|
||
|
||
Required:
|
||
|
||
```yaml
|
||
app: <chart-name> # must exist in helm-templates/
|
||
target_cluster: <cluster-folder> # must exist in helm-overrides/
|
||
release_name: <name> # often == app
|
||
workload_namespace: <ns> # the K8s namespace pods run in
|
||
image_tag: <tag> # NEVER 'latest'
|
||
resources:
|
||
cpu_request: <e.g. 250m>
|
||
memory_request: <e.g. 512Mi>
|
||
cpu_limit: <e.g. 1>
|
||
memory_limit: <e.g. 2Gi>
|
||
node_pool_key: <e.g. dedicated OR cloud.google.com/compute-class>
|
||
node_pool_value: <e.g. monitoring OR monitoring-cc>
|
||
```
|
||
|
||
Optional:
|
||
|
||
```yaml
|
||
needs_external_dns: <bool> # if true, add a Service to external-dns-services/
|
||
needs_external_secret: <bool> # if true, add an ExternalSecret to external-secrets/
|
||
needs_compute_class: <bool> # if true (Autopilot), add a ComputeClass under computeclass/
|
||
replicas: <N or autoscaling-block>
|
||
persistence:
|
||
enabled: <bool>
|
||
storage_class: <name> # MUST exist in manifests/storageclass/
|
||
size: <e.g. 100Gi>
|
||
```
|
||
|
||
---
|
||
|
||
## Steps (deterministic)
|
||
|
||
1. **Verify pre-conditions.**
|
||
```bash
|
||
ls helm-templates/<app>/Chart.yaml # chart exists
|
||
ls helm-overrides/<target_cluster>/ # cluster exists
|
||
! ls helm-overrides/<target_cluster>/<app>/ # app not already onboarded here
|
||
ls manifests/storageclass/<storage_class>.yaml # if persistence.enabled
|
||
```
|
||
|
||
2. **Read the cluster's scheduling profile.** Sample a sibling app on the **same** cluster:
|
||
```bash
|
||
ls helm-overrides/<target_cluster>/ | grep -v '^contour' | head -3
|
||
yq e '.nodeSelector' helm-overrides/<target_cluster>/<sibling>/custom-values.yaml
|
||
```
|
||
Confirm the agent's `node_pool_key` matches the cluster's actual style (`dedicated:` vs `cloud.google.com/compute-class:`). Mismatch → **fail fast** and ask.
|
||
|
||
3. **Generate `helm-overrides/<target_cluster>/<app>/custom-values.yaml`.** Use this template:
|
||
|
||
```yaml
|
||
image:
|
||
registry: asia-southeast1-docker.pkg.dev
|
||
repository: meesho-devops-admin-0622/admin/sre/<app>
|
||
tag: <image_tag>
|
||
pullPolicy: IfNotPresent
|
||
|
||
replicaCount: <replicas-or-omit-if-autoscaling>
|
||
|
||
resources:
|
||
requests:
|
||
cpu: <cpu_request>
|
||
memory: <memory_request>
|
||
limits:
|
||
cpu: <cpu_limit>
|
||
memory: <memory_limit>
|
||
|
||
nodeSelector:
|
||
<node_pool_key>: <node_pool_value>
|
||
tolerations:
|
||
- key: <node_pool_key>
|
||
value: <node_pool_value>
|
||
effect: NoSchedule
|
||
|
||
# if persistence.enabled
|
||
persistence:
|
||
enabled: true
|
||
storageClass: <storage_class>
|
||
size: <size>
|
||
accessModes: [ReadWriteOnce]
|
||
```
|
||
|
||
4. **(If `needs_external_dns: true`)** Generate `helm-overrides/<target_cluster>/<app>/external-dns-services/<svc>.yaml` per [raw-manifest-sidecar-schema.md §Service for external-dns binding](../../docs/platform/schemas/raw-manifest-sidecar-schema.md). Sample a sibling cluster's pattern.
|
||
|
||
5. **(If `needs_external_secret: true`)** Generate an `ExternalSecret` under `helm-overrides/<target_cluster>/external-secrets/`. Verify the cluster has a `SecretStore` / `ClusterSecretStore` (sample sibling apps' `existingSecret:` references).
|
||
|
||
6. **(If `needs_compute_class: true`)** Generate `helm-overrides/<target_cluster>/<app>/computeclass/<node_pool_value>.yaml`. The `metadata.name` MUST equal `<node_pool_value>`.
|
||
|
||
7. **Validate.**
|
||
```bash
|
||
yamllint helm-overrides/<target_cluster>/<app>/custom-values.yaml
|
||
helm template <release_name> helm-templates/<app> \
|
||
-f helm-overrides/<target_cluster>/<app>/custom-values.yaml > /dev/null
|
||
```
|
||
Render must succeed. If it errors, fail and surface the error.
|
||
|
||
8. **Open the PR.**
|
||
```bash
|
||
git checkout -b onboard/<app>-on-<target_cluster>
|
||
git add helm-overrides/<target_cluster>/<app>/
|
||
git commit -m "Onboard <app> to <target_cluster>"
|
||
git push origin onboard/<app>-on-<target_cluster>
|
||
gh pr create --base main --title "Onboard <app> to <target_cluster>"
|
||
```
|
||
|
||
PR body (use a heredoc):
|
||
|
||
```markdown
|
||
## Summary
|
||
Onboards `<app>` to `<target_cluster>`.
|
||
|
||
- Procedure: `docs/platform/procedures/onboard-app-to-cluster.md`
|
||
- Skill: `skills/infra/onboard-app.md`
|
||
- Sister-repo PR: <link to devops-infra-argo-config PR or "TBD">
|
||
|
||
## Validation
|
||
- `yamllint` passed
|
||
- `helm template` rendered cleanly
|
||
- Scheduling profile verified against sibling apps on `<target_cluster>`
|
||
|
||
## Approvers
|
||
- App owner: <handle>
|
||
- Cluster owner: <handle>
|
||
|
||
## CMR
|
||
<ticket or "n/a">
|
||
```
|
||
|
||
---
|
||
|
||
## Output
|
||
|
||
A single PR diff containing 1–3+ new files in this repo:
|
||
|
||
- `helm-overrides/<target_cluster>/<app>/custom-values.yaml`
|
||
- (optional) `helm-overrides/<target_cluster>/<app>/external-dns-services/<svc>.yaml`
|
||
- (optional) `helm-overrides/<target_cluster>/<app>/computeclass/<name>.yaml`
|
||
- (optional) `helm-overrides/<target_cluster>/external-secrets/<name>.yaml`
|
||
|
||
The skill does **not**:
|
||
|
||
- Open the sister-repo PR (separate skill / manual). It must be drafted by the user or a follow-up step.
|
||
- Run `argocd app sync` (Layer 1 boundary).
|
||
- Modify `helm-templates/<chart>/`.
|
||
- Modify `repository.yaml`.
|
||
|
||
---
|
||
|
||
## Pattern reference
|
||
|
||
A clean recent onboarding to compare against: pick any merged PR titled "Onboard ... to k8s-...". `git log --oneline --grep='Onboard' -i | head -10`.
|
||
|
||
---
|
||
|
||
## Gotchas
|
||
|
||
1. **Don't copy a sibling cluster's values verbatim** — per-cluster scheduling differs ([SANCTITY_RULES R5](../../docs/global/SANCTITY_RULES.md)).
|
||
2. **Don't set `automated.{prune,selfHeal}` in the sister-repo Application** ([ADR-A5](../../wiki/analyses/ADR-A5-manual-sync-default-for-infra.md)).
|
||
3. **Verify `image.tag`** is real before opening the PR — Argo CD only catches a missing tag at sync time.
|
||
4. **The release name (`metadata.name` of the resulting `Application`) is set in the sister repo, not here.** Don't assume it; verify with the user.
|
||
5. **For Contour**, always cross-reference [contour-nodeselector-tolerations-summary.md](../../contour-nodeselector-tolerations-summary.md) — the matrix is load-bearing.
|
||
|
||
---
|
||
|
||
## Layer constraint
|
||
|
||
Layer 1. Open the PR; do not merge it; do not Sync. Reviewer + sister-repo PR + Argo CD UI Sync click are the human gates.
|
||
|
||
---
|
||
|
||
## Related
|
||
|
||
- Procedure: [onboard-app-to-cluster.md](../../docs/platform/procedures/onboard-app-to-cluster.md).
|
||
- Schema: [custom-values-schema.md](../../docs/platform/schemas/custom-values-schema.md).
|
||
- Boundaries: [AGENT_BOUNDARIES.md](../../docs/global/AGENT_BOUNDARIES.md).
|