Knowledgebase

Run Terraform in Automation with Atlantis Print

  • 0

Introduction

Automation of Terraform is a way to ensure consistency and implement features such as integration with version control hooks, and it's useful for development and production servers. Following this guide, you'll set up an example CI/CD pipeline with Atlantis, GitHub, and Terraform.

Prerequisites

This guide uses a Rcs Ubuntu 20.04 VPS with 1 vCPU and 1 GB of RAM. This is an advance guide, requiring a basic understanding of Terraform and CI/CD concepts.

This guide uses variables with uppercase values in angle brackets. Replace these with your values.

1. Install Terraform CLI

Atlantis uses Terraform to plan, create, and destroy cloud resources.

  1. Download the 64-bit Linux version of Terraform, found on the Terraform download page. The example below is for version 0.14.5.

     # wget https://releases.hashicorp.com/terraform/0.14.5/terraform_0.14.5_linux_amd64.zip
  2. Extract the Terraform .zip file.

     # apt install -y unzip
     # unzip terraform_*_linux_amd64.zip && rm terraform_*_linux_amd64.zip
  3. Move terraform to /usr/bin.

     # mv terraform /usr/bin/terraform
  4. Check the terraform installation.

     # terraform --version
     # which terraform

2. Install Atlantis

  1. Download the 64-bit Linux version of Atlantis, found on the Atlantis release page. The example below is for version 0.16.0.

     # wget https://github.com/runatlantis/atlantis/releases/download/v0.16.0/atlantis_linux_amd64.zip
  2. Extract) the Atlantis .zip file.

     # unzip atlantis_linux_amd64.zip && rm atlantis_linux_amd64.zip
  3. Create an Atlantis user with a home directory.

     # adduser -m atlantis
  4. Move atlantis to its home directory /home/atlantis

     # mv atlantis /home/atlantis/atlantis
  5. Change the ownership of the file to Atlantis user.

     # chown atlantis:atlantis /home/atlantis/atlantis
  6. Check the Atlantis installation.

     # /home/atlantis/atlantis --help

3. Setup a GitHub Repository

Create a private GitHub repository. The recommended organization for the Github repository is shown below. Replace vultr-vc and instance1 (flagged with double asterisks below) with your corresponding module and service name.

    ├── modules
    │   └── vultr-vc **
    │       ├── provider.tf
    │       ├── variable.tf
    │       ├── output.tf
    │       └── main.tf
    │
    ├── services
    │   └── instance1 **
    │       ├── terraform.tfvars.example
    │       ├── variable.tf
    │       ├── output.tf
    │       └── main.tf
    ├── .gitignore
    ├── README.md
    └── atlantis.yaml

On GitHub:

  1. Go to Settings then Webhook.
  2. Click Add webhook.
  3. Set Payload URL to http://<INSTANCE_IP_OR_URL>/events
  4. Set Content type to application/json
  5. Enter a random string in Secret. More than eight characters is recommended.
  6. Pick the events to send.
    • Pushes
    • Pull request review comments
    • Pull requests
    • Issue comments
  7. Leave Active ticked.
  8. Click Add webhook.

Create a Github token:

  1. Go to Profile > Developer Settings > Personal access token
  2. Click Generate new token
  3. Select scopes.
    • repo
  4. Give the token a name, For example: Atlantis Token
  5. Click Generate Token and copy the token.

Create an atlantis.yaml file in the GitHub repository, which tells Atlantis which directories and workflows to apply. It also creates a tfvars file on /home/atlantis/tfvars/service.tfvars to execute terraform apply -var-file <FILENAME>.

version: 3
projects:
- name: instance1
    dir: services/instance1
    workflow: service
    autoplan:
    when_modified: ["modules/**/*.tf","*.tf"]
    enabled: true

workflows:
service:
    plan:
    steps:
    - init
    - plan:
        extra_args: ["-var-file", "/home/atlantis/tfvars/service.tfvars"]

4. Create a Terraform Module

