This project documents the complete process of deploying a highly available (HA) OpenStack cloud environment using Kolla-Ansible. The deployment includes:
- Multi-node setup (controller, compute, and storage nodes)
- Full containerization using Docker
- Galera cluster, HAProxy, and Keepalived for HA
- Centralized configuration using Ansible
- Virtual machines provisioned with KVM/QEMU
The guide is designed to help DevOps engineers, cloud architects, and advanced system administrators replicate the deployment in a lab or production-ready setup.
Tested Environment:
🖥️ OS: Rocky Linux 9
☁️ Cloud Stack: OpenStack2024.2
⚙️ Tools: Kolla-Ansible, Docker, Ansible
📘 Note: This documentation assumes a basic understanding of Linux, networking, and Ansible.
- The deployment was performed in a virtualized lab using VMWare Workstation.
- One base virtual machine (VM) was created and then cloned to spawn additional nodes with the appropriate roles assigned.
- All VMs run Rocky Linux 9.4 and share the same hardware specs initially, with modifications based on the role.
📥 Download Rocky Linux 9.4 ISO:
https://rockylinux.org/download
This section describes the specific responsibilities and key services hosted on each node type within the HA OpenStack cluster.
Primary Role:
The "brain" of the OpenStack cluster.
Key Services:
Keystone
: Identity managementGlance
: Image storage for VMsNova API
: Compute API endpointsHorizon
: Web dashboard interfaceMariaDB/Galera
: Highly available database clusterRabbitMQ
: Message queuing between OpenStack services
Responsibility:
Handles orchestration, authentication, database operations, and API endpoints for all OpenStack components.
Primary Role:
Runs virtual machines (VMs) and provides compute resources.
Key Services:
Nova Compute
: Manages VM lifecycle (create, delete, migrate, etc.)Libvirt/KVM
: Hypervisor interface to run VMs
Responsibility:
Provides vCPUs, RAM, and local storage for VMs. Compute nodes scale horizontally — adding more nodes increases cluster capacity.
Primary Role:
Manages all networking components of the OpenStack environment.
Key Services:
Neutron
: Networking service (routers, subnets, floating IPs)L3 Agent
: Routing and NAT for VM networksDHCP Agent
: Dynamic IP assignment to VMsOVS
/LinuxBridge
: Virtual switch to connect instances
Responsibility:
Ensures full VM connectivity, external access, router/NAT functionality, and applies security group rules.
Primary Role:
Provides persistent storage to VMs (and optionally object storage).
Key Services:
Cinder Volume
: Block storage for VMs using LVM as the backend- (Optional)
Swift
: Object storage (not enabled in this deployment)
Responsibility:
Manages volumes, snapshots, and backups. In our setup, LVM aggregates additional disks into a single volume group (cinder-volumes
) for dynamic block provisioning.
This section outlines the architecture of the OpenStack HA deployment, including the roles assigned to each node, their hardware specifications, and how they are organized to ensure scalability, high availability, and separation of concerns.
Hostname | Role | IPv4 | vCPU | RAM (GB) | Storage (GB) | Notes |
---|---|---|---|---|---|---|
controller01 | Controller Node | 192.168.142.141 | 2 | 8 | 40 | Also used to deploy Kolla |
controller02 | Controller Node | 192.168.142.142 | 2 | 8 | 40 | |
controller03 | Controller Node | 192.168.142.143 | 2 | 8 | 40 | |
compute01 | Compute Node | 192.168.142.151 | 2 | 8 | 40 | Virtualization enabled |
compute02 | Compute Node | 192.168.142.152 | 2 | 8 | 40 | Virtualization enabled |
network01 | Network Node | 192.168.142.161 | 2 | 8 | 40 | |
network02 | Network Node | 192.168.142.162 | 2 | 8 | 40 | |
storage01 | Storage (Cinder LVM) | 192.168.142.171 | 2 | 8 | 40 (+10 GB) | LVM volume for Cinder |
storage02 | Storage (Cinder LVM) | 192.168.142.172 | 2 | 8 | 40 (+10 GB) | LVM volume for Cinder |
📌 Note: Each VM was cloned from
controller01
and then customized (hostname, static IP, NICs, etc.).
Each VM includes at least two network interfaces:
ens160
: Internal/OpenStack management networkens192
: External network for floating IPs and external access
NIC names may vary depending on the hypervisor configuration.
⚠️ Reminder: Always confirm NIC names usingip a
after VM creation.
This section covers the step-by-step creation of the base Rocky Linux VM, cloning it to form the OpenStack cluster, OS preparation, static IP setup, and SSH key configuration.
- Create a virtual machine named
controller01
which will serve as the base image.
It will be cloned later to create other nodes, and each clone will be customized. - Create the VM using the previously specified hardware (e.g., 2 vCPUs, 8 GB RAM, 40 GB disk).
- Add another NIC to the VM to support internal and external network separation.
- Confirm the final specifications before finishing the setup.
- Start the VM and begin installing Rocky Linux 9.4.
- Choose your preferred installation language.
- Configure installation settings:
- Partitioning
- Networking
- Time zone
- User creation
-
Create a user named
kolla
to be used for Kolla Ansible deployment. -
Network Configuration:
- Keep DHCP enabled on the first NIC (we’ll assign a static IP later).
- Disable IPv4 on the second NIC (e.g.,
ens192
).
- Disable → Enable the NIC to apply settings.
- Finish configuration and begin the OS installation.
- After reboot, log in as
root
and update the system:
sudo dnf update -y
- Add the
kolla
user to thewheel
group:
usermod -aG wheel kolla
grep wheel /etc/group
- Edit the sudoers file to allow passwordless sudo for the
wheel
group:
visudo
- Find:
%wheel ALL=(ALL) ALL
- Comment that line and uncomment:
%wheel ALL=(ALL) NOPASSWD: ALL
- Shut down the base VM (
controller01
) before cloning. - Use full independent clone option.
- Repeat the process to create the full architecture:
controller02
,controller03
,compute01
,compute02
,network01
,network02
,storage01
,storage02
.
Each VM needs a unique hostname and static IP.
- Set the hostname:
sudo hostnamectl set-hostname <hostname>
- Validate:
hostname
- Set static IP for
ens160
:nmcli device status
sudo nmcli con mod ens160 ipv4.addresses 192.168.142.141/24
sudo nmcli con mod ens160 ipv4.gateway 192.168.142.2
sudo nmcli con mod ens160 ipv4.dns 192.168.142.2
sudo nmcli con mod ens160 ipv4.method manual
sudo nmcli con down ens160 && sudo nmcli con up ens160
ip a show ens160
Repeat for each VM with appropriate IP and hostname.
- This node will act as the Kolla-Ansible deployment host.
- This file ensures all nodes in the cluster can be referenced by hostname during the Kolla Ansible deployment.
- DNS entries in other nodes will be taken care by Ansible.
- Open the hosts file:
sudo nano /etc/hosts
- Add these entries:
192.168.142.141 controller01 192.168.142.142 controller02 192.168.142.143 controller03 192.168.142.151 compute01 192.168.142.152 compute02 192.168.142.161 network01 192.168.142.162 network02 192.168.142.171 storage01 192.168.142.172 storage02
- Test reachability:
for host in controller01 controller02 controller03 compute01 compute02 network01 network02 storage01 storage02; do ping -c 1 $host >/dev/null && echo "$host is reachable" || echo "$host is NOT reachable" done
- Open VM settings for each compute node.
- Enable virtualization in the hardware settings.
- Repeat for
compute02
.
- Add a new virtual disk (20GB or more) to each storage node.
- Verify:
lsblk
- Initialize and configure LVM:
sudo pvcreate /dev/nvme0n2 sudo vgcreate cinder-volumes /dev/nvme0n2 sudo vgs
- Repeat on
storage02
.
Now, we will generate an SSH key for the kolla
user on controller01
and copy the public key to all other nodes under the same user (kolla
). This is essential for password less SSH access, which Kolla Ansible uses to operate on remote nodes.
-
Log in as
kolla
oncontroller01
. -
Generate key pair:
ssh-keygen -t rsa -b 4096 -N "" -f ~/.ssh/id_rsa
- Copy public key to all nodes:
for host in controller01 controller02 controller03 compute01 compute02 network01 network02 storage01 storage02; do ssh-copy-id kolla@$host done
📌 You’ll be prompted for the
kolla
user password on each host.
- Test:
ssh kolla@controller03
All the following steps are executed on the deployment node (controller01
), which orchestrates the entire OpenStack environment using Kolla Ansible.
-
Update system packages:
sudo dnf update -y
-
Install Python build dependencies:
sudo dnf install git python3-devel libffi-devel gcc openssl-devel python3-libselinux -y
-
Install Ansible:
sudo pip3 install ansible-core
⚠️ If you face aPATH
warning, update your shell configuration:
nano ~/.bashrc
# Add this line
export PATH="/usr/local/bin:$PATH"
source ~/.bashrc
-
Install
kolla-ansible
via pip:sudo pip3 install kolla-ansible
-
Create the configuration directory:
sudo mkdir -p /etc/kolla sudo chown $USER:$USER /etc/kolla
-
Copy example config files:
cp -r /usr/local/share/kolla-ansible/etc_examples/kolla/* /etc/kolla/
-
Copy the multinode inventory file to the current directory:
cp /usr/local/share/kolla-ansible/ansible/inventory/multinode .
ℹ️ We're using multinode to deploy a highly available OpenStack setup across multiple nodes.
-
Install Ansible Galaxy dependencies:
kolla-ansible install-deps
- Path:
/etc/kolla/globals.yml
- Purpose: Main config file for customizing OpenStack deployment.
nano /etc/kolla/globals.yml
Paste the following configuration:
🔽 Click to Expand `globals.yml` Example
##########################
# General Configuration
##########################
config_strategy: "COPY_ALWAYS"
kolla_base_distro: "rocky"
openstack_release: "2024.2"
network_address_family: "ipv4"
kolla_container_engine: docker
docker_configure_for_zun: "yes"
containerd_configure_for_zun: "yes"
docker_apt_package_pin: "5:20.*"
##########################
# Network Configuration
##########################
network_interface: "ens160"
neutron_external_interface: "ens192"
kolla_internal_vip_address: "192.168.142.250"
##########################
# OpenStack Core Services
##########################
enable_openstack_core: "yes"
enable_keystone: "{{ enable_openstack_core | bool }}"
enable_glance: "{{ enable_openstack_core | bool }}"
enable_nova: "{{ enable_openstack_core | bool }}"
enable_neutron: "{{ enable_openstack_core | bool }}"
enable_heat: "{{ enable_openstack_core | bool }}"
enable_horizon: "{{ enable_openstack_core | bool }}"
##########################
# Networking Plugin
##########################
neutron_plugin_agent: "openvswitch"
enable_kuryr: "yes"
##########################
# High Availability
##########################
enable_haproxy: "yes"
enable_keepalived: "{{ enable_haproxy | bool }}"
##########################
# Database & Messaging
##########################
enable_mariadb: "yes"
enable_memcached: "yes"
enable_etcd: "yes"
##########################
# Telemetry & Monitoring
##########################
enable_ceilometer: "yes"
enable_aodh: "yes"
enable_gnocchi: "yes"
enable_gnocchi_statsd: "yes"
enable_prometheus: "yes"
enable_grafana: "yes"
##########################
# Block Storage (Cinder)
##########################
enable_cinder: "yes"
enable_cinder_backend_lvm: "yes"
cinder_volume_group: "cinder-volumes"
##########################
# Containerized Application Services
##########################
enable_zun: "yes"
enable_horizon_zun: "{{ enable_zun | bool }}"
##########################
# Image Service Configuration (Glance)
##########################
glance_backend_file: "yes"
glance_file_datadir_volume: "/mnt/glance"
-
Path:
/etc/kolla/passwords.yml
-
Purpose: Stores auto-generated or custom passwords for all OpenStack services.
-
Generate it with:
kolla-genpwd
- Defines node roles and groups for the Ansible deployment.
[control]
controller01
controller02
controller03
[network]
network01
network02
[compute]
compute01
compute02
[monitoring]
controller01
[storage]
storage01
storage02
[all:vars]
ansible_user=kolla
ansible_become=True
[deployment]
localhost ansible_connection=local
-
Bootstrap the servers:
kolla-ansible bootstrap-servers -i ./multinode
-
Run pre-deployment checks:
kolla-ansible prechecks -i ./multinode
-
Deploy OpenStack:
kolla-ansible deploy -i ./multinode
-
Validate service configurations:
kolla-ansible validate-config -i ./multinode
-
Post-deployment config (generates
clouds.yaml
):kolla-ansible post-deploy
-
Verify clouds.yaml file:
ls /etc/kolla/clouds.yaml
-
Install OpenStack CLI:
pip install python-openstackclient -c https://releases.openstack.org/constraints/upper/master
-
Test the deployment:
- Try to list the services:
openstack service list
- Source OpenStack admin credentials file (
admin-openrc.sh
) that allows you to interact with the OpenStack CLI
source /etc/kolla/admin-openrc.sh
- Check the status of compute nodes:
openstack compute service list
-
Access Horizon Dashboard: Open your browser and visit:
http://192.168.142.250
Login credentials:
-
Username:
admin
-
Password: (find it using)
grep keystone_admin_password /etc/kolla/passwords.yml
-
/usr/local/share/kolla-ansible/init-runonce
Example Services by Role:
cinder_backup
,cinder_volume
,iscsid
prometheus_cadvisor
,fluentd
neutron_l3_agent
,neutron_dhcp_agent
,neutron_openvswitch_agent
keepalived
,haproxy
This project demonstrates a full deployment of a highly available OpenStack cloud using Kolla-Ansible and Docker containers across multiple virtualized nodes. The setup includes key OpenStack services distributed among controller, compute, network, and storage nodes, all integrated with high availability components like Galera, HAProxy, and Keepalived.
By following this guide, system administrators and DevOps engineers can:
- Understand the architecture of a production-grade OpenStack environment
- Reproduce a working HA deployment for testing, learning, or production use
- Customize the setup further to include services like Swift, Ceilometer, or Barbican
🚀 Next Steps:
Consider integrating monitoring tools (Prometheus/Grafana), backups, and automation scripts to manage and scale the cloud environment more efficiently.