Use Your Component in a Stack
Atmos Stacks are the configuration for your components. It's how you can combine multiple reusable, stateful components into your "Stack" that you depend on.
If you think of your "components" as applications, then Stacks are simply which components you depend on and the settings that you want to pass to them. If you make your components highly reusable, it usually means they will need to accept a lot of configuration.
This is what makes Atmos so powerful: you can import and inherit configurations in a logical way to keep your configurations DRY and consistent.
You will learn
- How to specify the configuration for your Terraform "root modules" using Atmos Stacks
- How to organize Atmos Stacks into a Service Catalog
- How to use imports and inheritance for DRY configurations
- How Atmos identifies components using context variables and naming patterns
Stack configurations are merely all the settings for your components. They can be organized in any way you like, but we recommend a hierarchical layout. We share some different ways to organize your stacks in the Catalog, but for this example, we will use a simple layout.
Create Catalog for Reusable Configurations
Atmos supports the concept of a Service Catalog, which is where you can define all of your default configurations.
All the common default settings for each Atmos component should be in a separate file in the stacks/catalog
directory.
The file then gets imported into the parent Atmos stacks. This makes the stack configurations DRY by reusing the component's config that is common for all environments.
Refer to Stack Imports for more details on Atmos imports.
These Atmos component manifests will be imported into the top-level Atmos stacks. The default variables (in the vars
sections)
can be overridden in the derived Atmos components by using Atmos Component Inheritance.
Atmos Top-level Stacks
When executing the CLI commands, Atmos does not use the stack file names and their filesystem locations to search for the stack where the component is defined. Instead, Atmos uses the context variables (namespace
, tenant
, environment
, stage
) to search for the stack. The stack config file names (stack manifest names) can be anything, and they can be in any folder in any sub-folder in the stacks
directory.
For example, when executing the atmos terraform apply station -s dev
command, the Atmos stack dev
is specified by the -s
flag. By looking at name_pattern: "{stage}"
(see Configure CLI) and processing the tokens, Atmos knows that the stage
is dev
. This name_pattern
also supports {namespace}
, {tenant}
, and {environment}
.
{namespace}
- Corresponds to
var.namespace
in the stack configuration. {tenant}
- Corresponds to
var.tenant
in the stack configuration. {environment}
- Corresponds to
var.environment
in the stack configuration. {stage}
- Corresponds to
var.stage
in the stack configuration.
Atmos top-level stacks can be configured using a Basic Layout or a Hierarchical Layout.
The Basic Layout can be used when you have a very simple configuration using just a few stages. A more Hierarchical Layout should be used when you have a very complex organization, for example, with many AWS Organizational Units (which Atmos refers to as tenants) and dozens of AWS accounts and regions.
Basic Layout
A basic form of stack organization is to follow the pattern of naming where each $environment-$stage.yaml
is a file. This works well until you have so many environments and stages.
For example, $stage
might be prod
, which would result in stacks/deploy/prod.yaml
In our example, the filesystem layout for the stacks uses a Basic Layout with dev
, staging
and prod
and
would look like this:
infra-live/
Create Stack Configurations for Deployment
Since this is a simple Quick Start, we will just use a single Terraform component (components/terraform/weather
); in a real-world scenario, you may have dozens of components that comprise your stack. Rest assured, the process is the same for all components.
Define the Baseline Configuration
We’ll start by defining the baseline configuration of our Terraform root module to gather weather data. The name of our component’s configuration doesn’t need to match the name of the component folder. This allows us to deploy multiple instances of our component using different names.
components:
terraform:
<name-of-component>:
To specify which component to use, set the metadata.component
property to the path of the component's directory, relative to the components.base_path
as defined in the atmos.yaml
. In our case, the components.base_path
is components/terraform
, so we can simply specify weather
as the path.
components:
terraform:
station:
metadata:
component: weather
components/terraform/weather/v1
. The goal for maintainable infrastructure as code is to have as few versions as possible and to have all environments converge on the same version.So the complete baseline definition for our weather station configuration might look something like the following.
examples/quick-start-simple/stacks/catalog/station.yaml
0001
) in YAML to prevent them from being interpreted as integers. This is how YAML processes it, and not something special about Atmos.Define the Environment-specific Configurations
Next, we’ll define the environment-specific configurations for our Terraform root module. We’ll create a separate file for each environment and stage. In our case, we have three environments: dev
, staging
, and prod
.
When Atmos processes this stack config, it will first import and deep-merge all the variables from the imported files, then overlay the inline configuration. While the order of keys in a YAML map doesn’t affect behavior, lists are strictly ordered. Therefore, the order of imports
is important.
Define the dev
Environment Configuration
In the dev
stack configuration, Atmos first processes the imports
in the order defined. Then, it applies the globals vars
defined in the top-level section. Only include vars
in the globals that are true for every single component in the stack. If that's not the case, define them on a per-component basis.
For example, by setting var.stage
to dev
at a global level, we assume that every component in this stack will have a stage variable.
Finally, in the component-specific configuration for the station
, we set the fine-tuned parameters for this environment. Everything else gets inherited from its baseline configuration. There are no strict rules about where to place configurations. Organize them in a way that makes logical sense for your infrastructure’s data model.
examples/quick-start-simple/stacks/deploy/dev.yaml
Define the staging
Environment Configuration
The staging stack configuration is almost identical to the dev stack. The only changes are the location and language settings. Everything else stays the same as the baseline configuration, ensuring that the staging and dev environments are very similar.
examples/quick-start-simple/stacks/deploy/staging.yaml
Define the prod
Environment Configuration
And finally, we have the production (prod
) stack. Much like the staging
and dev
stacks, it’s very similar to the baseline configuration but with some parameter changes. In this setup, all three stacks are separate, share the same component, and vary the station's parameters as needed.
examples/quick-start-simple/stacks/deploy/prod.yaml
Now, we're finally ready to deploy our components. We'll show you how to do this in the next step.
Want to go deeper on this topic?
You can do so much more with stacks! We're just scratching the surface. If you want learn about imports, inheritance, templating, etc, check out the Core Concepts. Learn More