A Terraform module is a universal template that speeds up the creation of similar services.

  1. Create a Rcs provider.tf file.

     terraform {
         required_providers {
             vultr = {
             source = "vultr/vultr"
             version = "2.1.2"
             }
         }
     }
    
     provider "vultr" {
         api_key = var.vultr_token
         rate_limit = 700
         retry_limit = 3
     }
  2. Create a main.tf file.

    This example creates a Rcs Cloud Compute instance.

     resource "vultr_instance" "instance" {
         plan                = var.server_type
         region              = var.region
         os_id               = var.server_os
         label               = var.server_label
         tag                 = "terraform"
     }
  3. Create a variable.tf file, which defines the variables passed to the Terraform.

     variable "vultr_token" {
         description   = "Rcs api token"
         type          = string
     }
    
     variable "server_os" {
         description   = "Rcs OS"
         type          = string
     }
    
     variable "server_type" {
         description   = "Rcs Server Type Ex. vc2-1c-1gb"
         type          = string
     }
    
     variable "server_label" {
         description   = "Rcs Server Name Labeling"
         type          = string
     }
    
     variable "region" {
         description   = "Rcs Region"
         type          = string
     }

5. Create a Terraform Service

  1. Create a main.tf file.

    Terraform stores state about your infrastructure and configuration in a .tfstate file, which is declared in the terraform backend block. The module block sets the variables for the terraform module.

     terraform {
         backend "local" {
             path = "/home/atlantis/tfstate/service-instance1.tfstate"
         }
     }
    
     module "server1" {
         source          = "../../modules/vultr-vc"
         vultr_token     = var.vultr_token
         server_type     = "vc2-1c-1gb"
         server_os       = "387"
         server_label    = "Server1-Terraform"
         region          = "SGP"
     }

    Use the Rcs API to find valid server_os values.

     $ curl https://api.vultr.com/v2/os

    For valid region values:

     $ curl https://api.vultr.com/v2/regions
  2. Create a variable.tf file to pass the API token as a secret variable to Terraform.

     variable "vultr_token" {
         description   = "Rcs api token"
         type          = string
     }

6. Get an API Key

  1. Navigate to the Rcs Customer Portal.
  2. Go to Account > API.
  3. Click Enable API.
  4. Copy the Rcs API key.
  5. Go to Access Control.
  6. Add the Server IP to access control.

7. Set up the Atlantis Service

  1. Set up the tfvars file.

     # mkdir -p /home/atlantis/tfvars
     # nano /home/atlantis/tfvars/service.tfvars
  2. Add your Rcs API key as shown.

     vultr_token = "<VULTR_API_KEY>"
  3. Grant ownership of the tfvars folder to the atlantis user.

     # chown -R atlantis:atlantis /home/atlantis/tfvars
  4. Set up the tfstate local backend directory.

     # mkdir -p /home/atlantis/tfstate
     # chown -R atlantis:atlantis /home/atlantis/tfstate
  5. Set up the repos.yaml file in the atlantis user home directory.

     # nano /home/atlantis/repos.yaml

    The repos.yaml file sets the atlantis.yaml file's abilities in the GitHub repo. By setting it to mergeable, the action can only occur if the Pull Request is mergeable.

     repos:
     - id: /.*/
     apply_requirements: [mergeable]
     allowed_overrides: [workflow]
     allow_custom_workflows: true
  6. Grant ownership of repos.yaml to the atlantis user.

     # chown atlantis:atlantis /home/atlantis/repos.yaml
  7. Create a new systemd service.

     # cd /etc/systemd/system
     # nano atlantis.service or vi atlantis.service

    Paste the following:

     [Unit]
     Description=Atlantis
    
     [Service]
     User=atlantis
     WorkingDirectory=/home/atlantis
     ExecStart=/home/atlantis/atlantis server --allow-fork-prs --gh-user=<Github Username> --gh-token=<Github Token> --repo-whitelist=github.com/<GITHUB_USERNAME>/<REPOSITORY_NAME> --atlantis-url=http://<INSTANCE_IP_OR_URL> --gh-webhook-secret=GITHUB_SECRET> --repo-config=/home/atlantis/repos.yaml --log-level debug --port 80
     Restart=always
    
     [Install]
     WantedBy=multi-user.target
    
    
     # systemctl daemon-reload
     # systemctl start atlantis.service
  8. Check the installation.

     # systemctl status atlantis.service
     # journalctl -xe

8. Create a New Server / Service

