Skip to content

Commit f5fe373

Browse files
Gowiemosterman
andauthored
First tutorial for Atmos (#530)
* fix: fixes geodesic tut codeblock markdown final backticks * feat: adds first cut at atmos tutorial * fix: updates a number of small wording items after first read through * feat: updates h3 (###) to be a stylized a bit more usefully * chore: applies suggestions from Erik's code review Co-authored-by: Erik Osterman (CEO @ Cloud Posse) <erik@cloudposse.com> * Update content/tutorials/atmos-getting-started.md Co-authored-by: Erik Osterman (CEO @ Cloud Posse) <erik@cloudposse.com>
1 parent 7f26877 commit f5fe373

File tree

4 files changed

+274
-3
lines changed

4 files changed

+274
-3
lines changed

content/fundamentals/philosophy.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ SweetOps breaks down cloud infrastructure into 4 discrete layers:
4040

4141
We delineate between these layers as they have different Software Development Life Cycles (SDLC) and tools that are responsible for managing them. For example, Terraform is great for building your Foundation layer, but other tools might be better for managing the continuous delivery of the Application layer (e.g. ArgoCD). It's also important to note that each layer builds on the previous and the lower layers are less likely to change over time. At the bottom, you won't frequently change your AWS accounts and VPCs in your Foundation layer, just like when operating a platform you won't be rebuilding EKS clusters in your Platform layer without disrupting all tenants of the platform. You might, however, add HashiCorp Vault to your Shared Services layer to increase your security posture or add a new API microservice to your Application layer. The Application Layer is ultimately the most important layer of them all: it's what drives your business. It's where your applications live, which is why it will change continuously.
4242

43-
## Optimize for Day 2+ Operations
43+
## Optimize for Day 2 Operations
4444

4545
One important part we emphasize within SweetOps is that we optimize the methodology for [day 2+ operations](https://dzone.com/articles/defining-day-2-operations) and not the cold-start. The process to create the bottom layers of your platform is day 1 or your cold-start process. You will generally only perform a cold-start once so it's not logical or economical to focus on agility in this phase of building the platform. Instead, SweetOps focuses on optimizing the processes that come after your cold-start: GitOps, release engineering, monitoring/SRE, and ensuring your applications run efficiently on top of the base platform.
4646

Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
---
2+
title: "Getting started with Atmos"
3+
description: "Learn what Atmos is and how you can start using it with stacks to simplify your DevOps Automation tasks."
4+
weight: 2
5+
---
6+
7+
## Intro
8+
9+
`atmos` is part of the SweetOps toolchain and was built to make DevOps and Cloud automation easier across multiple tools. It has direct support for automating Terraform, Helm, Helmfile, and Istio. By natively utilizing [stacks]({{< relref "fundamentals/concepts.md#stacks" >}}), `atmos` enables you to effortlessly manage your Terraform and Helmfile [components]({{< relref "fundamentals/concepts.md#components" >}}) from your local machine or in your CI/CD pipelines.
10+
11+
In this tutorial we'll be looking at a simple (albeit contrived) example of automating multiple Terraform components together into a workflow. This will give you some understanding of what `atmos` can do while also giving you some experience with using it at the command line.
12+
13+
## Prerequisites
14+
15+
### Requirements
16+
17+
To accomplish this tutorial, you'll need to have [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) and [Docker](https://docs.docker.com/get-docker/) installed on your local machine. **That's all**.
18+
19+
### Understanding
20+
21+
Prior to starting this tutorial, you should be sure you understand [our various concepts and terminology]({{< relref "fundamentals/concepts.md" >}}) and have gone through our [Getting started with Geodesic]({{< relref "tutorials/geodesic-getting-started.md" >}}) tutorial because we'll be using Geodesic as our means to run `atmos`.
22+
23+
## Tutorial
24+
25+
### 1. Clone the tutorials repository
26+
27+
As part of this tutorial (and others in our tutorial series), we'll be utilizing [our tutorials repository](https://github.com/cloudposse/tutorials). This repository includes code and relevant materials for you to use alongside this tutorial walk through.
28+
29+
Let's clone it to your local machine:
30+
31+
```bash
32+
git clone git@github.com:cloudposse/tutorials.git
33+
```
34+
35+
Now that it's on your local machine, let's get into the code that walks us through using `atmos`:
36+
37+
```bash
38+
cd tutorials/02-atmos
39+
```
40+
41+
### 2. Build the image for our tutorial
42+
43+
Now that we've got our code located on your local machine, let's look at our tutorial's example directory:
44+
45+
```
46+
.
47+
├── Dockerfile
48+
├── Makefile
49+
├── README.md
50+
├── components/
51+
└── stacks/
52+
```
53+
54+
Here we've got a `Dockerfile` and a few other things going on. Let's pop open that `Dockerfile` and look at it quickly:
55+
56+
```Dockerfile
57+
ARG VERSION=0.141.6
58+
ARG OS=alpine
59+
ARG CLI_NAME=atmos
60+
61+
FROM cloudposse/geodesic:$VERSION-$OS
62+
63+
# Geodesic message of the Day
64+
ENV MOTD_URL="https://geodesic.sh/motd"
65+
66+
ENV DOCKER_IMAGE="cloudposse/atmos"
67+
ENV DOCKER_TAG="latest"
68+
69+
# Geodesic banner
70+
ENV BANNER="Atmos Tutorial"
71+
72+
# Install terraform.
73+
RUN apk add -u terraform-0.14@cloudposse
74+
# Set Terraform 0.14.x as the default `terraform`.
75+
RUN update-alternatives --set terraform /usr/share/terraform/0.14/bin/terraform
76+
77+
# Install Atmos
78+
RUN apk add atmos@cloudposse
79+
80+
COPY components/ /components/
81+
COPY stacks/ /stacks/
82+
83+
WORKDIR /
84+
```
85+
86+
Few important pieces to point out here:
87+
88+
1. We're using [Geodesic]({{< relref "reference/tools.md#geodesic" >}}) as our base image. This enables us to provide a consistent, reproducible toolbox to invoke `atmos` from the command line.
89+
1. We're installing Terraform 0.14 and using that as our default `terraform` executable. Geodesic supports installing multiple concurrent versions of `terraform` using the [`update-alternatives` system](https://manpages.debian.org/stretch/dpkg/update-alternatives.1.en.html).
90+
1. We're installing `atmos` as a simple binary via `apk`. This is because `atmos` is built and distributed as a [Cloud Posse linux package](https://github.com/cloudposse/packages).
91+
1. We're copying our `components/` and `stacks/` folder into the image.
92+
93+
Overall, a fairly simple and small set of additions on top of standard Geodesic base image. To get started using this image, first we have to build it. To do so, we could invoke `docker build` manually, but to speed things up we've provided a `make` target to simplify that process:
94+
95+
```bash
96+
# Pull the Cloud Posse build-harness, which provides some additional utilities
97+
# that our `build` target uses.
98+
make init
99+
100+
# Build our local Dockerfile onto out local machines as `cloudposse/atmos:latest`
101+
make build
102+
```
103+
104+
Once our image is built, we're ready to run it!
105+
106+
### 3. Run the `atmos` image
107+
108+
Now that we've built our image, we want to run it as a new geodesic shell so we can work on our example. Let's run the following command to do that:
109+
110+
```bash
111+
docker run -it \
112+
--rm \
113+
--volume $HOME:/localhost \
114+
--volume $PWD/stacks:/stacks \
115+
--volume $PWD/components:/components \
116+
cloudposse/atmos:latest
117+
```
118+
119+
Now we should have an interactive bash login shell open into our `cloudposse/atmos` image with our home folder, `stacks/`, and `components/` directories all mounted into it. To check that all is working correctly, let's invoke a couple commands to make sure all is looking good:
120+
121+
```bash
122+
terraform -v # Should return: Terraform v0.14.XX
123+
124+
atmos version # Should return a simple Semver number.
125+
```
126+
127+
Awesome, we've successfully set up `atmos` and we're ready to start using it!
128+
129+
### 4. Terraform plan and apply a component
130+
131+
Now that we've got access to `atmos`, let's do something simple like execute `plan` and `apply` on some terraform code! To do that, we need two things:
132+
133+
1. Components -- We've provided 3 small example components in our `components/terraform/` directory, which is mounted to `/` inside your running container.
134+
1. A Stack configuration -- We've provided a simple example stack located at `stacks/example.yaml`. This is similarly mounted to `/` inside your running container.
135+
136+
For our example in this step, we'll use `components/terraform/fetch-location` component. To plan that component, let's execute the following:
137+
138+
```bash
139+
atmos terraform plan fetch-location --stack=example
140+
```
141+
142+
If you properly entered your command, you should see a successful plan which resulted in "No changes. Infrastructure is up-to-date." You'll notice this first executes a `terraform init` before doing the plan. This is intentional to ensure `atmos` can be invoked without prior project setup. Note, we'll discuss the currently unknown `--stack` parameter shortly.
143+
144+
So now that we've done a plan... let's get this project applied. We could invoke `atmos terraform apply ...`, but our best option at this point would be to invoke `deploy` which will execute a terraform `init`, `plan`, and `apply` in sequential order:
145+
146+
```bash
147+
atmos terraform deploy fetch-location --stack=example
148+
```
149+
150+
Even though this component didn't have any resources, your deploy’s `apply` step will utilize the [`external`](https://registry.terraform.io/providers/hashicorp/external/latest/docs/data-sources/data_source) data source to invoke the component's `fetch_location.sh` script and output your city, region, and country (found by your IP address).
151+
152+
Awesome, we've got a component applied, but that would've been pretty trivial to do without `atmos`, right? We consolidated down 3 commands into one which is great, but we can do a lot better... Let's show you where `atmos` really provides value: Workflows.
153+
154+
### 5. Invoke an Atmos Workflow
155+
156+
The SweetOps methodology is built on small, composable components because through experience practitioners have found large root modules to become cumbersome: They require long `plan` times, create large blast radiuses, and don't foster reuse. The tradeoff with smaller root modules (components) however is that you then need to orchestrate them in an order that makes sense for what you're building. That is where `atmos` workflows come in. Workflows enable you to describe the ordering of how you want to orchestrate your terraform or helmfile components so that you can quickly invoke multiple components via one command. Let's look at an example in our `/stacks/example.yaml` file:
157+
158+
```yaml
159+
import: []
160+
vars: {}
161+
162+
terraform:
163+
vars: {}
164+
165+
helmfile:
166+
vars: {}
167+
168+
components:
169+
terraform:
170+
fetch-location:
171+
vars: {}
172+
173+
fetch-weather:
174+
vars:
175+
api_key: 2a820d40d573758aa714641fc331e897
176+
177+
output-results:
178+
vars:
179+
print_users_weather_enabled: true
180+
181+
helmfile: {}
182+
183+
workflows:
184+
deploy-all:
185+
description: Deploy terraform projects in order
186+
steps:
187+
- job: terraform deploy fetch-location
188+
- job: terraform deploy fetch-weather
189+
- job: terraform deploy output-results
190+
```
191+
192+
Here we can see our first stack, so let's break this file down to help understand what it is doing:
193+
194+
1. We've got a couple of empty elements at the top: `import` and `vars`. We'll address these in an upcoming tutorial.
195+
1. We've got `terraform` and `helmfile` elements that have empty `vars` elements. These provide any shared configuration variables across components when dealing with more complicated stacks. We'll address these in an upcoming tutorial as well.
196+
1. We've got our `components` element which has `terraform` and `helmfile` elements. This is where we describe our various components that make up our stack and the input configurations that we want to invoke them with (via their `vars` elements). You can see here we have our 3 terraform components from within our `components/terraform/` folder specified here and some configuration to go along with them.
197+
1. Finally, we've got our `workflows` element. This is a `map` type element that accepts a workflow name as the key and then the description and steps as values. In the example `deploy-all` workflow, our steps are `job` items which describe to `atmos` that we want to run `atmos terraform deploy` on each component in our stack.
198+
199+
To sum it up, our stack represents an environment: It describes the components we need to deploy for that environment, the configuration we want to supply to those components, and finally the ordering of how to orchestrate those components. This is immensely powerful as it enables us to provide one source of truth for what goes into building an environment and how to make it happen.
200+
201+
Now that we know what is in our `example.yaml` stack configuration, let's invoke that workflow:
202+
203+
```bash
204+
atmos workflow deploy-all -s example
205+
```
206+
207+
This will run our various steps through `atmos` and you should see the sequential `init`, `plan`, and `apply` of each component in the workflow to output the current weather for your area. We hope it's sunny wherever you're at 😁 🌤
208+
209+
Let's move on to updating our code and getting a feel for working a bit more hands on with `atmos` and stacks.
210+
211+
### 6. Update our Stack
212+
213+
One of the critical philosophies that SweetOps embodies is a focus on [improving Day 2+ operations]({{< relref "fundamentals/philosophy.md#optimize-for-day-2-operations" >}}) and with that in mind, it's important to know how you would update this stack and utilize `atmos` to make those changes. Luckily, that's as simple as you might think. Let's try it out and update the `stacks/example.yaml` file on our local machines to the following:
214+
215+
```yaml
216+
import: []
217+
vars: {}
218+
219+
terraform:
220+
vars: {}
221+
222+
helmfile:
223+
vars: {}
224+
225+
components:
226+
terraform:
227+
fetch-location:
228+
vars: {}
229+
230+
fetch-weather:
231+
vars:
232+
api_key: 2a820d40d573758aa714641fc331e897
233+
unit_of_measurement: metric # Guess you're from across the pond?
234+
235+
output-results:
236+
vars:
237+
print_users_weather_enabled: false # We disable outputting via Terraform.
238+
239+
helmfile: {}
240+
241+
workflows:
242+
deploy-all:
243+
description: Deploy terraform projects in order
244+
steps:
245+
- job: terraform deploy fetch-location
246+
- job: terraform deploy fetch-weather
247+
- job: terraform deploy output-results
248+
```
249+
250+
Above we updated a couple variables to change the behavior of our terraform code for this particular stack. Since we mounted our local `stacks/` folder to our `atmos` container via `--volume`, when you save the above stack file docker will update your container's `/stacks/example.yaml` file as well. Now to execute this again... we simply invoke our `deploy-all` workflow command:
251+
252+
```bash
253+
atmos workflow deploy-all -s example
254+
```
255+
256+
This should run through our workflow similar to the way we did it before, but this time we'll see our temperature come back from the weather API in celsius instead of fahrenheit and we'll skip over our terraform `local-exec`'s `printf` command for pretty printing our weather data. Instead we'll just get our updated temperature as one of our `Outputs`.
257+
258+
## Conclusion
259+
260+
Wrapping up, we've seen some critical aspects of SweetOps in action as part of this tutorial:
261+
262+
1. Another usage of Geodesic to easily provide a consistent environment where we can invoke `atmos`.
263+
1. An example stack along with the breakdown of what goes into a stack and why it is a powerful way to describe an environment.
264+
1. Example components that require a specific workflow in order to execute correctly.
265+
1. Usage of `atmos` in executing against some terraform code and orchestrating a workflow from our stack.
266+
267+
With these tools, you can skip documenting the various steps of building an environment (aka WikiOps) and instead focus on just describing and automating those steps! And there is a lot more `atmos` and stack files can do beyond this brief intro, so keep looking around the docs for more usage patterns!
268+
269+
<!-- TODO: Update the above to point at how-tos for Atmos / Stacks -->

content/tutorials/geodesic-getting-started.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,5 +95,6 @@ assume-role luke.skywalker
9595
# Finally, we can run our AWS CLI commands without having to manually invoke `aws-vault exec` each time
9696
aws s3 ls
9797
aws sts get-caller-identity
98+
```
9899

99100
The beautiful thing about all of this is that we didn't need to install anything except Docker on our local machine to make this happen. Both the AWS CLI and `aws-vault` tools involve specific installation instructions to get up and running, but by using Geodesic we're able to quickly skip over all of that and use a container that includes them out of the box alongside dozens of other tools as well. That is why we call it our toolbox as it enables consistent usage of CLI tools across your entire organization!

themes/cloudposse/src/scss/components/page-elements/page.scss

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,9 @@
111111

112112
> h3 {
113113
font-size: 13px;
114-
font-weight: 300;
114+
font-weight: bold;
115115
text-transform: uppercase;
116+
margin-top: 2rem;
116117
}
117118

118119
img {
@@ -176,7 +177,7 @@
176177
background-color: #ffffff7a;
177178
font-family: Consolas,andale mono wt,andale mono,lucida console,lucida sans typewriter,dejavu sans mono,bitstream vera sans mono,liberation mono,nimbus mono l,Monaco,courier new,Courier,monospace;
178179
}
179-
180+
180181
pre code {
181182
background-color: inherit;
182183
border: none;

0 commit comments

Comments
 (0)