Getting Started Using Terraform with OCI

November 1, 2018 | 6 minute read
John Featherly
Cloud Native Architect
Text Size 100%:

Introduction

Standing up infrastructure requires building networks, servers and storage entailing complex build and configuration management processes. Traditionally done with scripts or even manually, Terraform gives you a new alternative. Using Terraform you can write a declarative description of your infrastructure. Using the Terraform "compiler" the declaration is converted to a build plan and then the Terraform "builder" connects to your OCI tenancy and executes the plan. It is actually a bit more sophisticated than just doing the initial build. The builder connects to your tenancy and synchronizes it with the plan. Anything that already exists is left as-is, anything new is created and anything not in the plan is deleted. This allows you to edit your infrastructure by simply editing the Terraform code. Version control becomes only a matter of version control on the Terraform code.

The Shortest Path Example

In this example we'll take the shortest path to creating a simple resource in an OCI tenancy using Terraform code to demonstrate the steps involved in getting started with Terraform. To try it out you will need the following.

  • an OCI tenancy
  • API SSL key pair
  • Terraform executable
  • code sample
  • Terraform OCI provider

Of course you will also need a personal computer to run Terraform. Pretty much anything will do; Linux, Mac or Windows it just needs a bash shell. Easy enough on Linux and Mac, on Windows I've found MobaXterm or Git Bash to be reasonable choices.

Your OCI Tenancy

Login to the OCI console for your tenancy and collect the following identifying information

  • tenancy ID
  • user ID
  • compartment ID

These identifiers are all OCID's (pronounced O-sid) that look like ocid1.tenancy.oc1..aaaaaaaawpqblfemtluwxipipubxhioptheej2r32gvf7em7iftkr3vd2r3a<_span> and can be found on the tenancy and user information pages of the OCI console.

API SSL Key

You will need an SSL key pair to enable Terraform to connect to the OCI API under your identity. Start by generating a key

user@computer$ openssl genrsa -out oci_api_key.pem 2048

set file access to owner only read and write

user@computer$ chmod 600 oci_api_key.pem

generate the public half of the key pair

user@computer$ openssl rsa -pubout -in oci_api_key.pem -out oci_api_key_public.pem

The public key needs to be added to your user account in the OCI console. Open the account page for your user and select the "Add Public Key" button. Copy and paste the contents of the oci_api_key_public.pem file in the box of the "Add Public Key" dialog as shown below.

Notice that after the public key is added the fingerprint is listed in the "API Keys" list. Copy the fingerprint for later use.

Terraform Executable

The Terraform executable is available at terraform.io Available for Linux, Mac Windows etc. pick the binary that matches your PC.

The download contains a single executable file. Unzip it to a directory that is on your PATH for example _home_me_bin. In order to update the executable when a new version is released simply download the new version, unzip and replace the executable.

The Terraform Code<_h4>

As a basic example we'll put together Terraform code to make a VCN (Virtual Cloud Network) in OCI. There are a number of ways to get the identifier information we collected into the code but the most common is by using environment variables. The top of our code sample will reference the environment variables as shown. Create a development directory and add the following to a file called vcn.tf.

variable "tenancy_ocid" {}
variable "user_ocid" {}
variable "fingerprint" {}
variable "private_key_path" {}
variable "compartment_ocid" {}
variable "region" {}
provider "oci" {
  version          = ">= 3.0.0"
  tenancy_ocid     = "${var.tenancy_ocid}"
  user_ocid        = "${var.user_ocid}"
  fingerprint      = "${var.fingerprint}"
  private_key_path = "${var.private_key_path}"
  region           = "${var.region}"
}<_pre>

The corresponding environment variables have the form TF_VAR_* and hold the identity and connection information to the tenancy, user and compartment we collected earlier. Typically, put the following statements in a .sh file and source the file to set the environment values.

export TF_VAR_tenancy_ocid=ocid1.tenancy.oc1..aaaaaaaawpqblfe ...
export TF_VAR_user_ocid=ocid1.user.oc1..aaaaaaaacwmzc7bt ...
export TF_VAR_fingerprint=43:7b:50:07: ...
export TF_VAR_private_key_path=oci_api_key.pem
### Region
export TF_VAR_region=uk-london-1
### Compartment
export TF_VAR_compartment_ocid=ocid1.compartment.oc1..aaaaaaaaxxj ...<_pre>

Now add the following Terraform code that declares a VCN to the bottom of the vcn.tf file.

resource "oci_core_virtual_network" "simple-vcn" {
  cidr_block     = "10.0.0.0_16"
  dns_label      = "vcn1"
  compartment_id = "${var.compartment_ocid}"
  display_name   = "simple-vcn"
}<_pre>

The code declares a VCN resource named simple-vcn in the compartment identified from the compartment OCID environment variable.

Terraform OCI Provider<_h4>

