Contents

Terraform on Brightbox Cloud

Terraform is a tool to make managing your overall system infrastructure as easy as managing your individual server configuration. You map out all the different components of your systems from as many different providers as you need and represent them all in code. Terraform handles working out all the dependencies, building the components and configuring all the relationships.

It’s focused very much on infrastructure, so once everything is built the baton is passed onto your configuration management tool of choice, such as Puppet, Chef or Ansible. Terraform just handles orchestrating the bootstrapping.

The result is a detailed description of everything you need to build your entire system from scratch.

Brightbox has written a Terraform provider plugin to add support for managing Brightbox Cloud resources via our API.

This guide will take you through installing Terraform on your local machine and building a small cluster with it using a basic example configuration.

Install Terraform

There are detailed instructions on installing Terraform in their own getting started guide, but the general idea is to download the appropriate package and unzip the binaries to somewhere in your shell’s PATH.

If you’re using Linux or similar, you could unzip them into your system-wide /usr/local/bin directory. Or you can put them somewhere in your home directory and add that to your PATH variable. E.g:

$ wget -q https://releases.hashicorp.com/terraform/0.11.7/terraform_0.11.7_linux_amd64.zip
$ sudo unzip terraform_0.11.7_linux_amd64.zip -d /usr/local/bin

Archive:  terraform_0.11.7_linux_amd64.zip
  inflating: /usr/local/bin/terraform

Clone our example Terraform configuration

Our example Terraform configuration defines a cloud server and a cloud sql instance, plus cloud ips and appropriate firewall rules for them.

Get the example configuration from our GitHub repository:

$ git clone git@github.com:brightbox/terraform-brightbox-example.git
$ cd terraform-brightbox-example

Setup authentication

Terraform authenticates with Brightbox using your username and password (or with API Client credentials if you prefer), plus you need to specify which of your accounts you want it work with (if you’ve not collaborated on any other accounts, you’ll have only one but you still need to specify the id).

You can configure your credentials either by editing the provider.tf file and specifying everything there, or you can avoid writing credentials to disk and set them as environment variables:

$ export BRIGHTBOX_ACCOUNT=acc-xxxxx
$ export BRIGHTBOX_USER_NAME=jason.null@brightbox.com
$ export BRIGHTBOX_PASSWORD=mysecretpassword

Activate the brightbox plugin

Before using a configuration initialise terraform so that it knows about the Brightbox provider plugin

$ terraform init

Initializing provider plugins...
- Checking for available provider plugins on https://releases.hashicorp.com...
- Downloading plugin for provider "brightbox" (1.0.5)...

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

Execution plan

Now you have the example configuration checked out and your authentication configured, you can get terraform to show you its execution plan:

$ terraform plan

Refreshing Terraform state in-memory prior to plan...

The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

data.brightbox_image.webserver: Refreshing state...

------------------------------------------------------------------------

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:

  + brightbox_cloudip.db
      id:                   <computed>
      fqdn:                 <computed>
      locked:               <computed>
      name:                 "db ip"
      public_ip:            <computed>
      reverse_dns:          <computed>
      status:               <computed>
      target:               "${brightbox_database_server.db.id}"

  + brightbox_cloudip.webip
      id:                   <computed>
      fqdn:                 <computed>
      locked:               <computed>
      name:                 "web ip"
      public_ip:            <computed>
      reverse_dns:          <computed>
      status:               <computed>
      target:               "${brightbox_server.webserver.interface}"

  + brightbox_database_server.db
      id:                   <computed>
      admin_password:       <computed>
      admin_username:       <computed>
      allow_access.#:       <computed>
      database_engine:      "mysql"
      database_type:        <computed>
      database_version:     "5.6"
      locked:               <computed>
      maintenance_hour:     "2"
      maintenance_weekday:  "6"
      name:                 "db server"
      status:               <computed>
      zone:                 <computed>

  + brightbox_firewall_policy.webservers
      id:                   <computed>
      name:                 "web servers"
      server_group:         "${brightbox_server_group.webservers.id}"

  + brightbox_firewall_rule.webservers_outbound
      id:                   <computed>
      description:          "Outbound internet access"
      destination:          "any"
      firewall_policy:      "${brightbox_firewall_policy.webservers.id}"

  + brightbox_firewall_rule.webservers_ssh
      id:                   <computed>
      description:          "SSH access from anywhere"
      destination_port:     "22"
      firewall_policy:      "${brightbox_firewall_policy.webservers.id}"
      protocol:             "tcp"
      source:               "any"

  + brightbox_firewall_rule.webservers_web
      id:                   <computed>
      description:          "HTTP/S access from anywhere"
      destination_port:     "80,443"
      firewall_policy:      "${brightbox_firewall_policy.webservers.id}"
      protocol:             "tcp"
      source:               "any"

  + brightbox_server.webserver
      id:                   <computed>
      fqdn:                 <computed>
      hostname:             <computed>
      image:                "img-8q8yv"
      interface:            <computed>
      ipv4_address:         <computed>
      ipv4_address_private: <computed>
      ipv6_address:         <computed>
      ipv6_hostname:        <computed>
      locked:               <computed>
      name:                 "web server"
      public_hostname:      <computed>
      server_groups.#:      <computed>
      status:               <computed>
      type:                 "2gb.ssd"
      username:             <computed>
      zone:                 <computed>

  + brightbox_server_group.webservers
      id:                   <computed>
      name:                 "web servers"


