The application definition and development layer on AWS
The application definition and development layer on AWS
The application definition and development layer on AWS
Four boxes: where state lives, how services talk asynchronously, how source becomes an image, and how that image reaches a cluster. The first two are AWS at its strongest — a managed service per access pattern, and the work is choosing. The last two are where an AWS-only answer starts costing you something real.
1. Database — nine services, one question each
The mistake is asking "which database should we use". The useful question is which access pattern each piece of state has, and AWS then names itself.
| the access pattern | service | the thing that decides it |
|---|---|---|
| relational, known query shapes | RDS (MySQL/PostgreSQL) | you want SQL and a single writer |
| relational, needs to survive an AZ badly | Aurora | storage is replicated 6 ways across 3 AZs; failover in seconds |
| key-value at any scale, known keys | DynamoDB | single-digit ms at any size — if you know the access pattern first |
| wide-column, time-ordered | Keyspaces (Cassandra) | you have Cassandra data models already |
| in-memory cache | ElastiCache | it may be lost |
| in-memory durable | MemoryDB | it may not be lost |
| document | DocumentDB | MongoDB API compatibility, not MongoDB |
| graph | Neptune | traversals, not joins |
| time series | Timestream | retention tiers and interpolation built in |
This repository's data layer makes four decisions and refuses one, and MySQL on AWS and NoSQL on AWS argue both halves — including the connection budget as a fleet property, the proxy setting whose documented range is one value, and the cache key that leaks across tenants if you build it the obvious way.
The DynamoDB caveat that costs people months: it is superb if the access pattern is known before the table is designed, and hostile if it is not. A secondary index is not a
WHERE clause you add later at no cost — it is a second copy of the data with its own capacity. Teams that model in DynamoDB the way they modelled in Postgres end up with a table they cannot query and a migration they cannot schedule.What has no AWS equivalent: a managed operator-shaped database inside the cluster. If your requirement is genuinely "the database must be a Kubernetes object", every AWS answer is outside the cluster and reached over the network, with credentials from Secrets Manager and identity from IRSA or Pod Identity. That is a better architecture and it is not what the requirement asked for.
2. Streaming and messaging — five services, one decision
| service | delivery | ordering | retention | the reason to pick it |
|---|---|---|---|---|
| SQS Standard | at-least-once | none | 14 days | the default queue; nothing else is simpler |
| SQS FIFO | exactly-once within a dedup window | per message group | 14 days | ordering matters and throughput is modest |
| SNS | at-least-once fan-out | none | none | one publisher, many independent subscribers |
| EventBridge | at-least-once | none | archive + replay | routing on content, with schemas and a registry |
| Kinesis Data Streams | at-least-once | per shard | up to 365 days | many consumers replaying the same ordered log |
| MSK (Kafka) | Kafka's | per partition | yours | you have Kafka consumers and want to keep them |
The decision underneath all of these is: does a consumer need to re-read? A queue is destructive — SQS deletes on ack, and a second consumer group is not a concept. A log is not — Kinesis and Kafka keep the record and each consumer holds its own offset. Choosing SQS for something that later needs a second independent reader is the migration nobody budgets for.
EventBridge is the one that is under-used. Content-based routing with a schema registry, an archive you can replay, and direct targets in ~20 services without a Lambda in the middle. For "when X happens, also do Y" it removes more code than anything else in the list. Kafka for an LLM works through where MSK still earns its place and where EventBridge or Kinesis is the smaller answer.
3. Application definition and image build — the weak box
This is where an AWS-only story is genuinely thin, and the page should say so.
Application definition. Helm, Kustomize, CDK8s and Timoni are all things you run. Kustomize is in
kubectl itself, which makes it the lowest-dependency answer, and it is what this repository uses (k8s/base + overlays, applied by make deploy). AWS Proton is the nearest managed shape — templates, versioned, with a platform-team/developer split — and it is a deployment product rather than a manifest templating one. There is no managed Helm.Image build is the real gap. To turn source into an image you need something that runs a build:
| approach | AWS-managed? | the catch |
|---|---|---|
| CodeBuild with Docker | yes | privileged mode, or BuildKit; you maintain the buildspec and the base image |
| CodeBuild + finch/BuildKit rootless | yes | better, still a build tool you configure |
| Kaniko / Buildah in-cluster | no | a pod you run, with cache and credential handling of your own |
| App Runner from source | yes | it builds for you — and only for its own runtime set |
| Lambda container images | yes (build elsewhere) | moves the problem, does not remove it |
There is no "push source, receive an OCI image" AWS service in the general case. App Runner comes closest and constrains the runtime; CodeBuild is a managed machine that runs your build, which is not the same as a managed build. This repository builds with
docker buildx in make push-multiarch and is honest that the toolchain is not a cloud choice — the inventory lists it.Multi-architecture matters here. Graviton nodes need
arm64 images, and a single-arch image on a mixed node group produces exec format error at runtime rather than a scheduling failure — the pod places fine and then dies. The manifest-list build is not optional on a mixed cluster, and the Spring on EKS page has the worked case.4. Continuous integration and delivery
| stage | AWS-managed | the alternative you would otherwise run |
|---|---|---|
| source | CodeCommit, or GitHub via CodeStar Connections | — |
| build | CodeBuild | Jenkins, GitHub Actions runners |
| artifact | ECR, CodeArtifact | Nexus, Artifactory |
| deploy | CodePipeline + CodeDeploy | Argo CD, Flux |
The honest split is push versus pull. CodePipeline pushes: it holds credentials to your cluster and runs
kubectl apply. Argo CD and Flux pull: a controller inside the cluster reconciles against Git, and no CI system needs cluster credentials at all. The pull model is better on credentials and better at drift, and there is no AWS-managed GitOps controller — Argo CD and Flux are software you run.That is the trade in one line: AWS-only delivery means push-based delivery, and push-based delivery means your CI system holds cluster credentials. CI/CD on AWS works through the six-stage pathway three ways, the deployment methods on Kubernetes, and how keyless credentials (OIDC into an IAM role, no long-lived access key) narrow the blast radius when you do push.
What this layer costs when it is AWS-only
| you lose | nearest AWS shape | how much it hurts |
|---|---|---|
| a managed GitOps controller | CodePipeline (push) | a lot if drift and credential-free deploys matter to you |
| a managed image build | CodeBuild running your build | moderate — it is a machine, not a service |
| a managed Helm/templating service | Proton, Kustomize in kubectl | small |
| in-cluster databases | every AWS database, over the network | none — this is an improvement |
Verified, and not
Read, not run. Service semantics — SQS FIFO's deduplication window, EventBridge's archive and replay, Kinesis retention — are from AWS documentation. Nothing was applied to an AWS account while writing this.
Checked against this repository. Kustomize overlays, the multi-arch build and the
exec format error failure mode are real here; the outbox that makes MySQL the source of truth is in search-platform/ and argued in MySQL on AWS .Not verified, and load-bearing. The claim that CodeBuild with rootless BuildKit removes the privileged-mode requirement is documentation-derived and untested here. If it is wrong, the image-build row above is worse than stated, not better — and that box is already the weakest in the layer.
Next: observability and analysis .
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article