This repository is designed just for this purpose. So, fork it to a GitHub account you manage (either your private account or an organization you have admin rights on) and let's get started.
In this tutorial you will not be using any cloud providers, you won't need any extra credentials and the only resources you will manage are the ones managed by Spacelift's own Terraform provider.
Provisioning a Spacelift account is fully automated and only involves installing the GitHub app. At this point it's up to you to decide whether to give Spacelift access to all your repositories...
...or just the selected ones:
Note: don't agonize over this choice - you can always change it later.
Installing the application takes you to your first Spacelift screen where you can create your first stack.
Stacks are probably the most important concept in Spacelift. They connect your code and your infra, with some configuration in-between. To keep things short, a Spacelift stack maps directly to a single Terraform state file.
So without further ado, let's go through the stack creation process step by step. First, we need to tell Spacelift where the project code lives - this is the Integrate VCS step. Since in the previous step I only gave Spacelift access to a single repository (safety first), and this repository only has a single branch, my choices here are rather... limited. But you get the idea - you select the repo, you select the default branch to deploy from and off you go:
In the next step you will define some things about this stack's behavior. Since this is meant to be a quick and snappy tutorial we won't go into the details, but you can read more about them here. For now the only tweak we need to do here is to mark the stack as administrative. Why? Because only administrative stacks can manage Spacelift resources and that's what we'll be creating as part of this lab.
The next step is all about managing Terraform state. Spacelift can work with any remote state provider but it also provides its own state backend - though beyond convenience there are no benefits to using it. We don't have an existing state to import, so we do the most convenient thing there is - continue the defaults:
As they say, there are 2 hard problems in computer science: cache invalidation, naming things, and off-by-1 errors. We'll make it easy this time: we've come up with a good name for your first stack, so feel free copy it. For now we won't care about labels or description (yes, we support Markdown), though you can read up on them when you're done with this lab.
Congrats, you have your first stack. It doesn't do much, but we'll change it in the next step.
Creating a stack takes you to a very sad looking screen:
Let's add some color here. We can do that by clicking the Trigger button in the upper right hand corner of the screen. The trigger button will create a Spacelift job that will check out you code, run the usual Terraform commands on it and present you with the choice on whether you want to apply them or not:
You can always refer to the logs directly to see what's changing. In this case, we're creating 24 Spacelift resources, and they all look good. So let's confirm and see what happens next:
Wow, 6 seconds? That was quick! Let's go back to our main (Stacks) screen to see what we've just done.
What we just did in Step 3 was creating a bunch of very useful Spacelift resources. Looking at the main screen we can quickly notice two things - our Terraform starter stack turned green (always a good sign!) and there's another Stack we haven't seen before, called Managed stack:
And yes, it's red. Yes, it's normally a bad sign. And yes, this is expected - one of the exercises here is to fix it.
Now where did that come from? In fact, we had it declared it using Terraform, just here. The same file defines a bunch of things related to the environment, so let's click on the name of the new stack to be taken to its screen. Since it doesn't contain anything interesting just yet, let's quickly navigate to the Environment screen. And it's indeed a very busy screen, so let's just look at the first section there:
What we see is a bunch of environment variables and mounted files - some public and some secret - that we indeed saw defined in the stack.tf
we've only just looked at. But there are others - see the ones with the blue label to their right? Where did they come from? They're actually defined here and they belong to a context that's attached to the new Stack.
But before we move on to the context, click the Edit button in the upper right hand corner of the screen and play around with environment variables and mounted files.
Contexts are how Spacelift does configuration reuse. Rather than having to copy and paste a bunch of configuration variables, Spacelift allows you to encapsulate them as a package and attach them to as many stacks as you want. So if you navigate back to the main screen (hint: click on the logo, it normally works like that single button on your iPhone) and then go to the Contexts screen, that's what you're going to see:
Clicking on the context name takes you to the context screen, where you can see that it currently contains two environment variables (one plaintext and one secret) and two mounted files, one plaintext and one secret:
Note that you can edit the context just as you can edit the Stack's own environment. That Edit button is there for a reason, so go wild for a while before we move on to policies, which are the second most important topic in Spacelift.
When you navigate to the Policies screen, you will see that we've created 6 different policies for you - one of each available types except for the initialization policy, which would take a bit longer to explain and thus is not in the scope of this short tutorial.
All these policies are defined and explained in the policies.tf
file, but let's go through them one by one:
-
DevOps are admins is a login policy that would make anyone who's a member of the DevOps team in your GitHub organization to log in as a Spacelift administrator as opposed to the default situation where only GitHub admin users are automatically Spacelift admins. Note: this changes if you're using SSO instead of GitHub to authenticate;
-
All of Engineering gets read access is an access policy that gives any member of the Engineering GitHub team read access to every stack it's attached to;
-
Ignore commits outside the project root is a Git push policy that ignores push notifications which do not affect any files outside of project root of the stack it's attached to;
-
Enforce password strength is a plan policy that prevents you from creating weak passwords using
random_password
resource type - we'll see this one in action really soon; -
Allow only safe commands is a task policy that only allows you to run certain commands as tasks. This is another one that we're going to try hands-on;
-
Trigger stacks that declare an explicit dependency is a trigger policy that will cause every stack that declares dependency to be triggered when the current one is updated - while this one is probably beyond the scope of the basic tutorial, we wanted to show you that Spacelift is Turing-complete. Also, a trigger policy is what triggered a failing run on the newly created stack 😜
While it's worth mentioning that we're using an open-source language for our policies, authoring policies is outside of the scope of this tutorial. Instead, we'd like to show you the power of policies hands-on. Let's then navigate to our new stack (Managed stack) and try to figure out why the run created by the trigger policy failed? Looks like what we're trying to does not agree with our policy:
Don't worry for now about fixing it, we will do that in the next step. Instead, let's navigate to our new Stack's Tasks screen and try to run something. How about terraform destroy -auto-approve
? Nope, didn't work either:
Hint: try running ls
. Figuring out why it succeeds is an exercise left to the reader.
In this step we'll try to fix the problem reported by the plan policy and while doing that we'll see how Spacelift deals with testing your changes and handling Pull Requests. So without further ado, let's make a change to our code to make the random password we're trying to create in this new stack just a little bit longer - let's say 24 characters. Let's also not merge that change to main
but create a separate branch and open a Pull Request:
And here's the exact change we're making:
That little change causes two runs to be executed since this repo is now connected to two stacks - one that created manually and one that is managed programmatically. It's the latter stack we've made changes to, so you will see that there are no changes to the former but one resource would be created for the latter. Note that we report the same information in two ways - one (Atlantis-like) is a PR comment and the other one - commit status checks. The good thing about the latter is GitHub allows you to block PR merges on failing commit status checks.
Clicking on the Details link next to the commit status check takes you to the test run for the affected stack. Let's click on that and see what gives:
Now that the push policy is happy with the new length of your password, you can merge the Pull Request to the main branch. A run will be created automatically in the Runs tab of your Managed stack which should apply the changes automatically (see the autoapply
setting in stack.tf
):
You're a Spacelift expert now 😂 If you like what you've seen so far, here's a few next steps we can suggest:
- learn more about policies and create one from scratch;
- create some resources on a real public cloud;
- connect your Slack workspace;
- learn about our native cloud integrations;
- set up SSO for your organization;
- start a Spacelift agent in your own infrastructure (yes, it will run on your laptop, too);
Bacon