Plan: 9 to add, 0 to change, 0 to destroy.

------------------------------------------------------------------------

Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.

Apply

The plan looks good so let’s actually create the cluster. Just run terraform apply:

$ terraform apply

data.brightbox_image.webserver: Refreshing state...

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:

  + brightbox_cloudip.db
      id:                   <computed>
      fqdn:                 <computed>
      locked:               <computed>
      name:                 "db ip"
      public_ip:            <computed>
      reverse_dns:          <computed>
      status:               <computed>
      target:               "${brightbox_database_server.db.id}"

  + brightbox_cloudip.webip
      id:                   <computed>
      fqdn:                 <computed>
      locked:               <computed>
      name:                 "web ip"
      public_ip:            <computed>
      reverse_dns:          <computed>
      status:               <computed>
      target:               "${brightbox_server.webserver.interface}"

  + brightbox_database_server.db
      id:                   <computed>
      admin_password:       <computed>
      admin_username:       <computed>
      allow_access.#:       <computed>
      database_engine:      "mysql"
      database_type:        <computed>
      database_version:     "5.6"
      locked:               <computed>
      maintenance_hour:     "2"
      maintenance_weekday:  "6"
      name:                 "db server"
      status:               <computed>
      zone:                 <computed>

  + brightbox_firewall_policy.webservers
      id:                   <computed>
      name:                 "web servers"
      server_group:         "${brightbox_server_group.webservers.id}"

  + brightbox_firewall_rule.webservers_outbound
      id:                   <computed>
      description:          "Outbound internet access"
      destination:          "any"
      firewall_policy:      "${brightbox_firewall_policy.webservers.id}"

  + brightbox_firewall_rule.webservers_ssh
      id:                   <computed>
      description:          "SSH access from anywhere"
      destination_port:     "22"
      firewall_policy:      "${brightbox_firewall_policy.webservers.id}"
      protocol:             "tcp"
      source:               "any"

  + brightbox_firewall_rule.webservers_web
      id:                   <computed>
      description:          "HTTP/S access from anywhere"
      destination_port:     "80,443"
      firewall_policy:      "${brightbox_firewall_policy.webservers.id}"
      protocol:             "tcp"
      source:               "any"

  + brightbox_server.webserver
      id:                   <computed>
      fqdn:                 <computed>
      hostname:             <computed>
      image:                "img-8q8yv"
      interface:            <computed>
      ipv4_address:         <computed>
      ipv4_address_private: <computed>
      ipv6_address:         <computed>
      ipv6_hostname:        <computed>
      locked:               <computed>
      name:                 "web server"
      public_hostname:      <computed>
      server_groups.#:      <computed>
      status:               <computed>
      type:                 "2gb.ssd"
      username:             <computed>
      zone:                 <computed>

  + brightbox_server_group.webservers
      id:                   <computed>
      name:                 "web servers"


Plan: 9 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value:

Type yes and hit enter. Terraform will then build your cluster:

brightbox_server_group.webservers: Creating...
  name: "" => "web servers"