The OCI provider is registered at Hashicorp and Terraform will download and update the plugin automatically as needed. In the directory containing the vcn.tf file run the init command as follows.

user@computer$ terraform init<_pre>

You should see something like the following showing that the provider has been downloaded and installed in the working directory.

user@computer$ terraform init
Initializing provider plugins...
- Checking for available provider plugins on https:__releases.hashicorp.com...
- Downloading plugin for provider "oci" (3.5.0)...
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.<_pre>

Executing terraform -version<_span> will confirm the Terraform version and the provider version.

user@computer$ terraform -version
Terraform v0.11.10
+ provider.oci v3.5.0<_pre>

Running<_h3>

To create the build plan execute terraform plan<_span> in the working directory.

user@computer$ 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:
  + oci_core_virtual_network.simple-vcn
      id:                                                                 <computed>
      cidr_block:                                                         "10.0.0.0_16"
      compartment_id:                                                     "ocid1.compartment.oc1..aaaaaaaaxxjdxgyjxqxoiiv7yyb2zgez4pxaubsee4oguejnggwzhokqzhwa"
      default_dhcp_options_id:                                            <computed>
      default_route_table_id:                                             <computed>
      default_security_list_id:                                           <computed>
      display_name:                                                       "simple-vcn"
      dns_label:                                                          "vcn1"
      freeform_tags.%:                                                    <computed>
      state:                                                              <computed>
      time_created:                                                       <computed>
      vcn_domain_name:                                                    <computed>
Plan: 1 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.<_pre>

To create the resource execute terraform apply<_span> in the working directory.

user@computer$ 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:
  + oci_core_virtual_network.simple-vcn
      id:                       <computed>
      cidr_block:               "10.0.0.0_16"
      compartment_id:           "ocid1.compartment.oc1..aaaaaaaaxxjdxgyjxqxoiiv7yyb2zgez4pxaubsee4oguejnggwzhokqzhwa"
      default_dhcp_options_id:  <computed>
      default_route_table_id:   <computed>
      default_security_list_id: <computed>
      display_name:             "simple-vcn"
      dns_label:                "vcn1"
      freeform_tags.%:          <computed>
      state:                    <computed>
      time_created:             <computed>
      vcn_domain_name:          <computed>
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
oci_core_virtual_network.simple-vcn: Creating...
  cidr_block:               "" => "10.0.0.0_16"
  compartment_id:           "" => "ocid1.compartment.oc1..aaaaaaaaxxjdxgyjxqxoiiv7yyb2zgez4pxaubsee4oguejnggwzhokqzhwa"
  default_dhcp_options_id:  "" => "<computed>"
  default_route_table_id:   "" => "<computed>"
  default_security_list_id: "" => "<computed>"
  display_name:             "" => "simple-vcn"
  dns_label:                "" => "vcn1"
  freeform_tags.%:          "" => "<computed>"
  state:                    "" => "<computed>"
  time_created:             "" => "<computed>"
  vcn_domain_name:          "" => "<computed>"
oci_core_virtual_network.simple-vcn: Creation complete after 1s (ID: ocid1.vcn.oc1.uk-london-1.aaaaaaaajnknx...aa3tnnzvkxutb7urmrygugvvfnr77jcg6zy5pa)
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.<_pre>

Checking the network resources in the console we see the VNC has been created.

Execute terraform destroy<_span> to terminate the resource.

user@computer$ terraform destroy
oci_core_virtual_network.simple-vcn: Refreshing state... (ID: ocid1.vcn.oc1.uk-london-1.aaaaaaaajnknx...aa3tnnzvkxutb7urmrygugvvfnr77jcg6zy5pa)
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:
  - oci_core_virtual_network.simple-vcn
Plan: 0 to add, 0 to change, 1 to destroy.
Do you really want to destroy all resources?
  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
oci_core_virtual_network.simple-vcn: Destroying... (ID: ocid1.vcn.oc1.uk-london-1.aaaaaaaajnknx...aa3tnnzvkxutb7urmrygugvvfnr77jcg6zy5pa)
oci_core_virtual_network.simple-vcn: Destruction complete after 1s
Destroy complete! Resources: 1 destroyed.<_pre>

Summary

Terraform provides a powerful tool to create and manage infrastructure as code. Future additions to the tool set will likely include visual layout designers that will produce Terraform code from infrastructure diagrams and spreadsheets. Infrastructure as code is also a great option to rebuild environments in disaster recovery scenarios.

John Featherly

Cloud Native Architect


Previous Post

Performance of MFT Cloud Service (MFTCS) with File Storage Service (FSS) using a Hybrid Solution Architecture in Oracle Cloud Infrastructure (OCI)

Shub Lahiri | 15 min read

Next Post


Using the IDCS' OAuth Device Flow for Fun and Profit

Christopher Johnson | 11 min read