Using the IBM Cloud Provider to Provision Infrastructure

Share this post:

The IBM Cloud Provider is a Terraform plugin that lets you provision and orchestrate IBM Cloud resources. Terraform is a popular opensource infrastructure as code (IaC) solution supporting all the leading public cloud providers. Terraform templates describe the “to be” state of the infrastructure you want. The terraform engine takes a template and does the orchestration needed to transform the “as is” state to the “to be”.

The IBM Cloud Provider supports virtual machines, load balancers, IBM Containers, Watson services, Cloudant, and more. Using the provider you can create templates to provision the entire Bluemix service catalog. This article looks at how a fictitious services company uses Terraform and the IBM Cloud Provider to deliver client solutions.

Our Scenario

JK Services is a vertical solution provider with a focus on marketing automation solutions. Their flagship solution is ADA, the Ad Delivery Analytics application. ADA is a cloud native application that leverages IBM Watson to tailor online advertising and content delivery to website and app users. Put simply, ADA is an AI ad server.

For security and marketing reasons JK customers get their own instance of ADA when they purchase the SaaS application. Provisioning all the cloud infrastructure for even one ADA implementation was a manual, error-prone, and lengthy process. Using the IBM Cloud Provider, JK is able to provision and manage the infrastructure of each client in a repeatable and automated way. In addition, JK can be confident that each instance of the ADA application has the same infrastructure and software components.

ADA Infrastructure

ADA infrastructure architecture

ADA – the Ad Delivery Analytics app

The ADA application uses a number of cloud resources:

  • A kubernetes cluster deployed using IBM Containers is responsible for delivering content based on a visitor’s profile and preferences.
  • A click handler farm of virtual machines logs all events and actions the user takes on the delivered content (e.g. clicking on an ad)
  • The Cloudant NoSQL database stores visitor profile and preference information
  • IBM Watson Personality Insights and IBM’s BigInsigts Hadoop cluster injest the raw event logs and populate the visitor profile and preference database
  • Object Storage does log management and stores ad creatives and other delivered content

ADA Templates

Using the IBM Cloud Provider, JK Services built a number of Terraform templates to automatically provision the ADA infrastructure. Let’s look at different parts of their template…

IBM Cloud Provider Credentials

Since Terraform supports more than 50 plugin providers you have to explicitly say which provider you are using and give the necessary credentials for provisioning cloud resources.