brightbox_server_group.webservers: Creation complete after 0s (ID: grp-3zdjc)
brightbox_database_server.db: Creating...
  admin_password:          "" => "<computed>"
  admin_username:          "" => "<computed>"
  allow_access.#:          "" => "1"
  allow_access.2169567856: "" => "grp-3zdjc"
  database_engine:         "" => "mysql"
  database_type:           "" => "<computed>"
  database_version:        "" => "5.6"
  locked:                  "" => "<computed>"
  maintenance_hour:        "" => "2"
  maintenance_weekday:     "" => "6"
  name:                    "" => "db server"
  status:                  "" => "<computed>"
  zone:                    "" => "<computed>"
brightbox_firewall_policy.webservers: Creating...
  name:         "" => "web servers"
  server_group: "" => "grp-3zdjc"
brightbox_firewall_policy.webservers: Creation complete after 0s (ID: fwp-mhmxf)
brightbox_firewall_rule.webservers_web: Creating...
  description:      "" => "HTTP/S access from anywhere"
  destination_port: "" => "80,443"
  firewall_policy:  "" => "fwp-mhmxf"
  protocol:         "" => "tcp"
  source:           "" => "any"
brightbox_firewall_rule.webservers_outbound: Creating...
  description:     "" => "Outbound internet access"
  destination:     "" => "any"
  firewall_policy: "" => "fwp-mhmxf"
brightbox_server.webserver: Creating...
  fqdn:                     "" => "<computed>"
  hostname:                 "" => "<computed>"
  image:                    "" => "img-8q8yv"
  interface:                "" => "<computed>"
  ipv4_address:             "" => "<computed>"
  ipv4_address_private:     "" => "<computed>"
  ipv6_address:             "" => "<computed>"
  ipv6_hostname:            "" => "<computed>"
  locked:                   "" => "<computed>"
  name:                     "" => "web server"
  public_hostname:          "" => "<computed>"
  server_groups.#:          "" => "1"
  server_groups.2169567856: "" => "grp-3zdjc"
  status:                   "" => "<computed>"
  type:                     "" => "2gb.ssd"
  username:                 "" => "<computed>"
  zone:                     "" => "<computed>"
brightbox_firewall_rule.webservers_ssh: Creating...
  description:      "" => "SSH access from anywhere"
  destination_port: "" => "22"
  firewall_policy:  "" => "fwp-mhmxf"
  protocol:         "" => "tcp"
  source:           "" => "any"
brightbox_firewall_rule.webservers_outbound: Creation complete after 0s (ID: fwr-rfqgm)
brightbox_firewall_rule.webservers_ssh: Creation complete after 0s (ID: fwr-8yrt7)
brightbox_firewall_rule.webservers_web: Creation complete after 0s (ID: fwr-t9qkc)
brightbox_database_server.db: Still creating... (10s elapsed)
brightbox_server.webserver: Still creating... (10s elapsed)
brightbox_server.webserver: Creation complete after 14s (ID: srv-bzazl)
brightbox_cloudip.webip: Creating...
  fqdn:        "" => "<computed>"
  locked:      "" => "<computed>"
  name:        "" => "web ip"
  public_ip:   "" => "<computed>"
  reverse_dns: "" => "<computed>"
  status:      "" => "<computed>"
  target:      "" => "int-zc0f5"
brightbox_cloudip.webip: Creation complete after 3s (ID: cip-766q1)
brightbox_database_server.db: Creation complete after 2m2s (ID: dbs-5krgr)
brightbox_cloudip.db: Creating...
  fqdn:        "" => "<computed>"
  locked:      "" => "<computed>"
  name:        "" => "db ip"
  public_ip:   "" => "<computed>"
  reverse_dns: "" => "<computed>"
  status:      "" => "<computed>"
  target:      "" => "dbs-5krgr"
brightbox_cloudip.db: Creation complete after 0s (ID: cip-lyzey)

Apply complete! Resources: 9 added, 0 changed, 0 destroyed.

Outputs:

db admin account password = 3p33v4gnk1avcidk
db ip address = cip-lyzey.gb1.brightbox.com
web public ip address = cip-766q1.gb1.brightbox.com

Test it

To demonstrate that everything has been set up and linked together correct, test the MySQL connection from the new cloud server to the new cloud sql instance. Use the DNS names and password details from the Outputs section above:

$ ssh -l ubuntu cip-766q1.gb1.brightbox.com

ubuntu@srv-bzazl:~$ sudo apt-get update -qq
ubuntu@srv-bzazl:~$ sudo apt-get install -qq -y mysql-client