On your local computer or GitHub:

  1. Checkout to a new branch.

     $ git checkout -b SERVICE-2
  2. Create a new service folder. It's recommended to use the service name.

  3. Add an atlantis.yaml file in that folder. Paste the following:

     projects:
     - name: instance1
         dir: services/instance1
         workflow: service
         autoplan:
         when_modified: ["modules/**/*.tf","*.tf"]
         enabled: true
     - name: instance2
         dir: services/instance2
         workflow: service
         autoplan:
         when_modified: ["modules/**/*.tf","*.tf"]
         enabled: true
  4. Create a pull request on GitHub to the main branch.

  5. Check the automated Terraform Plan. For example, you may see:

     An execution plan has been generated and is shown below.
     Resource actions are indicated with the following symbols:
     + create
    
     Terraform will perform the following actions:
    
     # module.server1.vultr_instance.instance will be created
     + resource "vultr_instance" "instance" {
         + activation_email       = true
         + allowed_bandwidth      = (known after apply)
         + app_id                 = (known after apply)
         + backups                = "disabled"
         + date_created           = (known after apply)
         + ddos_protection        = false
         + default_password       = (sensitive value)
         + disk                   = (known after apply)
         + enable_ipv6            = false
         + enable_private_network = false
         + features               = (known after apply)
         + firewall_group_id      = (known after apply)
         + gateway_v4             = (known after apply)
         + hostname               = (known after apply)
         + id                     = (known after apply)
         + internal_ip            = (known after apply)
         + kvm                    = (known after apply)
         + label                  = "Server1-Terraform"
         + main_ip                = (known after apply)
         + netmask_v4             = (known after apply)
         + os                     = (known after apply)
         + os_id                  = 387
         + plan                   = "vc2-1c-1gb"
         + power_status           = (known after apply)
         + ram                    = (known after apply)
         + region                 = "SGP"
         + reserved_ip_id         = (known after apply)
         + script_id              = (known after apply)
         + server_status          = (known after apply)
         + snapshot_id            = (known after apply)
         + status                 = (known after apply)
         + tag                    = "terraform"
         + user_data              = (known after apply)
         + v6_main_ip             = (known after apply)
         + v6_network             = (known after apply)
         + v6_network_size        = (known after apply)
         + vcpu_count             = (known after apply)
         }
    
     Plan: 1 to add, 0 to change, 0 to destroy.

    To re-plan, you could use atlantis plan.

  6. Execute the terraform plan using atlantis apply

    The output of apply should look like this:

     module.server1.vultr_instance.instance: Creating...
     module.server1.vultr_instance.instance: Still creating... [10s elapsed]
     module.server1.vultr_instance.instance: Still creating... [20s elapsed]
     module.server1.vultr_instance.instance: Still creating... [30s elapsed]
     module.server1.vultr_instance.instance: Still creating... [40s elapsed]
     module.server1.vultr_instance.instance: Still creating... [50s elapsed]
     module.server1.vultr_instance.instance: Still creating... [1m0s elapsed]
     module.server1.vultr_instance.instance: Still creating... [1m10s elapsed]
     module.server1.vultr_instance.instance: Still creating... [1m20s elapsed]
     module.server1.vultr_instance.instance: Still creating... [1m30s elapsed]
     module.server1.vultr_instance.instance: Still creating... [1m40s elapsed]
     module.server1.vultr_instance.instance: Still creating... [1m50s elapsed]
     module.server1.vultr_instance.instance: Creation complete after 1m54s [id=1ef9bc13-cb27-48b2-b776-30559caffc3f]
    
     Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
    
     The state of your infrastructure has been saved to the path
     below. This state is required to modify and destroy your
     infrastructure, so keep it safe. To inspect the complete state
     use the `terraform show` command.
    
     State path: /home/atlantis/tfstate/service-instance1.tfstate

More Resources

