Terraform

This document is a supplement to the Aptible Terraform Provider on the Terraform Registry.

Environment definition

Environments are defined as data sources and should point toward a pre-existing environment that the Terraform user already has access to:

data "aptible_environment" "example" {
  handle = "terraform-example-environment"
}

Deployment and managing Docker images

Direct Docker Image Deployment is currently the only deployment method supported with Terraform. If you'd like to use Terraform to deploy your Apps and you're currently using Dockerfile Deployment you'll need to switch. See Migrating from Dockerfile Deploy for tips on how to do so.

If you’re already using Direct Docker Image Deployment, managing this is pretty easy. Set your Docker repo, registry username, and registry password as the configuration variables APTIBLE_DOCKER_IMAGE, APTIBLE_PRIVATE_REGISTRY_USERNAME, and APTIBLE_PRIVATE_REGISTRY_PASSWORD.

resource "aptible_app" "example-app" {
    env_id         = data.aptible_environment.example.env_id
    handle         = "example-app"
    config = {
        "APTIBLE_DOCKER_IMAGE": "",
        "APTIBLE_PRIVATE_REGISTRY_USERNAME": "",
        "APTIBLE_PRIVATE_REGISTRY_PASSWORD": "",
    }
}

πŸ“˜

Note

Please ensure you have the correct image, username, and password set every time you run terraform apply. If you are deploying outside of Terraform, you will also need to keep your Terraform configuration up to date.

Managing Services

The service process_type should match what's contained in your Procfile. Otherwise, service container sizes and container counts cannot be defined and managed individually.

resource "aptible_app" "example-app" {
  env_id         = data.aptible_environment.example.env_id
  handle         = "exmaple-app"
  config = {
    "APTIBLE_DOCKER_IMAGE": "",
    "APTIBLE_PRIVATE_REGISTRY_USERNAME": "",
    "APTIBLE_PRIVATE_REGISTRY_PASSWORD": "",
  }
  service {
    process_type           = "sidekiq"
    container_count        = 1
    container_memory_limit = 1024
  }
  service {
    process_type           = "web"
    container_count        = 2
    container_memory_limit = 4096
  }
}

Referencing Resources in Configurations

Resources can easily be referenced in configurations when using Terraform. Here is example for an App configuration that references Databases:

resource "aptible_app" "example-app" {
    env_id = data.aptible_environment.example.env_id
    handle = "example-app"
    config = {
        "REDIS_URL": aptible_database.example-redis-db.default_connection_url,
        "DATABASE_URL": aptible_database.example-pg-db.default_connection_url,
    }
    service {
        process_type           = "cmd"
        container_count        = 1
        container_memory_limit = 1024
    }
}

resource "aptible_database" "example-redis-b" {
  env_id         = data.aptible_environment.example.env_id
  handle         = "example-redis-db"
  database_type  = "redis"
  container_size = 512
  disk_size      = 10
  version        = "5.0"
}

resource "aptible_database" "example-pg-db" {
  env_id         = data.aptible_environment.example.env_id
  handle         = "example-pg-db"
  database_type  = "postgresql"
  container_size = 1024
  disk_size      = 10
  version        = "12"
}

Some apps use the port, hostname, username, and password broken apart rather than as a standalone connection url. Terraform can break those apart or you can add some logic in your app or container entrypoint to achieve this. This also works with endpoints. For example:

resource "aptible_app" "example-app" {
  env_id = data.aptible_environment.example.env_id
  handle = "example-app"
  config = {
    "ANOTHER_APP_URL": aptible_endpoint.example-endpoint.virtual_domain,
  }
  service {
    process_type = "cmd"
    container_count = 1
    container_memory_limit = 1024
  }
}

resource "aptible_app" "another-app" {
  env_id = data.aptible_environment.example.env_id
  handle = "another-app"
  config = {}
  service {
    process_type = "cmd"
    container_count = 1
    container_memory_limit = 1024
  }
}

resource "aptible_endpoint" "example-endpoint" {
  env_id         = data.aptible_environment.example.env_id
  default_domain = true
  internal       = true
  platform       = "alb"
  process_type   = "cmd"
  endpoint_type  = "https"
  resource_id    = aptible_app.another-app.app_id
  resource_type  = "app"
  ip_filtering   = []
}

The value aptible_endpoint.example-endpoint.virtual_domain will be the domain used to access the Endpoint (so app-0000.on-aptible.com or www.example.com).

πŸ“˜

Note

If your Endpoint uses a wildcard certificate/domain, virtual_domain would be something like *.example.com which is not a valid domain name. Therefore, when using a wildcard domain, you should provide the subdomain you want your application to use to access the Endpoint, like www.example.com, rather than relying solely on the Endpoint's virtual_domain.

Circular references

One potential risk of relying on URLs to be set in App configurations is circular references. This happens when your App uses the Endpoint URL in its configuration, but the Endpoint cannot be created until the App exists. Terraform does not have a graceful way to handle circular references. While this approach won't work for default domains, the easiest option is to define a variable that can be referenced in both the Endpoint resource and the App configuration:

variable "example_domain" {
  description = "The domain name"
  type        = string
  default     = "www.example.com"
}

resource "aptible_app" "example-app" {
  env_id = data.aptible_environment.example.env_id
  handle = "example-app"
  config = {
    "ANOTHER_APP_URL": var.example_domain,
  }
  service {
    process_type = "cmd"
    container_count = 1
    container_memory_limit = 1024
  }
}

resource "aptible_endpoint" "example-endpoint" {
  env_id         = data.aptible_environment.example.env_id
  endpoint_type  = "https"
  internal       = false
  managed        = true
  platform       = "alb"
  process_type   = "cmd"
  resource_id    = aptible_app.example-app.app_id
  resource_type  = "app"
  domain         = var.example_domain
  ip_filtering   = []
}

Managing DNS

While Aptible does not directly manage your DNS, we do provide you the information you need to manage DNS. For example, if you are using Cloudflare for your DNS, and you have an endpoing called example-endpoint, you would be able to create the record:

resource "cloudflare_record" "example_app_dns" {
  zone_id = cloudflare_zone.example.id
  name    = "www.example"
  type    = "CNAME"
  value   = aptible_endpoint.example-endpoint.id
  ttl     = 60
}

And for the Managed HTTPS dns-01 verification record:

resource "cloudflare_record" "example_app_acme" {
  zone_id = cloudflare_zone.example.id
  name    = "_acme-challange.www.example"
  type    = "CNAME"
  value   = "acme.${aptible_endpoint.example-endpoint.id}"
  ttl     = 60
}

Secure/Sensitive Values

You can use Terraform to mark values as secure. These values are redacted in the output of terraform plan and terraform apply.


variable "shhh" {
  description = "A sensitive value"
  type        = string
  sensitive   = true
}

resource "aptible_app" "example-app" {
  env_id = data.aptible_environment.example.env_id
  handle = "example-app"
  config = {
    "SHHH": var.shhh,
  }
  service {
    process_type = "cmd"
    container_count = 1
    container_memory_limit = 1024
  }
}

When you run terraform state show these values will also be marked as sensitive. For example:

resource "aptible_app" "example-app" {
    app_id   = 000000
    config   = {
        "SHHH" = (sensitive)
    }
    env_id   = 4749
    git_repo = "[email protected]:terraform-example-environment/example-app.git"
    handle   = "example-app"
    id       = "000000"

    service {
        container_count        = 1
        container_memory_limit = 1024
        process_type           = "cmd"
    }
}

Did this page help you?