At Bytesource we ♥ doing DevOps at Github with Atlantis/Terraform and AWS. Atlantis (https://runatlantis.io) is a powerful GitOps Terraform automation tool that is fully open source and allows developers to directly interact with AWS Infrastructure components via Terraform.
Our initial goal was to provide Developers a setup that allows them to build their software and deploy it to AWS environments without any obstacles. Do achieve this we decided to deploy Atlantis in ECS Fargate and allow the InstanceProfile to assume dedicated deployment roles in separate development and production accounts.
And to interact with Atlantis which runs Terraform for us we use Github. There the developers can follow the well established pull request based workflow to update configuration and then deploy it first into the dedicated development environment and then into the dedicated production environment.
Terraform
Most projects in real life don’t start with a setup that is fully automated, beautiful and documented. But nowadays we see that many developers start even in the earliest project phases already with automating the infrastructure they need. Terraform has proven to be a powerful tool in that respect and so we start every new project with at least a git repository for Terraform and a dedicated development environment.
Developers can start using those environments right away and we allow them to deploy to development manually from their machines to keep response times as low as possible. Especially during early development these fast response times guarantee quick results.
Once the project matures we introduce an additional production environment and Atlantis into mix. Terraform projects are usually structured in a similar way:
.
├── atlantis.yaml
├── configs
│ ├── production.tfvars
│ └── development.tfvars
├── main.tf
├── variables.tf
├── providers.tf
└── outputs.tf
A structure like this deploys comparable infrastructure to all environments which different parameters given by the variables in configs/production.tfvars
and configs/development.tfvars
. This way manual deployment into the development environments is still directly possible and Atlantis as a workflow tool can jump in.
Atlantis
Lets have a look at how Atlantis works.
For a developer Atlantis is directly integrated into Github and can be interacted with by simple comments on pull requests. By carefully managing the permissions on the repository the developer will be able to produce a terrafrom plan
with Atlantis and once the request is approved it can be applied and the pull request can be merged into the main
branch.
So how does the Atlantis side look like? In general it consists of two parts: A server side configuration and a repository configuration.
The Server side configuration is autogenerated in our environments and defines which workflows are available.
{
"repos": [
{
"allow_custom_workflows": false,
"allowed_workflows": [
"development",
"production"
],
"apply_requirements": [
"approved",
"mergeable"
],
"branch": "/.*/",
"id": "/.*/"
}
],
"workflows": {
"development": {
"apply": {
"steps": [
{
"env": {
"name": "TF_VAR_provider_role_arn",
"value": "arn:aws:iam::<development_account_id>:role/external/DeploymentRole"
}
},
{
"apply": {
"extra_args": []
}
}
]
},
"plan": {
"steps": [
{
"env": {
"name": "TF_VAR_provider_role_arn",
"value": "arn:aws:iam::<development_account_id>:role/external/DeploymentRole"
}
},
{
"plan": {
"extra_args": [
"-var-file=configs/development.tfvars"
]
}
}
]
}
},
"production": { ... equal to development except for the aws account id and the config file loaded ... }
}
}
This configuration is quite basic and defines the two workflows development
and production
which are different only by the terraform varialbe provider_role_arn
that they set. So to switch between environments aka. AWS accounts in Terraform a single line is required:
provider "aws" {
assume_role {
role_arn = var.provider_role_arn
}
}
This makes the workflow transparent to any viewer.
The repository configuration atlantis.yaml
is in turn very simple:
version: 3
projects:
- name: production
dir: .
autoplan:
enabled: false
terraform_version: v1.3.3
workflow: provisioning
- name: development
dir: .
autoplan:
enabled: false
terraform_version: v1.3.3
workflow: development
Sumup
While the overall setup looks simple, each part can move quite a lot and thus they have to be carefully configured to fit together. The central piece that is connecting all environments is the AWS Role that is assumed when deploying. Setting this Role via the variable provider_role_arn
in the workflow on the server gives a simple governance over which environments can be used. The user also can not override these workflows as that is forbidden by the Atlantis server and since all changes in git are reviewed a certain amount of governance is given here too while still allowing the developer to have short development cycles.