Lesson 06 of 9 · Modules
Orchestration
Build OpenStack environments as code: Heat's native HOT templates and stacks, the Terraform OpenStack provider, and how to choose between them for tenant and platform automation.
Two ways to describe an environment
| Heat | Terraform OpenStack provider | |
|---|---|---|
| Where it runs | Inside the cloud (a service) | Your machine or CI |
| Format | HOT (YAML) templates | HCL |
| State | Kept by Heat | Terraform state (remote backend) |
| Scope | OpenStack resources | OpenStack and anything else with a provider |
| Plans/previews | stack update --dry-run (limited) |
Full plan |
Heat is the hotel's own event-planning service: you hand them a form, and they set up the rooms, the Wi-Fi and the projectors, and take it all down afterwards. Terraform is an independent event planner who can also book the catering, the taxis and the venue next door, because they work with many companies, not just this hotel.
A HOT template
heat_template_version: 2021-04-16
description: One web server on a private network with a floating IP
parameters:
key_name: { type: string }
image: { type: string, default: ubuntu-24.04 }
flavor: { type: string, default: m1.small }
public_net: { type: string, default: public }
resources:
net:
type: OS::Neutron::Net
subnet:
type: OS::Neutron::Subnet
properties:
network: { get_resource: net }
cidr: 10.10.0.0/24
router:
type: OS::Neutron::Router
properties:
external_gateway_info: { network: { get_param: public_net } }
router_if:
type: OS::Neutron::RouterInterface
properties:
router: { get_resource: router }
subnet: { get_resource: subnet }
web:
type: OS::Nova::Server
properties:
image: { get_param: image }
flavor: { get_param: flavor }
key_name: { get_param: key_name }
networks: [ { network: { get_resource: net } } ]
fip:
type: OS::Neutron::FloatingIP
depends_on: router_if
properties:
floating_network: { get_param: public_net }
fip_assoc:
type: OS::Neutron::FloatingIPAssociation
properties:
floatingip_id: { get_resource: fip }
port_id: { get_attr: [ web, addresses, { get_resource: net }, 0, port ] }
outputs:
web_ip:
value: { get_attr: [ fip, floating_ip_address ] }
(Attribute paths such as the port lookup vary slightly between releases; openstack orchestration resource type show OS::Nova::Server lists what your cloud supports.)
$ openstack stack create -t web.yaml --parameter key_name=mykey web --wait
$ openstack stack output show web web_ip
The same with Terraform
terraform {
required_providers {
openstack = { source = "terraform-provider-openstack/openstack" }
}
}
provider "openstack" {} # uses OS_CLOUD / clouds.yaml
resource "openstack_networking_network_v2" "net" { name = "web-net" }
resource "openstack_networking_subnet_v2" "subnet" {
network_id = openstack_networking_network_v2.net.id
cidr = "10.10.0.0/24"
}
resource "openstack_compute_instance_v2" "web" {
name = "web-01"
image_name = "ubuntu-24.04"
flavor_name = "m1.small"
key_pair = "mykey"
network { uuid = openstack_networking_network_v2.net.id }
}
(Add a router, router interface and floating IP resources to match the Heat example.) All the Terraform practices from Terraform & IaC apply: remote state, modules, plans in CI.
Choosing
- Heat: tenant self-service without extra tooling; Octavia, Magnum and some services use it internally; no external state to manage.
- Terraform: platform teams automating OpenStack alongside DNS, Kubernetes, monitoring and other clouds with one workflow.
- Many organisations use Terraform for platform infrastructure and let tenants choose.
Try it: the same environment twice (lab cloud)
- Create the web stack with Heat; read the events as it builds; SSH in via the output IP.
- Update the stack with a bigger flavor (
openstack stack update … --parameter flavor=m1.medium) and watch what Heat does to the server. - Break the template (a wrong image name), create it, and find the error in the stack events.
- Build the same environment with Terraform and the OpenStack provider; compare
terraform planwith Heat's behaviour. - Delete both, and confirm nothing is left behind (
openstack server list,openstack floating ip list).
Going deeper: IaC for private clouds
- Keep images, flavors and networks (platform-owned) in platform Terraform; let tenant stacks reference them by name or ID.
- Use Heat environment files and nested templates for reusable building blocks, or Terraform modules.
- Automate quotas and projects too (Keystone and Nova resources exist in the Terraform provider), so onboarding a team is a pull request.
Recap
- Heat: native HOT templates → stacks; debug with
stack event list. - Terraform OpenStack provider: HCL, plans, state, modules, and multi-provider workflows.
- Heat for native tenant self-service; Terraform for platform-wide automation. Both are infrastructure as code.
This site is a public version of my personal engineering knowledge hub. It intentionally excludes confidential company information and internal operational details.