Overview

Skill Level: Intermediate

Terraform is 'infrastructure as code' automation software by HashiCorp. It allows users to define (clloud) infrastructure in a high-level scripting language, which can be executed to build the infrastructure on the desired cloud platform.

Ingredients

Terraform, IBM Cloud IaaS

 

IBM Cloud IaaS account

IBM Cloud Infrastructure API key

IaaS permissions to create and deploy servers, configure network interfaces

A control workstation on which Terraform can be installed and executed. 

 

 

Step-by-step

  1. Terraform and IBM Cloud

    As the size on complexity of cloud hosted applications grows’, manually buiding cloud infrastructure via a UI can become slow and error-prone. It is also not repeatable, limiting the ability to build development and test environments that match what will be used in production.¬†

    Terraform is a tool for building cloud environments, the focus was IaaS, but it supports any service (PaaS or FaaS) that can be configured by an API , so includes database services, DNS, CDNs and many other resources. Terraform is open-source, its developer Hashicorp also offers a proprietry solution, though by itself the open-source solution offers a lot of value in automating environment builds using the idea of ‘infrastructure as code’, versioning and managing infrastructure in the same way that developers manage code.¬†

     

    Automating Infrastructure provisioning

    Terraform enables predictable and consistent provisioning of IBM Cloud environments:

    • The same configuration can be used for development, test and production, ensuring consistency and a known working configuration
    • Environments can be provisioned on demand, reducing costs for test and development environments which can be spun up as needed.¬†
    • Reduces the potential for human error while deploying infrastructure

    Configurations are also reasonably portable. Each cloud provider may offer different features, but are all similar enough in offering VMs, networking etc that a configuration can be easily ported. It is certainly less work that moving from one cloud-specific provisioning framework to another. 

    The Terraform infrastructure as code approach, also offers another benefit of understanding the impact of infrastructure changes before they occur. The Terraform command line interface allows users to ‘plan’ a confguration and preview the changes that will be performed on the environment. Team members can collaborate on changes, previewing and validating the impact of any change. Configurations can also be managed through a configuration tool such as GitHub, tracking and versioning all environment change and ensuring that the infrastructure matches the application code.¬†

     

    Infrastructure and applications

    Terraform’s role is at the infrastructure level. It is not part of the solution to install software on virtual machines. There are many excellent open-source and proprietry tools for installing and managing application installation and updates, including Puppet, Chef and Ansible. Integration solutions exist that enable the results of a Terraform¬†operation to be consumed by these tools to automate the complete end to end build of infrastructure and applications.¬†

     

    Terraform providers

    Terraform works with providers to interact with the open marketplace of cloud platforms, including IBM Cloud. It is the provider that is responsible for understanding API interactions and exposing the resources of the cloud platform you are working with. 

    IBM provides the Terraform IBM plugin to support IBM Cloud. By utilizing Terraform and the Terraform IBM plugin, you can manage the lifecycle of IBM Cloud Infrastructure and services supporting business applications. 

     

    Archirecture Overview

    The desired infrastructure configuration is read from tf files, along with environment variables from terraform.tfvars. Via the IBM provider using the IBM Cloud REST APIs, Terraform deploys the desired infrastructure and records the final state in the terraform.tfstate file.

    terraform_ov-1

  2. Install Terraform

    To use terraform to manage IBM Cloud, it is necessary to install Terraform and the terraform-provider-ibm binaries. The instructions here assume that Terraform is being installed on the users workstation, in this case Mac OSX. However it could be any server that has access to the Internet. 

    Create a terraform directory

    mkdir $HOME/terraform
    cd terraform

    Download a terraform binary from https://www.terraform.io/downloads.html and copy into the created directory

    Ensure that the $PATH environment variable is updated to point to the terraform directory. On Linux or Mac, you need to add the following to your ~/.profile or ~/.bashrc or or ~/.bash_profile

    export PATH=$PATH:$HOME/terraform

    Check the Terraform installation by running the terraform command in your terminal or command prompt window. You should see a list of Common commands. 

    $ terraform

    Usage: terraform [--version] [--help] <command> [args]
    The available commands for execution are listed below.
    The most common, useful commands are shown first, followed by
    less common or more advanced commands. If you're just getting
    started with Terraform, stick with the common commands. For the
    other commands, please read the help and docs before usage

    Common commands:
        apply              Builds or changes infrastructure
        console            Interactive console for Terraform interpolations
        destroy            Destroy Terraform-managed infrastructure
        env                Workspace management
        fmt                Rewrites config files to canonical format
      ....... 
        version            Prints the Terraform version
        workspace          Workspace management

    All other commands:
        debug              Debug output management (experimental)
        force-unlock       Manually unlock the terraform state
        state              Advanced state management
  3. Install IBM Terraform Provider

    To support a multi-cloud approach, Terraform works with providers. A provider is responsible for understanding API interactions and exposing resources. In this section, you will download and configure the IBM Cloud provider.

    Download the latest version of the terraform-provider-ibm binary from https://github.com/IBM-Cloud/terraform-provider-ibm/releases

    For non-Windows systems, create a .terraform.d/plugins directory in your user’s home directory and place the binary plugin file inside of it. Use the following commands for reference.

    mkdir $HOME/.terraform.d/plugins
    mv $HOME/Downloads/terraform-provider-ibm $HOME/.terraform.d/plugins/ 

    Test the terraform-provider-ibm plugin as well. You will get the following result.

    cd $HOME/.terraform.d/plugins
    ./terraform-provider-ibm

    2018/09/04 16:40:52 IBM Cloud Provider version 0.10.0  9d816c8293dd1d8428bef979142a626ef6ab940e
    This binary is a plugin. These are not meant to be executed directly.
    Please execute the program that consumes these plugins, which will
    load any plugins automatically

     

  4. Configure Terraform for IBM Cloud

    Terraform communicates with the IBM Cloud via REST API. To securely access the IBM Cloud you need to provide both the IBM Cloud API key and SoftLayer API key credentials. The IBM provider can utilise two different ways to present the credentials it requires.

    • static tf variables
    • environment variables

    In this tutorial static variables will be used, as it allows easier sharing of configurations between users, but requires good oversight of file security permissions and avoiding exposing API keys on public repositories. See https://ibm-cloud.github.io/tf-ibm-docs/index.html#using-terraform-with-the-ibm-cloud-provider for more details of how to use Environment variables. 

    Download the sample files to your terraform directory. These define the provider, credentials and the resource to be provisioned.  

    git clone https://github.com/stevestrutt/terraform_sample

    Variables defined in the terraform.tfvars file are automatically loaded by Terraform. This approach is used in this example. Open terraform.tfvars with your editor, modify the file by adding all the credentials listed, adding these credentials in that files means you don’t need to re-enter these credentials every time running terraform apply. You must add all credentials listed in the terraform.tfvars file in order to complete the rest of this tutorial.

    • SL_USERNAME is a SoftLayer user name. Go to https://control.bluemix.net/account/user/profile, scroll down, and check API Username.
    • SL_API_KEY is a SoftLayer API Key.¬†Go to https://control.bluemix.net/account/user/profile, scroll down, and check Authentication Key.
    • BM_API_KEY – An API key for IBM Cloud services. If you don’t have one already, go to https://console.bluemix.net/iam/#/apikeys and create a new key.

    Note add terraform.tfvars to your .gitignore file or similar to ensure that it is not pushed to a public code repository. See the Terraform Variables documentation for other ways of protecting local secrets. 

  5. Basic Terraform operation

    This section provides basic terraform commands with a sample resource configuration file. If you are familiar with Terraform, you can skip this section.

    See https://www.terraform.io/docs/configuration/index.html for terraform configuration instructions. Especially, Configuration Syntax, Interpolation Syntax, Resources, Variables provide the major concepts.

    https://ibm-cloud.github.io/tf-ibm-docs/index.html provides reference guides for Terraform IBM plugin.

    You will review the configuration file using terraform plan, create a virtual server using terraform apply, and check the current resource status using terraform show.

    • Create an empty directory.
    • Create a file sample.tf with the following definition.
    resource "ibm_compute_vm_instance" "vm1" {
    hostname = "vm1"
    domain = "example.com"
    os_reference_code = "DEBIAN_7_64"
    datacenter = "dal09"
    network_speed = 10
    hourly_billing = true
    private_network_only = false
    cores = 1
    memory = 1024
    disks = [25] local_disk = false
    }

    Execute terraform init to initialize Terraform IBM plugin. You will get the following messages.

    $ terraform init

    Initializing provider plugins...

    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.

    When you execute terraform plan, Terraform performs the following tasks.

    • Terraform reads example.tf and validates the resource definitions and syntax.
    • Terraform reads any existing¬†terraform.tfstate file, checks the current terraform resource IDs, and retrieves the resource information from IBM Cloud using API calls with the resource IDs.
    • Terraform compares the difference between example.tf and the resource information in IBM Cloud and provides a plan report.

    The following is the result of terraform plan.¬†The result describes that it will create a new virtual server in IBM Cloud. The VM’s hostname will be vm1. Once the VM is created, Terraform will get the actual ID of the created IBM Cloud Virtual Server and use it as¬†the id of ibm_compute_vm_instance.vm1.

    $ 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.
    ------------------------------------------------------------------------
    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:

      + ibm_compute_vm_instance.vm1

          id:                           <computed>
          block_storage_ids.#:          <computed>
          cores:                        "1"
          datacenter:                   "dal09"
          disks.#:                      "1"
          disks.0:                      "25"
          domain:                       "example.com"
          file_storage_ids.#:           <computed>
          hostname:                     "vm1"
          hourly_billing:               "true"
          ip_address_id:                <computed>
          ip_address_id_private:        <computed>
        ipv4_address:                 <computed>
          ipv4_address_private:         <computed>
          ipv6_address:                 <computed>
          ipv6_address_id:              <computed>
          ipv6_enabled:                 "false"
          ipv6_static_enabled:          "false"
          local_disk:                   "false"
          memory:                       "1024"
          network_speed:                "10"
          os_reference_code:            "CENTOS_7_64"
          private_interface_id:         <computed>
          private_network_only:         "false"
          private_security_group_ids.#: <computed>
          private_subnet:               <computed>
          private_subnet_id:            <computed>
          private_vlan_id:              <computed>
          public_bandwidth_limited:     <computed>
          public_bandwidth_unlimited:   "false"
          public_interface_id:          <computed>
          public_ipv6_subnet:           <computed>
          public_ipv6_subnet_id:        <computed>
          public_security_group_ids.#:  <computed>
          public_subnet:                <computed>
          public_subnet_id:             <computed>
          public_vlan_id:               <computed>
          secondary_ip_addresses.#:     <computed>
          wait_time_minutes:            "90"

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

     
    Now create the virtual server using terraform apply. Response yes to the prompt.

    [NOTE] It will create an hourly virtual server in your IBM Cloud account and cost will be charged.

    $ terraform apply

    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:

      + ibm_compute_vm_instance.vm1
          id:                           <computed>
          block_storage_ids.#:          <computed>
          cores:                        "1"
          datacenter:                   "dal09"

          ......

    Plan: 1 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: yes

    ibm_compute_vm_instance.vm1: Creating...

    ibm_compute_vm_instance.vm1: Still creating... (10s elapsed)
    ibm_compute_vm_instance.vm1: Still creating... (20s elapsed)
    ibm_compute_vm_instance.vm1: Still creating... (30s elapsed)
    ibm_compute_vm_instance.vm1: Still creating... (40s elapsed)
    ibm_compute_vm_instance.vm1: Still creating... (50s elapsed)
    ibm_compute_vm_instance.vm1: Still creating... (1m0s elapsed)
    ibm_compute_vm_instance.vm1: Still creating... (1m10s elapsed)
    ibm_compute_vm_instance.vm1: Still creating... (1m20s elapsed)
    ibm_compute_vm_instance.vm1: Still creating... (1m30s elapsed)
    ibm_compute_vm_instance.vm1: Still creating... (1m40s elapsed)
    ibm_compute_vm_instance.vm1: Still creating... (2m0s elapsed)
    ibm_compute_vm_instance.vm1: Still creating... (2m10s elapsed)
    ibm_compute_vm_instance.vm1: Still creating... (2m20s elapsed)
    ibm_compute_vm_instance.vm1: Still creating... (2m30s elapsed)
    ibm_compute_vm_instance.vm1: Still creating... (2m40s elapsed)
    ibm_compute_vm_instance.vm1: Creation complete after 2m44s (ID: 60948867)

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

     
    It will take a few minutes to complete the provisioning. You can check the details of the virtual server at https://control.bluemix.net/devices

    After the completion of the virtual server provisioning, Terraform creates a terraform.tfstate file and saves information about the infrastructure configured, in this case the virtual server . You can inspect the contents of this file using a text editor.

  6. Showing and updating resources

    Check the virtual server information using the terraform show command. This reads the terraform.tfstate file and displays information Terraform has recorded about the virtual server. 

    $ terraform show

    ibm_compute_vm_instance.vm1:
      id = 60948867
      block_storage_ids.# = 0
      cores = 1
      datacenter = dal09
      dedicated_acct_host_only = false
      disks.# = 1
      disks.0 = 25
      domain = example.com
      file_storage_ids.# = 0
      hostname = vm1
      hourly_billing = true
      ip_address_id = 119153307
      ip_address_id_private = 119154963
      ipv4_address = 169.46.192.34
      ipv4_address_private = 10.173.135.134
      ipv6_enabled = false
      ipv6_static_enabled = false
      local_disk = false
      memory = 1024
      network_speed = 10
      notes =
      os_reference_code = CENTOS_7_64
      private_interface_id = 35066699
      private_network_only = false
      private_security_group_ids.# = 0
      private_subnet = 10.173.135.128/26
      private_subnet_id = 1304363
      private_vlan_id = 2433445
      public_bandwidth_unlimited = false
      public_interface_id = 35066701
      public_security_group_ids.# = 0
      public_subnet = 169.46.192.32/28
      public_subnet_id = 1810073
      public_vlan_id = 2433443
      secondary_ip_addresses.# = 0
      wait_time_minutes = 90

    Some properties are editable. Open sample.tf and change the value of network_speed to 100. When you execute terraform plan, it will report that network_speed will be changed to 100 as follows:
     

    $ 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.

    ibm_compute_vm_instance.vm1: Refreshing state... (ID: 51404681)

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

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

    Terraform will perform the following actions:

    ~ ibm_compute_vm_instance.vm1
    network_speed: "10" => "100"

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

     

    Execute terraform apply to update the value of network_speed to 100.

    You can check the status using terraform show. The IBM Cloud IaaS portal page will show the updated information.

    Some VM configuration settings can be changed in IBM Cloud IaaS portal. Terraform will detect these changes and revert them back to the planned confguration if required. Change the number of the processors to 2 in the IaaS portal from the Modify Device Configuration button on the Device Details page for the VM. Once the change is complete execute a terraform refresh. Terraform will get the updated virtual server information and update the terraform.tfstate file. Now a terraform show will display two processors as follows:
     

     

    $ terraform refresh
    $ terraform show
    ibm_compute_vm_instance.vm1:
      id = 60948867
      block_storage_ids.# = 0


      cores = 2
    ...
  7. Deleting resources

    Delete the virtual server using the terraform destroy command.

    $ terraform destroy

    ibm_compute_vm_instance.vm1: Refreshing state... (ID: 60948867)
    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:

      - ibm_compute_vm_instance.vm1

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

    Do you really want to destroy?
      Terraform will destroy all your managed infrastructure, as shown above.
      There is no undo. Only 'yes' will be accepted to confirm.

      Enter a value: yes

    ibm_compute_vm_instance.vm1: Destroying... (ID: 60948867)
    ibm_compute_vm_instance.vm1: Still destroying... (ID: 60948867, 10s elapsed)
    ibm_compute_vm_instance.vm1: Destruction complete after 14s
    Destroy complete! Resources: 1 destroyed.