ubuntu@srv-bzazl:~$ mysql -h cip-bjj4c.gb1.brightbox.com -u admin -p
Enter password: 

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 70
Server version: 5.6.29-76.2-log Percona Server (GPL), Release 76.2, Revision ddf26fe

mysql> show status like 'Uptime';
+---------------|-------+
| Variable_name | Value |
+---------------|-------+
| Uptime        | 378   |
+---------------|-------+
1 row in set (0.00 sec)

mysql>

Terraform state data

Terraform keeps track of what resources it creates and their attributes in a state file named terraform.tfstate in the current directory. This is required for terraform to continue to manage your cluster, so keep it safe.

For each new cluster you want to manage, just create a new directory with a copy of your configs in.

Provisioning

If this was a real cluster, you’d obviously need to configure your new cloud server and deploy your app to it. These steps are usually best left to configuration management tools like Puppet, Ansible or Chef but Terraform can be told how to execute these once the server is online. See their Terraform documentation on provisioners for more details.

Destroy it

Since this is just a test cluster, you can tear it all down now. Just run terraform destroy and it’ll destroy just those resources that it created as part of this example.

$ terraform destroy

brightbox_server_group.webservers: Refreshing state... (ID: grp-3zdjc)
data.brightbox_image.webserver: Refreshing state...
brightbox_firewall_policy.webservers: Refreshing state... (ID: fwp-mhmxf)
brightbox_database_server.db: Refreshing state... (ID: dbs-5krgr)
brightbox_firewall_rule.webservers_outbound: Refreshing state... (ID: fwr-rfqgm)
brightbox_firewall_rule.webservers_web: Refreshing state... (ID: fwr-t9qkc)
brightbox_firewall_rule.webservers_ssh: Refreshing state... (ID: fwr-8yrt7)
brightbox_cloudip.db: Refreshing state... (ID: cip-lyzey)
brightbox_server.webserver: Refreshing state... (ID: srv-bzazl)
brightbox_cloudip.webip: Refreshing state... (ID: cip-766q1)

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  - brightbox_cloudip.db

  - brightbox_cloudip.webip

  - brightbox_database_server.db

  - brightbox_firewall_policy.webservers

  - brightbox_firewall_rule.webservers_outbound

  - brightbox_firewall_rule.webservers_ssh

  - brightbox_firewall_rule.webservers_web

  - brightbox_server.webserver

  - brightbox_server_group.webservers


Plan: 0 to add, 0 to change, 9 to destroy.


brightbox_firewall_rule.webservers_web: Destroying... (ID: fwr-t9qkc)
brightbox_firewall_rule.webservers_ssh: Destroying... (ID: fwr-8yrt7)
brightbox_cloudip.db: Destroying... (ID: cip-lyzey)
brightbox_firewall_rule.webservers_outbound: Destroying... (ID: fwr-rfqgm)
brightbox_cloudip.webip: Destroying... (ID: cip-766q1)
brightbox_firewall_rule.webservers_ssh: Destruction complete after 0s
brightbox_firewall_rule.webservers_web: Destruction complete after 1s
brightbox_firewall_rule.webservers_outbound: Destruction complete after 1s
brightbox_cloudip.db: Destruction complete after 4s
brightbox_database_server.db: Destroying... (ID: dbs-5krgr)
brightbox_cloudip.webip: Destruction complete after 4s
brightbox_server.webserver: Destroying... (ID: srv-bzazl)
brightbox_database_server.db: Still destroying... (ID: dbs-5krgr, 10s elapsed)
brightbox_server.webserver: Still destroying... (ID: srv-bzazl, 10s elapsed)
brightbox_database_server.db: Destruction complete after 10s
brightbox_server.webserver: Destruction complete after 10s
brightbox_firewall_policy.webservers: Destroying... (ID: fwp-mhmxf)
brightbox_firewall_policy.webservers: Destruction complete after 0s
brightbox_server_group.webservers: Destroying... (ID: grp-3zdjc)
brightbox_server_group.webservers: Destruction complete after 1s

Destroy complete! Resources: 9 destroyed.

If you’d rather not completely trust Terraform, remember you can use our “resource lock” feature to prevent accidental deletions of important resources.

Further details

You can read more about the resources and data sources available in the Brightbox Cloud Terraform Provider in the documentation section of the Terraform website

Last updated: 13 Sep 2018 at 11:16 UTC

Try Brightbox risk-free with £20 free credit Sign up takes just two minutes...