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-utilsfirst
$ 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 –versionCreate 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.tfThe 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 AdminTFIn 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 TenantTFIn 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 fmtFor Tenants
$ cd TenantTF
$ terraform init
$ terraform fmtterraform 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 planFor Tenants
$ cd TenantTF
$ terraform validate
$ terraform planterraform 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 applyFor Tenants
$ cd TenantTF
$ terraform applyNext 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.