AWS → STACKIT · CASE STUDY
The AWS Retail Store sample, assessed end to end
The Retail Store Sample App from AWS Containers is a public estate with five services on Amazon ECS and five managed data services behind them. StackToIT read it unchanged: 282 resources, 44 migration units, none DIRECT. This walkthrough follows the package from its first number to the decisions that decide the project, and states plainly what the run does not establish.
Proven on a real AWS estate
The AWS Retail Store Sample App, a public Terraform project from AWS, assessed by StackToIT and published in full, exactly as the run wrote it.
View Case Study- 282
- Terraform resource declarations analyzed
- 44
- migration units identified
- 38
- target units generated, from 52 considered
- 331
- plan steps written
How to read the package
The order an architect would open the files in. Paths are relative to the output folder of the published run.
Start with the summary and the first blocker
index.html and executive/brief.md state the figures and name the first required action: allow calls to STACKIT APIs that are not generally available. Four steps wait for that answer.
Read the classes
assessment.json holds each unit with class, confidence and reason. Of 44 units, 34 are RECONFIGURE, 9 REPLATFORM and 1 REDESIGN. No unit is HIGH confidence, because the source provider is unpinned.
Take the decisions
executive/decisions.md counts 16 decisions to make: 9 plan decisions with named options, 5 manual actions and 2 plan statements; decisions.json holds the records. Among the plan decisions are data movement, the engine version downgrade, the ingress path and pod segmentation.
Follow the sequence
migration/technical-sequencing.md orders units into waves by dependency; migration/data-movement.md lists the six stateful units that need a method.
Open the draft
terraform/ holds 38 generated units. Every block carries comments for what was not carried, with a pointer into the engineering trace.
Work the manual steps
execution/manual/actions.md groups the manual work into packages with an owner, a condition for done, and a rollback line.
What the 44 units became
Present units only; eight more units depend on values OpenTofu decides at plan time and are counted separately.
| AWS source | STACKIT target | Class |
|---|---|---|
| Amazon ECS cluster and five services | STACKIT Kubernetes Engine (SKE) cluster | REPLATFORM (6 units) |
| Aurora clusters for catalog and orders | MariaDB (catalog) and PostgreSQL Flex (orders) | REPLATFORM (2 units) |
| OpenSearch domain | STACKIT OpenSearch | Replatform |
| DynamoDB table for carts | MongoDB Flex, or PostgreSQL JSONB as the other option | Redesign |
| ElastiCache replication group | Key Value Store (Valkey) | Reconfigure |
| Amazon MQ broker | STACKIT RabbitMQ | Reconfigure |
| Application Load Balancer | STACKIT Application Load Balancer | Reconfigure |
| 10 IAM roles | Service accounts with project role assignments | RECONFIGURE (10 units) |
| 12 security groups, VPC, NAT gateway, elastic IP | Security groups, networks, implicit outbound path | RECONFIGURE (15 units) |
| 4 secrets, one KMS key, one log group | Secrets Manager, KMS, a Logs instance | RECONFIGURE (6 units) |
By domain, the 44 units are 16 network, 15 identity, 6 compute, 5 data, 1 observability and 1 messaging.
Two data services, drafted side by side
Blocks from terraform/data.tf of the published run, without the comment lines above them. Left: the orders database, an Aurora cluster moved to PostgreSQL Flex. Right: the carts table, a DynamoDB table moved to MongoDB Flex as an alternative, not an equivalent.
resource "stackit_postgresflex_instance" "dependencies_orders_rds_this" {
project_id = var.project_id
name = "retail-store-ecs-orders"
version = "15"
flavor_id = "2.4"
storage = {
class = var.postgresflex_storage_class
size = var.orders_rds_storage_size
}
backup_schedule = "0 2 * * *"
network = {
acl = coalescelist(var.orders_rds_allowed_cidrs, stackit_ske_cluster.retail_app_ecs_cluster.egress_address_ranges)
access_scope = var.orders_rds_access_scope == "SNA" ? "SNA" : null
}
retention_days = 32
}resource "stackit_mongodbflex_instance" "dynamodb_tables" {
project_id = var.project_id
name = "dynamodb-tables"
acl = var.dynamodb_tables_allowed_cidrs
version = var.dynamodb_tables_version
flavor = {
cpu = var.dynamodb_tables_cpu
ram = var.dynamodb_tables_ram
}
replicas = 3
storage = {
class = var.mongodbflex_storage_class
size = var.dynamodb_tables_storage_gb
}
backup_schedule = "0 2 * * *"
options = {
type = "Replica"
point_in_time_window_hours = var.dynamodb_tables_pitr_hours
}
}Sizes derived from the source
The plan and flavor follow from the source’s size. The run raises a decision for it, with the default marked as unconfirmed.
Access lists
The orders database admits the cluster’s outbound address ranges unless you supply CIDRs, so the database block depends on the cluster resource.
DynamoDB is a redesign
Key design, capacity modes, streams and conditional writes do not carry over. The data access layer is rewritten against the MongoDB API, and the data moves by export and import.
Compute and logging
The cluster that replaces the ECS services and the Logs instance for the task logs. The cluster’s node pool sizes are variables.
resource "stackit_ske_cluster" "retail_app_ecs_cluster" {
project_id = var.project_id
name = "reta-7b7ce2"
node_pools = [{
name = "workloads"
machine_type = var.cluster_machine_type
minimum = var.cluster_nodes_min
maximum = var.cluster_nodes_max
availability_zones = var.availability_zones
}]
}resource "stackit_logs_instance" "logs_retention_180d" {
project_id = var.project_id
display_name = "logs-retention-180d"
retention_days = 180
}The workloads are manifests
terraform/kubernetes/ holds a manifest set per service. The cluster’s outbound address ranges are computed, so the managed services’ access lists wait for them.
180 days is the ceiling
The source log group keeps its logs for ever, which a Logs instance cannot do. The run states that older logs are not kept and raises the archive decision.
The decisions that decide the project
How the data moves
Six stateful units need a method: export and import, engine replication or an own tool. The source states no size, change rate or tolerated downtime, so the run chooses no mechanism.
Catalog on OpenSearch
The catalog service depends on OpenSearch 3.3 while the region offered version 2. Options: move the data into the offered version 2, run the engine yourself on SKE, or wait. Until then the application is blocked.
Carts and checkout
DynamoDB has no counterpart, so the services that use it need code changes. Checkout also shares the TLS-only Valkey endpoint.
Ingress path
Keep a NodePort with the load balancer on node IPs, run an ingress controller, or use the load balancer extension for SKE. Each changes what your team operates.
Pod segmentation
Security groups at node level are coarser than the source’s per-service groups. NetworkPolicies are written by a person.
Public endpoints and fixed egress
Managed services default to public endpoints behind access lists. The NAT gateway’s fixed address is lost unless servers get their own public IP.
What this run does not establish
Stated by the run itself, not added afterwards.
The source was not validated
The upstream estate has no provider lock file, so OpenTofu validation of the source did not run and every unit is capped at MEDIUM confidence.
Nothing was planned or applied on STACKIT
The draft passed static validation against the provider schema. No plan ran against a live project, and no unit is cleared for automation.
No cost comparison
The source names no AWS region, so no AWS price was fetched. Five of fourteen STACKIT lines are priced, which is a partial figure and not a saving.
No application is ready
Zero of five applications are ready: catalog is blocked, carts and checkout need a redesign, and orders and ui are not ready because environment values or the workload identity are still open.
Questions about this case study
Is the Retail Store estate edited?
No. The run assessed the ECS Terraform root as published upstream, together with the local modules it calls. The source code is not republished; the linked repository holds it.
Why is nothing DIRECT?
Every present unit needs at least a configuration change, such as identity, networks or endpoints. The nearest to a lift is the group of RECONFIGURE units.
How many steps does the plan contain?
331 plan steps: 53 OpenTofu steps, 4 STACKIT API steps behind an opt-in, 272 manual steps and 2 refused. None of the 57 automated steps runs as written: 48 are free of decisions and manual prerequisites, and all 48 wait for a value such as the project ID.
Can I check the package myself?
Yes. The output is published unchanged with its manifest, and the verify step confirms that all 145 files match it by size and SHA-256. For your own estate, an assessment of its Terraform produces the same kind of package.
Sources
Your next move: STACKIT.
Tell us about your estate. We show you what StackToIT delivers for it: target architecture, Terraform artifacts and a structured migration plan.