Introduction Automation of Terraform is a way to ensure consistency and implement features such as integration with version control hooks, and it's useful for development and production servers. Following this guide, you'll set up an example CI/CD pipeline with Atlantis, GitHub, and Terraform. Prerequisites This guide uses a Rcs Ubuntu 20.04 VPS with 1 vCPU and 1 GB of RAM. This is an advance guide, requiring a basic understanding of Terraform and CI/CD concepts. Deploy a new Rcs Ubuntu 20.04 (x64) cloud server Update the server according to the Ubuntu best practices guide This guide uses variables with uppercase values in angle brackets. Replace these with your values. 1. Install Terraform CLI Atlantis uses Terraform to plan, create, and destroy cloud resources. Download the 64-bit Linux version of Terraform, found on the Terraform download page. The example below is for version 0.14.5. # wget https://releases.hashicorp.com/terraform/0.14.5/terraform_0.14.5_linux_amd64.zip Extract the Terraform .zip file. # apt install -y unzip # unzip terraform_*_linux_amd64.zip && rm terraform_*_linux_amd64.zip Move terraform to /usr/bin. # mv terraform /usr/bin/terraform Check the terraform installation. # terraform --version # which terraform 2. Install Atlantis Download the 64-bit Linux version of Atlantis, found on the Atlantis release page. The example below is for version 0.16.0. # wget https://github.com/runatlantis/atlantis/releases/download/v0.16.0/atlantis_linux_amd64.zip Extract) the Atlantis .zip file. # unzip atlantis_linux_amd64.zip && rm atlantis_linux_amd64.zip Create an Atlantis user with a home directory. # adduser -m atlantis Move atlantis to its home directory /home/atlantis # mv atlantis /home/atlantis/atlantis Change the ownership of the file to Atlantis user. # chown atlantis:atlantis /home/atlantis/atlantis Check the Atlantis installation. # /home/atlantis/atlantis --help 3. Setup a GitHub Repository Create a private GitHub repository. The recommended organization for the Github repository is shown below. Replace vultr-vc and instance1 (flagged with double asterisks below) with your corresponding module and service name. ├── modules │ └── vultr-vc ** │ ├── provider.tf │ ├── variable.tf │ ├── output.tf │ └── main.tf │ ├── services │ └── instance1 ** │ ├── terraform.tfvars.example │ ├── variable.tf │ ├── output.tf │ └── main.tf ├── .gitignore ├── README.md └── atlantis.yaml On GitHub: Go to Settings then Webhook. Click Add webhook. Set Payload URL to http:///events Set Content type to application/json Enter a random string in Secret. More than eight characters is recommended. Pick the events to send. Pushes Pull request review comments Pull requests Issue comments Leave Active ticked. Click Add webhook. Create a Github token: Go to Profile > Developer Settings > Personal access token Click Generate new token Select scopes. repo Give the token a name, For example: Atlantis Token Click Generate Token and copy the token. Create an atlantis.yaml file in the GitHub repository, which tells Atlantis which directories and workflows to apply. It also creates a tfvars file on /home/atlantis/tfvars/service.tfvars to execute terraform apply -var-file . version: 3 projects: - name: instance1 dir: services/instance1 workflow: service autoplan: when_modified: ["modules/**/*.tf","*.tf"] enabled: true workflows: service: plan: steps: - init - plan: extra_args: ["-var-file", "/home/atlantis/tfvars/service.tfvars"] 4. Create a Terraform Module A Terraform module is a universal template that speeds up the creation of similar services. Create a Rcs provider.tf file. terraform { required_providers { vultr = { source = "vultr/vultr" version = "2.1.2" } } } provider "vultr" { api_key = var.vultr_token rate_limit = 700 retry_limit = 3 } Create a main.tf file. This example creates a Rcs Cloud Compute instance. resource "vultr_instance" "instance" { plan = var.server_type region = var.region os_id = var.server_os label = var.server_label tag = "terraform" } Create a variable.tf file, which defines the variables passed to the Terraform. variable "vultr_token" { description = "Rcs api token" type = string } variable "server_os" { description = "Rcs OS" type = string } variable "server_type" { description = "Rcs Server Type Ex. vc2-1c-1gb" type = string } variable "server_label" { description = "Rcs Server Name Labeling" type = string } variable "region" { description = "Rcs Region" type = string } 5. Create a Terraform Service Create a main.tf file. Terraform stores state about your infrastructure and configuration in a .tfstate file, which is declared in the terraform backend block. The module block sets the variables for the terraform module. terraform { backend "local" { path = "/home/atlantis/tfstate/service-instance1.tfstate" } } module "server1" { source = "../../modules/vultr-vc" vultr_token = var.vultr_token server_type = "vc2-1c-1gb" server_os = "387" server_label = "Server1-Terraform" region = "SGP" } Use the Rcs API to find valid server_os values. $ curl https://api.vultr.com/v2/os For valid region values: $ curl https://api.vultr.com/v2/regions Create a variable.tf file to pass the API token as a secret variable to Terraform. variable "vultr_token" { description = "Rcs api token" type = string } 6. Get an API Key Navigate to the Rcs Customer Portal. Go to Account > API. Click Enable API. Copy the Rcs API key. Go to Access Control. Add the Server IP to access control. 7. Set up the Atlantis Service Set up the tfvars file. # mkdir -p /home/atlantis/tfvars # nano /home/atlantis/tfvars/service.tfvars Add your Rcs API key as shown. vultr_token = "" Grant ownership of the tfvars folder to the atlantis user. # chown -R atlantis:atlantis /home/atlantis/tfvars Set up the tfstate local backend directory. # mkdir -p /home/atlantis/tfstate # chown -R atlantis:atlantis /home/atlantis/tfstate Set up the repos.yaml file in the atlantis user home directory. # nano /home/atlantis/repos.yaml The repos.yaml file sets the atlantis.yaml file's abilities in the GitHub repo. By setting it to mergeable, the action can only occur if the Pull Request is mergeable. repos: - id: /.*/ apply_requirements: [mergeable] allowed_overrides: [workflow] allow_custom_workflows: true Grant ownership of repos.yaml to the atlantis user. # chown atlantis:atlantis /home/atlantis/repos.yaml Create a new systemd service. # cd /etc/systemd/system # nano atlantis.service or vi atlantis.service Paste the following: [Unit] Description=Atlantis [Service] User=atlantis WorkingDirectory=/home/atlantis ExecStart=/home/atlantis/atlantis server --allow-fork-prs --gh-user= --gh-token= --repo-whitelist=github.com// --atlantis-url=http:// --gh-webhook-secret=GITHUB_SECRET> --repo-config=/home/atlantis/repos.yaml --log-level debug --port 80 Restart=always [Install] WantedBy=multi-user.target # systemctl daemon-reload # systemctl start atlantis.service Check the installation. # systemctl status atlantis.service # journalctl -xe 8. Create a New Server / Service On your local computer or GitHub: Checkout to a new branch. $ git checkout -b SERVICE-2 Create a new service folder. It's recommended to use the service name. Add an atlantis.yaml file in that folder. Paste the following: projects: - name: instance1 dir: services/instance1 workflow: service autoplan: when_modified: ["modules/**/*.tf","*.tf"] enabled: true - name: instance2 dir: services/instance2 workflow: service autoplan: when_modified: ["modules/**/*.tf","*.tf"] enabled: true Create a pull request on GitHub to the main branch. Check the automated Terraform Plan. For example, you may see: An execution plan has been generated and is shown below. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # module.server1.vultr_instance.instance will be created + resource "vultr_instance" "instance" { + activation_email = true + allowed_bandwidth = (known after apply) + app_id = (known after apply) + backups = "disabled" + date_created = (known after apply) + ddos_protection = false + default_password = (sensitive value) + disk = (known after apply) + enable_ipv6 = false + enable_private_network = false + features = (known after apply) + firewall_group_id = (known after apply) + gateway_v4 = (known after apply) + hostname = (known after apply) + id = (known after apply) + internal_ip = (known after apply) + kvm = (known after apply) + label = "Server1-Terraform" + main_ip = (known after apply) + netmask_v4 = (known after apply) + os = (known after apply) + os_id = 387 + plan = "vc2-1c-1gb" + power_status = (known after apply) + ram = (known after apply) + region = "SGP" + reserved_ip_id = (known after apply) + script_id = (known after apply) + server_status = (known after apply) + snapshot_id = (known after apply) + status = (known after apply) + tag = "terraform" + user_data = (known after apply) + v6_main_ip = (known after apply) + v6_network = (known after apply) + v6_network_size = (known after apply) + vcpu_count = (known after apply) } Plan: 1 to add, 0 to change, 0 to destroy. To re-plan, you could use atlantis plan. Execute the terraform plan using atlantis apply The output of apply should look like this: module.server1.vultr_instance.instance: Creating... module.server1.vultr_instance.instance: Still creating... [10s elapsed] module.server1.vultr_instance.instance: Still creating... [20s elapsed] module.server1.vultr_instance.instance: Still creating... [30s elapsed] module.server1.vultr_instance.instance: Still creating... [40s elapsed] module.server1.vultr_instance.instance: Still creating... [50s elapsed] module.server1.vultr_instance.instance: Still creating... [1m0s elapsed] module.server1.vultr_instance.instance: Still creating... [1m10s elapsed] module.server1.vultr_instance.instance: Still creating... [1m20s elapsed] module.server1.vultr_instance.instance: Still creating... [1m30s elapsed] module.server1.vultr_instance.instance: Still creating... [1m40s elapsed] module.server1.vultr_instance.instance: Still creating... [1m50s elapsed] module.server1.vultr_instance.instance: Creation complete after 1m54s [id=1ef9bc13-cb27-48b2-b776-30559caffc3f] Apply complete! Resources: 1 added, 0 changed, 0 destroyed. The state of your infrastructure has been saved to the path below. This state is required to modify and destroy your infrastructure, so keep it safe. To inspect the complete state use the `terraform show` command. State path: /home/atlantis/tfstate/service-instance1.tfstate More Resources Rcs Terraform Configuring Atlantis Atlantis Documentation

Was this answer helpful?
Back

Powered by WHMCompleteSolution