natron-deployment
| Type | Skill |
| Plugin | awl-cicd · v0.0.22 |
| Invoke | /awl-cicd:natron-deployment |
| Tools | Read, Write, Edit, Bash, Glob, Grep |
| Source | plugins/awl-cicd/skills/natron-deployment/SKILL.md |
When Claude uses it
Abschnitt betitelt „When Claude uses it“This skill should be used when the user asks to “add a database”, “postgres for the app”, “pgvector”, “S3 storage”, “persistent volume”, “basic auth on staging”, “custom domain”, “expose only via teleport”, “deploy frontend and backend from one repo”, “rotate secret”, “argocd out of sync”, “delete a deployment”, or “deploy to customer cluster”. Provisions and operates cluster-side resources for an app on the AWL Natron Kubernetes cluster: shared PostgreSQL via pgAdmin, S3 on flow.swiss, persistent volumes, ingress basic auth, Teleport-only endpoints, custom domains, monorepo multi-app deploys, ArgoCD operations. For the CI deploy job and DEPLOYMENT_VALUES basics use deploying-to-kubernetes.
Trigger phrases: add a database · postgres for the app · pgvector · S3 storage · persistent volume · basic auth on staging · custom domain · expose only via teleport · deploy frontend and backend from one repo · rotate secret · argocd out of sync · delete a deployment · deploy to customer cluster
Definition
Abschnitt betitelt „Definition“Pipeline setup, DEPLOYMENT_VALUES basics, the pre-merge checklist, and branch-to-environment mapping live in the deploying-to-kubernetes skill. Read that first if the app has no deploy job yet.
No local cluster access exists by default. kubectl works only through Teleport Connect (tsh login --proxy=teleport.awl.k8s.natron.cloud). Anything that needs ArgoCD write permission, namespace deletion, or a database extension is a DevOps request (Slack #tools-autodeploy).
Database (shared PostgreSQL)
Abschnitt betitelt „Database (shared PostgreSQL)“| Environment | pgAdmin | Host from inside the cluster |
|---|---|---|
| Staging | https://pgadmin.staging.appswithlove.net/ | postgres17.postgres:5432 |
| Production | https://pgadmin.prod.appswithlove.net/ | postgres17.postgres:5432 |
pgAdmin credentials are in 1Password. Steps, done by a human in pgAdmin:
- Login/Group Roles → create a role, enable “Can login”, set a password. Use
openssl rand -hex 32; characters like/,+,=break connection URIs. - Databases → create a database with that role as owner. Use the same name for role and database.
- Store the password as a GitLab CI variable (masked, scope
*).
DEPLOYMENT_VALUES: | configmap: DB_HOST: postgres17.postgres DB_PORT: "5432" DB_USER: "my-db" DB_DATABASE: "my-db" gitlabSecrets: DB_PASS: DB_PASSWORDPayload projects need only DATABASE_URI.
Constraints of the shared instance:
- It runs a PostGIS image (
postgis/postgis:17-*).pgvectoris not installed andCREATE EXTENSIONneeds superuser. Both are DevOps tickets; never propose swapping the instance image, it would break PostGIS for every other project. wal_level=logicalis already set (needed for PowerSync replication). A replication role needsREPLICATION BYPASSRLS LOGINplusGRANT SELECTper table, granted by a human in pgAdmin.- The instance is shared. Restarts by DevOps hit every project (
57P01 admin shutdown, thenECONNREFUSEDfor a few minutes). - No SSL enforcement on the internal connection.
S3 storage
Abschnitt betitelt „S3 storage“Object storage is flow.swiss S3. Create an access key pair in the flow.swiss console (credentials in 1Password), store both as CI variables.
# stagingDEPLOYMENT_VALUES: | configmap: S3_HOST: https://os.alp1.flow.swiss gitlabSecrets: S3_KEY: S3_KEY S3_SECRET: S3_SECRET
# productionDEPLOYMENT_VALUES: | configmap: S3_HOST: https://os.zrh1.flow.swiss gitlabSecrets: S3_KEY: S3_KEY S3_SECRET: S3_SECRETDon’t add the gitlabSecrets mapping before the variables exist; a missing variable makes ArgoCD red. Prefer S3 over persistent volumes for uploads and anything larger than config files.
Persistent volume
Abschnitt betitelt „Persistent volume“DEPLOYMENT_VALUES: | volumes: uploads: path: /app/uploads size: 1Gi type: pvcVolumes survive stop jobs and redeploys. Copying files in or fixing permissions (the app runs as UID 1000) requires kubectl cp or a helper pod via Teleport; the recipes are in references/TEMPLATES.md.
Basic auth
Abschnitt betitelt „Basic auth“Generate the htpasswd line and escape $ as $$$$ (GitLab expands $):
docker run --rm -ti backplane/htpasswd -nb '<user>' '<pass>' | sed 's/\$/$$$$/g'DEPLOYMENT_VALUES: | ingress: password: <htpasswd-output>This protects the whole ingress. Paths can’t be excluded.
Teleport-only endpoint
Abschnitt betitelt „Teleport-only endpoint“For internal tools that must not be public:
DEPLOYMENT_VALUES: | teleport: enabled: true name: my-admin-tool # optional description: Admin UI # optional ingress: enabled: false # public ingress is on by defaultThe app appears in the Teleport of the matching cluster after a few minutes.
Custom domain
Abschnitt betitelt „Custom domain“Set DEPLOYMENT_DOMAIN on the deploy job. Domains outside *.staging|testing|prod.appswithlove.net need a DNS record pointing at the cluster ingress first (Operation Manuals → Natron.io → HTTP Ingress & SSL in ClickUp). Let’s Encrypt issues the certificate automatically once the domain resolves; certificate errors show up in ArgoCD.
Customer cluster
Abschnitt betitelt „Customer cluster“Autodeploy can target external clusters that DevOps registered in ArgoCD:
deploy-main-branch: variables: DEPLOYMENT_CLUSTER: "customer-cluster-name"Monorepo support
Abschnitt betitelt „Monorepo support“include: - component: $CI_SERVER_FQDN/devops/ci-cd-templates/deploy-default-branches@main inputs: app-dir: frontend # no trailing slash app-suffix: -frontend - component: $CI_SERVER_FQDN/devops/ci-cd-templates/deploy-default-branches@main inputs: app-dir: backend app-suffix: -backend watch: - packages/shared/**/*
deploy-main-branch-frontend: variables: DEPLOYMENT_DOMAIN: app.example.com
deploy-main-branch-backend: variables: DEPLOYMENT_DOMAIN: api.example.comEach include creates its own build-docker-<suffix> and deploy-*-<suffix> jobs, image tags main-frontend etc., and environments staging-frontend etc. Jobs run only when their app-dir or a watch path changed.
Side services
Abschnitt betitelt „Side services“Redis or Meilisearch next to the app: deploy-service template with service-name and preset. Details in gitlab-cicd/references/templates/deploy.md.
ArgoCD operations
Abschnitt betitelt „ArgoCD operations“| Environment | URL |
|---|---|
| Staging | https://argocd.teleport.awl-staging.k8s.natron.cloud/ |
| Production | https://argocd.teleport.awl.k8s.natron.cloud/ |
Both need a Teleport account and an ArgoCD account. Application name: <DEPLOYMENT_NAME>-<namespace>-<cluster>.
- Force refresh: click Refresh on the application.
- Logs / shell: pod → context menu → Logs or Exec.
- Last deploy time: creation time of the pod.
- Error details: click Sync failed, not the error counter.
- Rotate a secret: update the GitLab variable, then delete the ExternalSecret (same name as the deployment). ArgoCD recreates it with the new value. Deleting needs ArgoCD write permission; without it, change the
gitlabSecretsmapping to force a new fetch. - Pause:
replicas: 0inDEPLOYMENT_VALUES. - Stop an environment: manual
stop-*-branchjob in the pipeline. Removes the app, keeps volumes. - Delete for good (wrong name, wrong namespace, renamed app): DevOps only, via
#tools-autodeploy. A renamed app leaves the old one running.
Default values
Abschnitt betitelt „Default values“DEPLOYMENT_NAME: ${CI_PROJECT_NAME}DEPLOYMENT_NAMESPACE: ${CI_PROJECT_NAMESPACE}DEPLOYMENT_CLUSTER: in-clusterDEPLOYMENT_DOMAIN: ${CI_PROJECT_PATH_SLUG}.<env>.appswithlove.netDEPLOYMENT_IMAGE: ${CI_REGISTRY_IMAGE}:${CI_COMMIT_REF_SLUG}DEPLOYMENT_VALUES: replicas: 1 port: 80 healthz: / resources: requests: { memory: 96Mi } limits: { memory: 256Mi } ingress: enabled: true className: nginx-external annotations: nginx.ingress.kubernetes.io/proxy-body-size: "0" nginx.ingress.kubernetes.io/proxy-buffer-size: "128k" nginx.ingress.kubernetes.io/proxy-buffers-number: "4" cert-manager.io/cluster-issuer: letsencrypt-http01Reference
Abschnitt betitelt „Reference“- Full DEPLOYMENT_VALUES options, PVC operations, ArgoCD CLI
- Complete working examples
- ClickUp: Natron Deployment guide (Apps with love Wiki), Operation Manuals → Natron.io

