A paved road. Four steps. The developer never runs kubectl. Everything goes through Git.
Clone the Reference MVP (dotnet-rds-iam-mvp). Copy the _templates/ folder structure for your infrastructure needs (eks-service, postgresql-logical, redis, ssm-parameter).
Create a feature branch. Copy templates to accounts/dev/us-east-1/services/eks/<namespace>/<your-service>/. Fill in placeholders. Open PR → auto-plan → merge → auto-apply.
Create clusters/dev/<namespace>/<your-service>.yaml Argo CD Application manifest. Push to main. Root App auto-discovers and deploys within 30 seconds.
Create azure-pipelines.yml in your app repo using the Conveyor CI template. A Classic Release pipeline handles promotion: Dev → QA → Prod. See Releases for the full architecture.
Infrastructure is DRY and self-service. Developers interact only with the top layer (_templates); _envcommon and modules are platform-managed.
| Template | Creates |
|---|---|
eks-service | IRSA role + K8s ServiceAccount + namespace |
postgresql-logical | Logical database + IAM-auth user on shared RDS |
redis | Dedicated ElastiCache Redis cluster |
ssm-parameter | Bulk app config in SSM Parameter Store |
secrets-manager | Skeleton secrets in AWS Secrets Manager (single or bulk mode). ARNs auto-published to SSM as _SECRET_ARN params. |
s3 | S3 bucket with encryption and tagging |
ecr | ECR repository with scanning enabled |
ec2 | EC2 instance with SSM, monitoring, logging |
Platform charts (api-workload, grpc-workload, worker-workload) provide bounded flexibility:
| Extension | How |
|---|---|
| Pod annotations / labels | podAnnotations: {}, podLabels: {} |
| Environment variables | additionalEnvVars: [{name: X, value: Y}] |
| Init containers | initContainers: [{name: wait-for-db, ...}] |
| Extra volumes / mounts | extraVolumes: [], extraVolumeMounts: [] |
| Scheduling | nodeSelector, topologySpreadConstraints |
| Network egress | networkPolicy: {enabled: true, rds: true, redis: true} |
securityContext — non-root enforced by KyvernoextraContainers — sidecars managed by platformhostPath — blocked by Kyverno| Error | Cause | Fix |
|---|---|---|
ImagePullBackOff | ECR image doesn't exist or wrong tag | Check ECR repo exists, verify image.tag in Argo CD manifest |
CrashLoopBackOff | App crashing at startup | kubectl logs <pod> --previous |
| Kyverno rejection | Policy violation (root, no limits, wrong registry) | Read the error — it tells you exactly which policy and what to fix |
ServiceAccount not found | Blueprint service infra not deployed in this environment | cd blueprint/accounts/<env>/us-east-1/services/<name> && terragrunt run-all apply — pod auto-recovers |
| Connection timeout to RDS | NetworkPolicy blocking egress (QA/Prod only) | Add networkPolicy.rds: true in values.yaml. In dev, set networkPolicy.enabled: false or a partial policy will block HTTPS. |
Argo CD root-app Unknown | SSH key for Ledger repo is empty / missing | Recreate ledger-repo-ssh secret in argocd ns, label as repository, restart argocd-repo-server |
App hangs after [Forge] .NET Env: ... | Pod can't reach AWS APIs (SSM) on port 443 | Check NetworkPolicies. If a partial egress policy blocks 443, disable in dev or rely on Kyverno auto-baseline in QA/Prod. |
| All pods recreated after EKS redeploy | Forgot to redeploy Blueprint service infra | Run terragrunt run-all apply on every services/<name>/ in that account |
| # | Step | Repo | What it does |
|---|---|---|---|
| 1 | Deploy service infrastructure | Blueprint | Logical database, Redis cache, SSM config, IRSA role + K8s ServiceAccount |
| 2 | Add Application YAML | Ledger | Argo CD discovers and deploys the pods (uses the ServiceAccount from Step 1) |