Layered Stack Configuration
The Layered Stack Configuration Design Pattern describes the mechanism of grouping Atmos components by category or function, adding the groups of components to layers, and importing the layers into top-level Atmos stacks.
Each layer imports or configures a set of related Atmos components. Each Atmos component belongs to just one layer. Each layer can be managed separately, possibly by different teams.
The Layered Stack Configuration Design Pattern works around the limitations of the Partial Stack Configuration pattern. Instead of splitting the top-level Atmos stacks into parts, the Layered Stack Configuration pattern adds separate layers to group the related Atmos components by category, and then import the layer manifests into the top-level Atmos stacks.
Use-cases
Use the Layered Stack Configuration pattern when:
-
You have many Atmos components, and you need to group the components by category or function
-
You want to split the components into layers. Each layer should be managed and modified independent of the other layers, possibly by different people or teams
-
You want to keep the configuration easy to manage and DRY
Benefits
The Layered Stack Configuration pattern provides the following benefits:
-
Allows to group Atmos components by category or function
people or teams. Furthermore, controls like GitHub's
CODEOWNERS
can be leveraged so that specific teams or individuals must review changes to these files. -
Allows importing only the required layers into the top-level stacks (only the groups of components that need to be provisioned in the stacks)
-
Makes the configurations easier to understand
Example
In the following structure, we have various Terraform components (Terraform root modules) in the components/terraform
folder.
In the stacks/catalog
folder, we define the defaults for each component using the Component Catalog Atmos
Design Pattern.
In the stacks/layers
folder, we define layers (groups of components), and import the related components into the layer manifests:
load-balancers.yaml
data.yaml
dns.yaml
logs.yaml
notifications.yaml
firewalls.yaml
networking.yaml
eks.yaml
│ # Centralized stacks configuration (stack manifests)
├── stacks
│ ├── catalog # component-specific defaults
│ │ ├── alb
│ │ │ └── defaults.yaml
│ │ ├── aurora-postgres
│ │ │ └── defaults.yaml
│ │ ├── dns
│ │ │ └── defaults.yaml
│ │ ├── eks
│ │ │ └── defaults.yaml
│ │ ├── efs
│ │ │ └── defaults.yaml
│ │ ├── msk
│ │ │ └── defaults.yaml
│ │ ├── ses
│ │ │ └── defaults.yaml
│ │ ├── sns-topic
│ │ │ └── defaults.yaml
│ │ ├── network-firewall
│ │ │ └── defaults.yaml
│ │ ├── network-firewall-logs-bucket
│ │ │ └── defaults.yaml
│ │ ├── waf
│ │ │ └── defaults.yaml
│ │ ├── vpc
│ │ │ └── defaults.yaml
│ │ └── vpc-flow-logs-bucket
│ │ └── defaults.yaml
│ ├── layers # grouping of components by category/function
│ │ ├── load-balancers.yaml
│ │ ├── data.yaml
│ │ ├── dns.yaml
│ │ ├── logs.yaml
│ │ ├── notifications.yaml
│ │ ├── firewalls.yaml
│ │ ├── networking.yaml
│ │ └── eks.yaml
│ ├── mixins
│ │ ├── tenant # tenant-specific defaults
│ │ │ └── plat.yaml
│ │ ├── region # region-specific defaults
│ │ │ ├── us-east-2.yaml
│ │ │ └── us-west-2.yaml
│ │ └── stage # stage-specific defaults
│ │ ├── dev.yaml
│ │ ├── staging.yaml
│ │ └── prod.yaml
│ └── orgs # Organizations
│ └── acme
│ ├── _defaults.yaml
│ └── plat # 'plat' represents the "Platform" OU (a.k.a tenant)
│ ├── _defaults.yaml
│ ├── dev
│ │ ├── _defaults.yaml
│ │ ├── global-region.yaml
│ │ ├── us-east-2.yaml
│ │ └── us-west-2.yaml
│ ├── staging
│ │ ├── _defaults.yaml
│ │ ├── global-region.yaml
│ │ ├── us-east-2.yaml
│ │ └── us-west-2.yaml
│ └── prod
│ ├── _defaults.yaml
│ ├── global-region.yaml
│ ├── us-east-2.yaml
│ └── us-west-2.yaml
│ # Centralized components configuration
└── components
└── terraform # Terraform components (a.k.a Terraform "root" modules)
├── alb
├── aurora-postgres
├── dns
├── eks
├── efs
├── msk
├── ses
├── sns-topic
├── network-firewall
├── network-firewall-logs-bucket
├── waf
├── vpc
└── vpc-flow-logs-bucket
Add the following minimal configuration to atmos.yaml
CLI config file :
components:
terraform:
base_path: "components/terraform"
stacks:
base_path: "stacks"
name_pattern: "{tenant}-{environment}-{stage}"
included_paths:
# Tell Atmos to search for the top-level stack manifests in the `orgs` folder and its sub-folders
- "orgs/**/*"
excluded_paths:
# Tell Atmos that the `defaults` folder and all sub-folders don't contain top-level stack manifests
- "defaults/**/*"
schemas:
jsonschema:
base_path: "stacks/schemas/jsonschema"
opa:
base_path: "stacks/schemas/opa"
atmos:
manifest: "stacks/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json"
Add the following configuration to the stacks/layers/load-balancers.yaml
layer manifest:
import:
# Import the related component manifests into this layer manifest
- catalog/alb/defaults
# Import other Load Balancer components
Add the following configuration to the stacks/layers/data.yaml
layer manifest:
import:
# Import the related component manifests into this layer manifest
- catalog/aurora-postgres/defaults
- catalog/msk/defaults
- catalog/efs/defaults
# Import other Data components
Add the following configuration to the stacks/layers/dns.yaml
layer manifest:
import:
# Import the related component manifests into this layer manifest
- catalog/dns/defaults
# Import other DNS components
Add the following configuration to the stacks/layers/logs.yaml
layer manifest:
import:
# Import the related component manifests into this layer manifest
- catalog/network-firewall-logs-bucket/defaults
- catalog/vpc-flow-logs-bucket/defaults
# Import other Logs components
Add the following configuration to the stacks/layers/notifications.yaml
layer manifest:
import:
# Import the related component manifests into this layer manifest
- catalog/ses/defaults
- catalog/sns-topic/defaults
# Import other Notification components
Add the following configuration to the stacks/layers/firewalls.yaml
layer manifest:
import:
# Import the related component manifests into this layer manifest
- catalog/network-firewall/defaults
- catalog/waf/defaults
# Import other Firewall components
Add the following configuration to the stacks/layers/networking.yaml
layer manifest:
import:
# Import the related component manifests into this layer manifest
- catalog/vpc/defaults
# Import other Networking components
Add the following configuration to the stacks/layers/eks.yaml
layer manifest:
import:
# Import the related component manifests into this layer manifest
- catalog/eks/defaults
Import the required layers into the stacks/orgs/acme/plat/dev/us-east-2.yaml
top-level stack manifest:
import:
# The `orgs/acme/plat/dev/_defaults` and `mixins/region/us-east-2` manifests
# define the top-level Atmos stack `plat-ue2-dev`
- orgs/acme/plat/dev/_defaults
- mixins/region/us-east-2
# Import the layers (groups of components)
- layers/load-balancers
- layers/data
- layers/dns
- layers/logs
- layers/notifications
- layers/firewalls
- layers/networking
- layers/eks
Import the required layers into the stacks/orgs/acme/plat/dev/us-west-2.yaml
top-level stack manifest:
import:
# The `orgs/acme/plat/dev/_defaults` and `mixins/region/us-west-2` manifests
# define the top-level Atmos stack `plat-uw2-dev`
- orgs/acme/plat/dev/_defaults
- mixins/region/us-west-2
# Import the layers (groups of components)
- layers/load-balancers
- layers/data
- layers/dns
- layers/logs
- layers/notifications
- layers/firewalls
- layers/networking
- layers/eks
Import the required layers into the stacks/orgs/acme/plat/prod/us-east-2.yaml
top-level stack manifest:
import:
# The `orgs/acme/plat/prod/_defaults` and `mixins/region/us-east-2` manifests
# define the top-level Atmos stack `plat-ue2-prod`
- orgs/acme/plat/prod/_defaults
- mixins/region/us-east-2
# Import the layers (groups of components)
- layers/load-balancers
- layers/data
- layers/dns
- layers/logs
- layers/notifications
- layers/firewalls
- layers/networking
- layers/eks
Similarly, import the required layers into the other top-level stacks for the other organizations, OUs/tenants, accounts and regions. Make sure to import only the layers that define the component that need to be provisioned in the stacks.