Use Terraform to manage OpenStack Cluster
After having a production and homelab OpenStack for a while, I could say that provisioning Workloads, managing it with an Admin and Tenant perspective is important.
Terraform is an open-source Infrastructure as code software tool that is used for provisioning network, server, cloud platforms and more, since Terraform is a declarative language, it can act as a blue print of the infrastructure that you are working on. This is a very helpful to know what would be added and removed on your infrastructure and can be managed by Git as well as a GitOps use case.
For this article lets cover the basics of managing an OpenStack cluster using Terraform and recrete the Demo project of OpenStack via Terraform.
Installation of Terraform
Since I use a Centos as jumphost where I will run Terraform based on the official documentation we need to do the following:
- Install
yum-utils
first
$ sudo dnf install yum-utils -y
- Add Hashicop Terraform repo
$ sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
- Install
terraform
$ sudo dnf install terraform -y
- Check Installation
$ terraform –version
Create your terraform script for OpenStack provider
In Terraform you need what you call a provider, A Provider basically is a converter that terraform calls to convert your .tf
into API calls to the platform that we will orchestrate, there are 3 types of providers namely Official,Partner and Community. Official providers are Hashicorp maintained, Partner are maintained by technology companies that partners with Hashicorp, and Community basically maintained by Open Source Community.
For OpenStack there is a good Community provider in this link, For us to use this provider we need to create a .tf
file, lets call it main.tf
$ vi main.tf
The content will be
terraform {
required_version = ">= 0.14.0"
required_providers {
openstack = {
source = "terraform-provider-openstack/openstack"
version = "1.49.0"
}
}
}
provider "openstack" {
user_name = “OS_USERNAME”
tenant_name = “OS_TENANT”
password = “OS_PASSWORD”
auth_url = “OS_AUTH_URL”
region = “OS_REGION”
}
You need to change the OS_USERNAME
, OS_TENANT
, OS_PASSWORD
, OS_AUTH_URL
, and OS_REGION
variables, for it to work.
Admin terraform file
As an Admin for OpenStack is focused on provisioning External Network, Routers, Users, Images, Tenant Profile, and its Quotas.
for this example will provision,Flavors, a Router connected to an External Network, a Test Image a Tenant profile and a User.
Let’s create first a Admin directory for your Admin related provisioning.
$ mkdir AdminTF
$ cd AdminTF
In the main.tf
terraform {
required_version = ">= 0.14.0"
required_providers {
openstack = {
source = "terraform-provider-openstack/openstack"
version = "1.49.0"
}
}
}
provider "openstack" {
user_name = “OS_USERNAME”
tenant_name = “admin”
password = “OS_PASSWORD”
auth_url = “OS_AUTH_URL”
region = “OS_REGION”
}
resource "openstack_compute_flavor_v2" "small-flavor" {
name = "small"
ram = "4096"
vcpus = "1"
disk = "0"
flavor_id = "1"
is_public = "true"
}
resource "openstack_compute_flavor_v2" "medium-flavor" {
name = "medium"
ram = "8192"
vcpus = "2"
disk = "0"
flavor_id = "2"
is_public = "true"
}
resource "openstack_compute_flavor_v2" "large-flavor" {
name = "large"
ram = "16384"
vcpus = "4"
disk = "0"
flavor_id = "3"
is_public = "true"
}
resource "openstack_compute_flavor_v2" "xlarge-flavor" {
name = "xlarge"
ram = "32768"
vcpus = "8"
disk = "0"
flavor_id = "4"
is_public = "true"
}
resource "openstack_networking_network_v2" "external-network" {
name = "external-network"
admin_state_up = "true"
external = "true"
segments {
network_type = "flat"
physical_network = "physnet1"
}
}
resource "openstack_networking_subnet_v2" "external-subnet" {
name = "external-subnet"
network_id = openstack_networking_network_v2.external-network.id
cidr = "10.0.0.0/8"
gateway_ip = "10.0.0.1"
dns_nameservers = ["10.0.0.254", "10.0.0.253"]
allocation_pool {
start = "10.0.0.1"
end = "10.0.254.254"
}
}
resource "openstack_networking_router_v2" "external-router" {
name = "external-router"
admin_state_up = true
external_network_id = openstack_networking_network_v2.external-network.id
}
resource "openstack_images_image_v2" "cirros" {
name = "cirros"
image_source_url = "https://download.cirros-cloud.net/0.6.1/cirros-0.6.1-x86_64-disk.img"
container_format = "bare"
disk_format = "qcow2"
properties = {
key = "value"
}
}
resource "openstack_identity_project_v3" "demo-project" {
name = "Demo"
}
resource "openstack_identity_user_v3" "demo-user" {
name = "demo-user"
default_project_id = openstack_identity_project_v3.demo-project.id
password = "demo"
}
Tenant terraform file
As a Tenant usually you create VMs, Network, and Security groups for your VMs.
For this example, we will use the user created above by the admins
Let’s first create a Tenant directory for your Tenant related provisioning.
$ mkdir TenantTF
$ cd TenantTF
In the main.tf
terraform {
required_version = ">= 0.14.0"
required_providers {
openstack = {
source = "terraform-provider-openstack/openstack"
version = "1.49.0"
}
}
}
provider "openstack" {
user_name = “demo-user”
tenant_name = “demo”
password = “demo”
auth_url = “OS_AUTH_URL”
region = “OS_REGION”
}
resource "openstack_compute_keypair_v2" "demo-keypair" {
name = "demo-key"
public_key = "ssh-rsa ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
}
resource "openstack_networking_network_v2" "demo-network" {
name = "demo-network"
admin_state_up = "true"
}
resource "openstack_networking_subnet_v2" "demo-subnet" {
network_id = openstack_networking_network_v2.demo-network.id
name = "demo-subnet"
cidr = "192.168.26.0/24"
}
resource "openstack_networking_router_interface_v2" "demo-router-interface" {
router_id = “XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX”
subnet_id = openstack_networking_subnet_v2.demo-subnet.id
}
resource "openstack_compute_instance_v2" "demo-instance" {
name = "demo"
image_id = "YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY"
flavor_id = "3"
key_pair = "demo-key"
security_groups = ["default"]
metadata = {
this = "that"
}
network {
name = "demo-network"
}
}
Initialize your Terraform
Next after creating your terraform files you need to initialize Terraform
For Admin
$ cd AdminTF
$ terraform init
$ terraform fmt
For Tenants
$ cd TenantTF
$ terraform init
$ terraform fmt
terraform init
will download the provider from the registry for us to use in provisioning that we will do for this project, terraform fmt
will format the files for it to be neat if you will add it in repositories.
Create your Terraform plan
Next will be create the plan for you to see what resources will be created.
For Admin
$ cd AdminTF
$ terraform validate
$ terraform plan
For Tenants
$ cd TenantTF
$ terraform validate
$ terraform plan
terraform validate
will validate the .tf
files if the syntax is correct, terraform plan
will create a planfile in cache where all managed resources be tracked in creation and destroy.
Apply your your first TF
Finally deploying the resources we will do <code>terraform apply</code> this will apply all states of the resources that is in the plan file.
For Admin
$ cd AdminTF
$ terraform apply
For Tenants
$ cd TenantTF
$ terraform apply
Next Steps
It took long enough previously I created an article how to deploy a minimal openstack cluster with raspberry pi, but lets see how to have more detailed Terraform and Ansible, and some CI/CD with GitLab.