1 comment on"Infrastructure automation with Terraform on IBM Cloud IaaS"

  1. Benedetto Lo Giudice January 22, 2019

    Thanks for this, just trying it I got an error:

    “`
    tf init
    There are some problems with the configuration, described below.

    The Terraform configuration must be valid before initialization so that
    Terraform can determine which modules and providers need to be installed.

    Error: Error parsing /Users/neo/workspace/terraform_sample/sample.tf: At 8:26: Unknown token: 8:26 IDENT yes
    “`

    I had to comment line 8 in the example (I am sorry but I don’t have time to dig deeper):

    “`
    resource “ibm_compute_vm_instance” “vm1” {
    hostname = “vm1”
    domain = “example.com”
    os_reference_code = “CENTOS_7_64”
    datacenter = “dal09”
    network_speed = 100
    hourly_billing = true

    # private_network_only = yes
    cores = 1
    memory = 1024
    disks = [25]
    local_disk = false
    }
    “`

    Other than that, it worked, thanks a lot.
    Now I need to see why my own homegrown example is getting this error:

    “`
    1 error(s) occurred:

    * ibm_container_cluster.cluster: 1 error(s) occurred:

    * ibm_container_cluster.cluster: Request failed with status code: 401, ServerErrorResponse: {“incidentID”:”968b50ef-fb39-4a8c-812f-b9dccd3d067f”,”code”:”E0057″,”description”:”Unable to connect to the IBM Cloud account. Ensure that you have a paid account.”,”type”:”Authentication”,”recoveryCLI”:”Run ‘ibmcloud ks credentials-set’ with your IBM Cloud user name and API key.”}

    Terraform does not automatically rollback in the face of errors.
    Instead, your Terraform state file has been partially updated with
    any resources that successfully completed. Please address the error
    above and apply again to incrementally change your infrastructure.
    “`

Join The Discussion