provider "ibm" {
bluemix_api_key = "${var.bluemix_api_key}"
softlayer_username = "${var.softlayer_username}"
softlayer_api_key = "${var.softlayer_api_key}"

This snippet shows the three (3) needed credentials to provision IBM Cloud resources:

  • An IBM Bluemix API key
  • A softlayer username
  • A softlayer API key

You can use environment variables like SL_API_KEY to specify these credentials or you can use Terraform variables. We use variables in this example. For example, the pattern "${var.NAME}” references the variable “NAME”. Here we have variables bluemix_api_key, softlayer_username, and softlayer_api_key defined.

variable "bluemix_api_key" {}
variable "softlayer_username" {}
variable "softlayer_api_key" {}

Variables can optionally have descriptions and default values. We’ll see examples of these later.

IBM Containers Based Kubernetes Cluster

Serving ads and content is the responsibility of an ad server. The ad server runs on a Kubernetes cluster implemented with IBM Containers and has to integrate with the profiles and preferences database.

Here’s the template definition for the ad server cluster:

resource "ibm_container_cluster" "ad_server_cluster" {
count = "${var.create_ad_server}"

name = "ad-server-cluster-${}"
datacenter = "${var.datacenter}"
org_guid = "${}"
space_guid = "${}"
account_guid = "${}"
no_subnet = true
subnet_id = ["${var.subnet_id}"]

workers = [
name = "worker1"
action = "add"
name = "worker2"
action = "add"
name = "worker3"
action = "add"
name = "worker4"
action = "add"
name = "worker5"
action = "add"

machine_type = "${var.machine_type}"
isolation = "${var.isolation}"
public_vlan_id = "${var.public_vlan_id}"
private_vlan_id = "${var.private_vlan_id}"

We can see that ad_server_cluster is specified as an ibm_container_cluster resource. Parts of the specification are hard-coded. For example, the workers array specifically says this is a 5-node cluster. Other parts of the spec use user-supplied values. For example, the datacenter where the cluster is deployed and the type of machine are specified using the variables datacenter and machine_type respectively.

variable "datacenter" {
description = "Datacenter location for the cluster"
default = "dal12"
variable "machine_type" {
description = "Cluster node machine type"
default = "u1c.2x4"

Integrating with the Cloudant NoSQL Database

Cloudant database instances are available as a service in the IBM Bluemix catalog. The IBM Cloud Provider uses the service_resource to specify any and all Bluemix services. Describing a service just needs the name and billing information for the service:

resource "ibm_service_instance" "profiledb" {
name = "profiledb-${}"
space_guid = "${}"
service = "cloudantNoSQLDB"
plan = "Lite"
tags = ["adserver"]

Here we are using the free (“Lite”) plan for Cloudant. As stated above, specifying a Watson service like Personality Insights would be exactly the same. The only difference would be the name of the service and the plan being used.

NOTE: One of the things you might have noticed is that all resources have a name. Since JK Services is building out the same infrastructure for each customer they need to use unique names for all the resources. For example, the Cloudant database will have a name like “profiledb-A4By” because a variable random_id is used as a suffix on all resource names.

IBM Container clusters can use any IBM Service via a service binding. The service binding makes connection credentials available in the cluster’s environment. The IBM Cloud Provider resource for this is aptly called ibm_container_bind_service.

resource "ibm_container_bind_service" "profiledb_bind_service" {
cluster_name_id = "${}"
service_instance_space_guid = "${}"
service_instance_name_id = "${}"
namespace_id = "default"
org_guid = "${}"
space_guid = "${}"
account_guid = "${}"

The profiledb_bind_service references the cluster’s name using the cluster resource directly (${}). The same is done for the Cloudant database service. You can reference any resource using Terraform’s ${TYPE.NAME.ATTRIBUTE} interpolation syntax.

Planning & Applying the Template

Terraform supports two separate actions with templates: plan and apply. “Plan” is a dry run. When you do a terraform plan you get back a report on the resources that needed to be created, updated, or deleted based on the template definitions and the current state of the infrastructure.

Here’s a snippet from a terraform plan report:

~/dev/ADA $ 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. Refreshing state... Refreshing state...
data.ibm_account.account: Refreshing state...
The Terraform execution plan has been generated and is shown below.
Resources are shown in alphabetical order for quick scanning. Green resources
will be created (or destroyed and then created if an existing resource
exists), yellow resources are being changed in-place, and red resources
will be destroyed. Cyan entries are data sources to be read.

Note: You didn't specify an "-out" parameter to save this plan, so when
"apply" is called, Terraform can't guarantee this is what will execute.

+ ibm_compute_autoscale_group.sample-http-cluster
cooldown: "30"
health_check.{07c2b926d154bd5dc241f595a572d3349d41d98f2484798a4a616f4fafe1ebc0}: "1"
health_check.type: "HTTP"
maximum_member_count: "10"
minimum_member_count: "1"
name: "${}-${}"
port: "80"
regional_group: "as-sgp-central-1"
termination_policy: "CLOSEST_TO_NEXT_CHARGE"
virtual_guest_member_template.#: "1"
virtual_guest_member_template.0.block_storage_ids.#: "&lt;computed&gt;"
virtual_guest_member_template.0.cores: "1"


The terraform apply action is what takes the as-is state of the infrastructure and transforms it to the to-be state as described by the template. The apply action can take some time depending on the number and type of resources you are provisioning.


Using the IBM Cloud Provider JK Services is able to specify their infrastructure using simple text file templates and leverage the Terraform engine to manage their deployment in a repeatable and automated way. The IBM Cloud Provider supports the entire Bluemix services catalog, IBM Containers, virtual machines, and other storage, compute, and network resources.

Resources to Learn More

Program Director, IBM Cloud Functions & IBM Cloud Provider

More DevOps stories
May 6, 2019

Are You Ready for SAP S/4HANA Running on Cloud?

Our clients tell us SAP applications are central to their success and strategy for cloud, with a deadline to refresh the business processes and move to SAP S/4HANA by 2025. Now is the time to assess, plan and execute the journey to cloud and SAP S/4HANA

Continue reading

May 3, 2019

Kubernetes Tutorials: 5 Ways to Get You Building Fast

Ready to start working with Kubernetes? Want to build your Kubernetes skills? The five tutorials in this post will teach you everything you need to know about how to manage your containerized apps with Kubernetes.

Continue reading

May 3, 2019

Using Portworx to Deploy and Manage an HA MySQL Cluster on IBM Cloud Kubernetes Service

This tutorial is a walkthrough of the steps involved in deploying and managing a highly available MySQL cluster on IBM Cloud Kubernetes Service.

Continue reading