🏗️ OpenStack in One Page: What It Is and How the Services Fit Together
OpenStack is software you install to build your own cloud. This page shows what the pieces are, how they talk to each other, and where the state lives, using a real test cloud and a real instance followed through its logs
💡 How this page was made. Everything shown as output was run for real on 8 October 2026 on a test cloud built with DevStack (branch stable/2026.1) in a throwaway virtual machine: Ubuntu 24.04, 4 CPUs, 8 GB of RAM, with nested KVM. Release names, dates and what each project is for come from the OpenStack documentation, read the same day (releases.openstack.org, docs.openstack.org). The comparisons with AWS and Azure are my own rough ones, not from the docs. The next page builds this test cloud step by step.
What OpenStack is, and what it is not
AWS, Azure, Google Cloud and Oracle Cloud are services you rent. OpenStack is software you install. It turns a rack of ordinary servers into a private cloud: you log in (or call an API), ask for a virtual machine, a network, a disk, and the software finds a server with room, builds it, wires it up and hands it to you. It is the same idea as the big clouds, with you running the datacentre, the upgrades and the pager.
That makes it infrastructure as a service (IaaS): machines, networks and storage. It is not:
- A single program. It is a family of cooperating services, each with a code name, an API and its own database tables. This page is a map of them.
- Kubernetes. Kubernetes schedules containers onto machines you already have. OpenStack provides the machines (virtual or bare metal), and people often run Kubernetes inside OpenStack instances.
- Only a virtualisation manager. Tools like Proxmox or plain libvirt manage VMs on a few hosts. OpenStack adds self-service for many users: projects, quotas, an API for everything, a shared image catalogue, virtual networks and floating IPs.
⚠️ Be honest about the cost. The software is free. Running it is a job: upgrades every six months, a database and a message queue to keep healthy, networking that has to be designed, and users who will break things in new ways. For a handful of VMs on one server, a simpler tool is usually the right answer. OpenStack pays off when many people need to create and destroy infrastructure on their own.
Releases and names
From releases.openstack.org (read 8 October 2026): OpenStack is "developed and released around 6-month cycles". Each release has an alphabetical code name and, since 2023, a year-based version number:
- 2025.1 Epoxy (2 April 2025) and 2025.2 Flamingo (1 October 2025): both still listed as maintained.
- 2026.1 Gazpacho (1 April 2026): the release used on this page.
- 2026.2 Hibiscus (30 September 2026): released a week before this page was written.
- 2027.1 Indri: in development, estimated for 24 March 2027.
Some releases are marked SLURP (Skip Level Upgrade Release Process): you may upgrade from one SLURP release straight to the next, skipping the one between. For a cloud you cannot afford to rebuild, that matters more than the names.
The versions you actually see are per project. On the test cloud:
nova 33.0.3.dev9 neutron 28.0.3.dev30 keystone 29.1.0 glance 32.0.1.dev20 cinder 28.0.1.dev11 horizon 25.7.4.dev30 python-openstackclient 9.0.0
Each project has its own version number; the release (Gazpacho) is the set of them that were tested together. The .devN suffix means "this many commits after the release tag": DevStack takes the latest of the stable branch, not an exact tag.
The services at a glance
These roles are the ones the OpenStack documentation gives. The "like" in brackets is my rough comparison, only a hint for people who know another cloud: the services do not match one to one.
- Keystone, Identity. "Authentication and authorization services throughout the entire cloud." Users, projects, roles, tokens, and the catalogue of where every other service lives. (Like IAM.)
- Nova, Compute. Manages "virtual machine instances at scale". It decides where an instance runs and drives the hypervisor. (Like EC2 or Azure VMs.)
- Glance, Image. Manages "disk-image discovery, registration, and delivery": the templates you boot instances from. (Like AMIs or Azure images.)
- Neutron, Networking. IP management, DNS, DHCP, load balancing and security groups: virtual networks, routers and floating IPs. (Like a VPC.)
- Cinder, Block Storage. Manages the lifecycle of persistent block volumes that you attach to instances. (Like EBS or managed disks.)
- Swift, Object Storage. Stores and retrieves arbitrary data as objects. (Like S3 or blob storage.)
- Horizon, Dashboard. A "web-based interface for both cloud administrators and cloud tenants". (Like the console.)
- Placement. "A REST API stack and data model used to track resource provider inventories and usages". Nova asks it which hosts have room. It has no equivalent you ever see in a big cloud, because the provider hides it.
And the ones you add later, as the cloud grows:
- Heat, Orchestration. "Orchestrate composite cloud applications using a declarative template format through an OpenStack-native REST API." (Like CloudFormation.)
- Octavia. "Brings network load balancing to OpenStack."
- Ironic. "Provisions bare metal (as opposed to virtual) machines", and gives Nova an interface "that allows physical servers to be managed as though they were virtual machines".
- Manila, shared file systems for several tenants.
The core set for a first cloud is Keystone, Nova, Placement, Glance, Neutron and Cinder, with Horizon as the face. That is exactly what DevStack installs by default (the DevStack docs list keystone, glance, nova, placement, cinder, neutron and horizon), and it is what this series uses.
The test cloud, as it really is
First, how a client finds anything. Keystone keeps a service catalogue: a list of services and their URLs. Every command starts by asking it.
$ openstack service list +----------------------------------+-------------+----------------+ | ID | Name | Type | +----------------------------------+-------------+----------------+ | 2cb2beba0e1343e2908633794a650428 | nova | compute | | 371f8dbca9ba44158ae9e1f7af0b0886 | nova_legacy | compute_legacy | | 6ec3213027bf41c48a39670494fab4dd | keystone | identity | | b148c02452fb4238aa66161e9e3952fd | cinder | block-storage | | c8d22d548eb34116a6be71d3fe5f9579 | glance | image | | d71f9edeada244d2880e31744959aed9 | placement | placement | | eb3373922b0e42b29ea7899d7cfd25ae | neutron | network | +----------------------------------+-------------+----------------+ $ openstack endpoint list --interface public -c "Service Name" -c "Service Type" -c URL +--------------+----------------+--------------------------------------------+ | Service Name | Service Type | URL | +--------------+----------------+--------------------------------------------+ | cinder | block-storage | http://10.0.2.15/volume/v3 | | neutron | network | http://10.0.2.15/networking | | glance | image | http://10.0.2.15/image | | keystone | identity | http://10.0.2.15/identity | | placement | placement | http://10.0.2.15/placement | | nova | compute | http://10.0.2.15/compute/v2.1 | | nova_legacy | compute_legacy | http://10.0.2.15/compute/v2/$(project_id)s | +--------------+----------------+--------------------------------------------+
Seven services. Two things worth a look:
- Everything is on http://10.0.2.15/... on one port, under a path: /identity, /compute, /image, /networking, /volume, /placement. DevStack puts a web server (Apache) in front and sends each path to the right service. A production cloud uses separate hosts, ports and TLS; the catalogue is how clients cope with either.
- nova_legacy is an older compute endpoint (API version 2), kept for old clients. The real one is nova, version v2.1.
Behind that front door the services run as systemd units. DevStack names them devstack@...:
$ systemctl list-units "devstack@*" --no-legend | awk '{print $1, $3, $4}' | sed 's/.service//'
devstack@c-api active running
devstack@c-sch active running
devstack@c-vol active running
devstack@dstat active running
devstack@etcd active running
devstack@g-api active running
devstack@keystone active running
devstack@n-api-meta active running
devstack@n-api active running
devstack@n-cond-cell1 active running
devstack@n-cpu active running
devstack@n-novnc-cell1 active running
devstack@n-sch active running
devstack@n-super-cond active running
devstack@neutron-api active running
devstack@neutron-ovn-maintenance-worker active running
devstack@neutron-periodic-workers active running
devstack@neutron-rpc-server active running
devstack@placement-api active running
devstack@q-ovn-agent active running
$ systemctl list-units "devstack@*" --no-legend | wc -l
20
$ systemctl list-units --type=service --state=running | grep -E "apache2|mysql|rabbitmq|libvirt|ovn|memcached"
apache2 libvirtd memcached mysql ovn-controller ovn-controller-vtep ovn-northd ovn-ovsdb-server-nb ovn-ovsdb-server-sb rabbitmq-server
Twenty units, and the names tell you the story: n- is Nova (n-api, n-sch the scheduler, n-cpu the compute process, n-super-cond and n-cond-cell1 the conductors, n-novnc-cell1 the console proxy, n-api-meta the metadata service that instances ask for their settings), g-api Glance, c- Cinder (API, scheduler, volume), neutron-... and q-ovn-agent Neutron with its OVN networking, keystone, placement-api, and etcd for coordination. Underneath are the ordinary services: MySQL, RabbitMQ (the message queue), memcached, libvirt (which drives the hypervisor), Open vSwitch/OVN (the virtual network), and Apache.
Why the VM had to be 8 GB: after the install, with one tiny instance running, free reported 5.4 GB used. The biggest single process is the database (mysqld, about 690 MB), then the web workers, then the instance itself (qemu, 209 MB for a 256 MB guest), then Nova and Neutron processes at 160 to 180 MB each. A cloud is many small processes, not one big one.
Everything is a REST call
The openstack command is a client. It turns your command into HTTP requests to those URLs. You can watch it with --debug:
$ openstack --debug server list (only the request lines, trimmed)
REQ: curl -g -i -X GET http://10.0.2.15/identity -H "Accept: application/json" -H "User-Agent: openstacksdk/4.10.0 keystoneauth1/5.13.1 ..."
Making authentication request to http://10.0.2.15/identity/v3/auth/tokens
REQ: curl -g -i -X GET http://10.0.2.15/image -H "Accept: application/json" ...
REQ: curl -g -i -X GET http://10.0.2.15/compute/v2.1 -H "Accept: application/json" ...
REQ: curl -g -i -X GET "http://10.0.2.15/compute/v2.1/servers/detail?flavor=None&image=None&name=None&..." ...
RESP BODY: {"servers": []}
Three steps, in order: (1) find the identity service and ask it to authenticate (/identity/v3/auth/tokens), (2) with the token and the catalogue it gets back, find the compute service, (3) call the compute API (GET /compute/v2.1/servers/detail). The answer is plain JSON ({"servers": []}: no instances yet).
Because it is just HTTP, you can do the same with curl:
$ openstack token issue -c expires -c project_id -c user_id
+------------+----------------------------------+
| Field | Value |
+------------+----------------------------------+
| expires | 2026-10-08T22:05:28+0000 |
| project_id | 2b380a2be5ad443e92cabeae7d9909b4 |
| user_id | 8da6246745c84127a7d28b5c9810a1f6 |
+------------+----------------------------------+
$ TOKEN=$(openstack token issue -f value -c id)
$ curl -s -H "X-Auth-Token: $TOKEN" http://10.0.2.15/compute/v2.1/flavors | python3 -m json.tool | head -12
{
"flavors": [
{
"id": "1",
"name": "m1.tiny",
"links": [
{
"rel": "self",
"href": "http://10.0.2.15/compute/v2.1/flavors/1"
},
{
"rel": "bookmark",
$ curl -s -w "\nHTTP %{http_code}\n" http://10.0.2.15/compute/v2.1/flavors
{"error": {"code": 401, "title": "Unauthorized", "message": "The request you have made requires authentication."}}
HTTP 401
$ curl -s -H "X-Auth-Token: $TOKEN" http://10.0.2.15/image/v2/images | python3 -m json.tool | grep -E '"name"|"status"|"disk_format"|"size"'
"name": "cirros-0.6.3-x86_64-disk",
"disk_format": "qcow2",
"size": 21692416,
"status": "active",
A token is a string with an expiry date, tied to one user and one project. Send it in the X-Auth-Token header and the call works; leave it out and you get 401 Unauthorized. Every service validates the token against Keystone before it does anything. When a call fails, check the three things in this order: do I have a valid token, for the right project, with a role that allows this?
Who are you: users, projects and roles
Keystone's vocabulary is short:
- User: a person or a program (demo, admin, but also one per service: nova, neutron, glance, cinder, placement are users too).
- Project: the unit of ownership and quota: instances, networks and volumes belong to a project. The older word was tenant, and you still see it in docs and API fields. The AWS comparison is closest to an account, the Azure one to a subscription.
- Role: what a user may do in a project (admin, member, reader).
- Domain: a container for users and projects, for separating organisations. This cloud only has the Default domain.
$ openstack project list +----------------------------------+--------------------+ | ID | Name | +----------------------------------+--------------------+ | 287f29e0beda4bebadcf93b156b68e44 | demo | | 2b380a2be5ad443e92cabeae7d9909b4 | admin | | a88278127f3b4c6c849839b457095734 | alt_demo | | d1c848b414e24933ac30fdeb6e6858c9 | invisible_to_admin | | f9316cdb10da402a96f49f35809b3b74 | service | +----------------------------------+--------------------+ $ openstack role assignment list --names --user demo --project demo +-------------+--------------+-------+--------------+--------+--------+-----------+ | Role | User | Group | Project | Domain | System | Inherited | +-------------+--------------+-------+--------------+--------+--------+-----------+ | anotherrole | demo@Default | | demo@Default | | | False | | member | demo@Default | | demo@Default | | | False | +-------------+--------------+-------+--------------+--------+--------+-----------+
demo is a member of the demo project: it may create and delete things there, and by the project model does not see admin's resources (that is what projects are for; not tested here). The service project is where the services' own users live. Rights are always a role in a project, never just "a user".
Inside Nova: four kinds of process and a queue
Nova is where you can see the pattern that most of OpenStack follows. The Nova documentation describes the parts:
- nova-api "processes REST requests". It is the front door and does nothing slow.
- nova-scheduler "decides which host gets each instance."
- nova-conductor "handles requests that need coordination (build/resize), acts as a database proxy, or handles object conversions."
- nova-compute "manages communication with hypervisor and virtual machines", and runs on the hypervisor itself.
They do not call each other directly. They talk through a message queue (RabbitMQ here, through a library called oslo.messaging) using RPC. And one rule, from the docs: compute nodes cannot access the database directly. "Services running on the compute node proxy database requests over RPC to a central manager called the conductor." In a big cloud with thousands of compute nodes, that keeps the database safe from them.
$ openstack compute service list +--------------------------------------+----------------+--------+----------+---------+-------+----------------------------+ | ID | Binary | Host | Zone | Status | State | Updated At | +--------------------------------------+----------------+--------+----------+---------+-------+----------------------------+ | 72156c93-1751-4a43-8f9e-d41cd2b0d9ce | nova-scheduler | cloud1 | internal | enabled | up | 2026-10-08T21:08:58.000000 | | 599f5860-4ac5-422a-bf25-a863d1f5a3bf | nova-conductor | cloud1 | internal | enabled | up | 2026-10-08T21:09:03.000000 | | d234e40f-be71-42dd-aebf-b51de43db27e | nova-conductor | cloud1 | internal | enabled | up | 2026-10-08T21:09:24.000000 | | 39ea8eda-99fe-4f3a-a551-1b8242d4bd7b | nova-compute | cloud1 | nova | enabled | up | 2026-10-08T21:09:29.000000 | +--------------------------------------+----------------+--------+----------+---------+-------+----------------------------+ $ openstack volume service list +------------------+--------------------+------+---------+-------+----------------------------+---------+---------------+ | Binary | Host | Zone | Status | State | Updated At | Cluster | Backend State | +------------------+--------------------+------+---------+-------+----------------------------+---------+---------------+ | cinder-scheduler | cloud1 | nova | enabled | up | 2026-10-08T21:09:26.000000 | None | None | | cinder-volume | cloud1@lvmdriver-1 | nova | enabled | up | 2026-10-08T21:09:27.000000 | None | None | +------------------+--------------------+------+---------+-------+----------------------------+---------+---------------+ $ openstack network agent list +--------------------------------------+------------------------------+--------+-------------------+-------+-------+-------------------+ | ID | Agent Type | Host | Availability Zone | Alive | State | Binary | +--------------------------------------+------------------------------+--------+-------------------+-------+-------+-------------------+ | b20d8aa6-d887-4256-9d7d-d0d1c847024d | OVN Controller Gateway agent | cloud1 | | :-) | UP | ovn-controller | | ae1fa8db-c466-5cc9-87c7-cd8485e25a9a | OVN Neutron agent | cloud1 | | :-) | UP | neutron-ovn-agent | +--------------------------------------+------------------------------+--------+-------------------+-------+-------+-------------------+
The first list is the Nova services as the database sees them: a scheduler, two conductors (one for the whole cloud, one for cell1) and one nova-compute. Each service reports in regularly, and State: up means its last report was recent. The same idea in the other lists: Cinder has a scheduler and a volume service (cloud1@lvmdriver-1: the host plus the storage backend, here plain LVM), and Neutron has OVN agents. If an instance will not start, this is the first place to look: is every service up?
Nova calls a deployment shard a cell. Every cloud has at least one. The databases below show two, nova_cell0 (a special cell for instances that could not be scheduled; that role is from Nova's cell design, and no failure was provoked here) and nova_cell1 (the working one).
Where the state lives: databases and the queue
Each service owns its own database and nobody reaches into somebody else's. On the test cloud:
$ mysql -uroot -p... -e "show databases" (system databases left out) cinder glance keystone neutron nova_api nova_cell0 nova_cell1 placement stats $ mysql -uroot -p... -N -e "select table_schema, count(*) from information_schema.tables where table_schema in (...) group by table_schema" keystone 49 glance 16 placement 13 cinder 36 neutron 135 nova_cell1 111 nova_cell0 111 nova_api 32 $ rabbitmqctl list_queues name messages | head -6 scheduler_fanout_92e6263afe3746889944228d380758f4 0 q-plugin.cloud1 0 cinder-scheduler.cloud1 0 cinder-volume.cloud1@lvmdriver-1 0 cinder-scheduler 0 $ rabbitmqctl -q list_connections name | wc -l 37
Eight databases (plus a stats one DevStack adds), one per service or cell. Neutron's 135 tables are the biggest: networks, ports, routers and security groups are a lot of rows. The queues carry the messages between processes, such as "scheduler, find a host", "volume service, create a volume", and 37 connections are open to RabbitMQ (counted with rabbitmqctl -q list_connections name).
This is also where a cloud hurts when it is run badly:
- Lose the database and the cloud forgets what it has created. Back it up.
- Lose the queue and the services cannot talk. Instances keep running (the hypervisor does not need the queue), but you cannot create or change anything.
- Lose Keystone and nothing authenticates, including the services calling each other.
(These three consequences follow from the design described above; this page did not break the lab to test them.)
How the cloud knows what hardware it has: Placement
When Nova must pick a host, it needs to know what each host has and what is already used. That is the Placement service: "resource providers" (here, the compute host), their inventory and usage, in resource classes such as VCPU, MEMORY_MB and DISK_GB.
$ openstack image list +--------------------------------------+--------------------------+--------+ | ID | Name | Status | +--------------------------------------+--------------------------+--------+ | 0a909d81-1440-4430-a266-930399e6e8b5 | cirros-0.6.3-x86_64-disk | active | +--------------------------------------+--------------------------+--------+ $ openstack flavor list +----+-----------+-------+------+-----------+-------+-----------+ | ID | Name | RAM | Disk | Ephemeral | VCPUs | Is Public | +----+-----------+-------+------+-----------+-------+-----------+ | 1 | m1.tiny | 512 | 1 | 0 | 1 | True | | 2 | m1.small | 2048 | 20 | 0 | 1 | True | | 3 | m1.medium | 4096 | 40 | 0 | 2 | True | | 4 | m1.large | 8192 | 80 | 0 | 4 | True | | 5 | m1.xlarge | 16384 | 160 | 0 | 8 | True | | c1 | cirros256 | 256 | 1 | 0 | 1 | True | | d1 | ds512M | 512 | 5 | 0 | 1 | True | | d2 | ds1G | 1024 | 10 | 0 | 1 | True | | d3 | ds2G | 2048 | 10 | 0 | 2 | True | | d4 | ds4G | 4096 | 20 | 0 | 4 | True | +----+-----------+-------+------+-----------+-------+-----------+ $ openstack network list -c Name +---------+ | Name | +---------+ | private | | public | +---------+ $ openstack hypervisor list +--------------------------------------+---------------------+-----------------+-----------+-------+ | ID | Hypervisor Hostname | Hypervisor Type | Host IP | State | +--------------------------------------+---------------------+-----------------+-----------+-------+ | d880925a-07e4-4bbf-a0ab-1112fc9723e6 | cloud1 | QEMU | 10.0.2.15 | up | +--------------------------------------+---------------------+-----------------+-----------+-------+ $ openstack resource provider inventory list $(openstack resource provider list -f value -c uuid | head -1) +----------------+------------------+----------+----------+----------+-----------+-------+------+ | resource_class | allocation_ratio | min_unit | max_unit | reserved | step_size | total | used | +----------------+------------------+----------+----------+----------+-----------+-------+------+ | VCPU | 4.0 | 1 | 4 | 0 | 1 | 4 | 1 | | MEMORY_MB | 1.0 | 1 | 7941 | 512 | 1 | 7941 | 256 | | DISK_GB | 1.0 | 1 | 57 | 0 | 1 | 57 | 1 | +----------------+------------------+----------+----------+----------+-----------+-------+------+
Read the inventory of the one hypervisor, cloud1:
- VCPU: total 4, allocation ratio 4.0. The machine has 4 vCPUs, and the cloud is willing to hand out 16 (4 times: CPU is overcommitted by default, because instances are rarely all busy at once). max_unit 4 means one instance may have at most 4.
- MEMORY_MB: total 7941, reserved 512, ratio 1.0. Memory is not overcommitted, and 512 MB is kept for the host itself.
- DISK_GB: total 57, ratio 1.0. The root disk of the VM.
Also visible: flavors (the sizes you pick: m1.tiny is 512 MB RAM and 1 disk GB, cirros256 is an extra-small flavor for CirrOS), one image (cirros-0.6.3, a 21 MB test image), two networks (private for instances and public for the outside), and the hypervisor (Type: QEMU: libvirt reports the type as QEMU even when it uses KVM, and the config says virt_type = kvm).
One instance, followed through the logs
To see the services work together, the test cloud booted one instance (CirrOS, the tiny 256 MB flavor, on the private network):
$ openstack server create --flavor cirros256 --image cirros-0.6.3-x86_64-disk --network private --wait flow-test
$ openstack server list -c Name -c Status -c Networks -c Flavor
+-----------+--------+---------------------------------------------------------+-----------+
| Name | Status | Networks | Flavor |
+-----------+--------+---------------------------------------------------------+-----------+
| flow-test | ACTIVE | private=10.0.0.46, fd28:9fa8:c0f3:0:f816:3eff:fec4:ac14 | cirros256 |
+-----------+--------+---------------------------------------------------------+-----------+
$ journalctl -u 'devstack@*' | grep req-9b23ddd7-14b5-4570-9751-c7cd4ce87128 (log lines per service)
51 devstack@neutron-api
30 devstack@g-api
26 devstack@n-api
23 devstack@placement-api
(plus the scheduler, the conductor and nova-compute, which log under their own names)
Every API call gets a request ID, and the services pass it along when they call each other. So one grep over the logs of all services finds the whole story of one request. The server was ACTIVE in 14 seconds. What happened, in order (shortened from the real log lines):
n-api POST /compute/v2.1/servers status: 202 len: 376 microversion: 2.100 time: 0.951358 placement-api GET /placement/allocation_candidates?limit=1000&resource... placement-api GET /placement/allocations/5207c12a-d569-4456-8f1c-c998a... placement-api PUT /placement/allocations/5207c12a-d569-4456-8f1c-c998a... nova-conductor INFO dbcounter Registered counter for database nova_cell1 nova-compute INFO nova.compute.claims [instance: 5207c12a-...] Claim successful on node cloud1 neutron-api INFO neutron.db.ovn_revision_numbers_db Successfully bumped revision number for resource 1c17a238-... nova-compute INFO nova.virt.libvirt.driver [instance: 5207c12a-...] Creating image(s) nova-compute INFO os_vif Successfully plugged vif VIFOpenVSwitch(active=False,address=fa:16:3e:c4:ac:14,bridge_name='br-int',... nova-compute INFO nova.compute.manager [instance: 5207c12a-...] Took 8.89 seconds to spawn the instance on the hypervisor. nova-compute INFO nova.compute.manager [instance: 5207c12a-...] Took 14.14 seconds to build instance. $ sudo virsh list --all Id Name State ----------------------------------- 1 instance-00000001 running
Read it as a story:
- nova-api accepts the request and answers 202 Accepted in under a second. The build continues in the background: this is why server create returns before the server is ready, and why --wait exists.
- The scheduler asks Placement for allocation_candidates ("which hosts have room for this flavor?"), picks one and writes the allocation back (PUT .../allocations/...): the resources are now claimed.
- The conductor coordinates the build with the cell's database.
- nova-compute on the chosen host confirms the claim ("Claim successful on node cloud1") and starts building: Glance supplies the image (30 log lines), Neutron creates and binds the network port (51 lines), then compute writes the disk ("Creating image(s)") and plugs the virtual network card into the Open vSwitch bridge br-int.
- libvirt starts the guest: virsh list shows instance-00000001, running. "Took 8.89 seconds to spawn" and "Took 14.14 seconds to build".
Five of the services above cooperated on one command, each doing its one job. The compute node never touched a database itself: it asked the conductor, as the Nova documentation says. When you troubleshoot a failed boot, you follow the same path: API, scheduler (no valid host?), Placement, compute, image, network port.
Regions, zones and cells
The words look like the big clouds' and mean something a little different:
- Region: a name in the catalogue that groups services (here RegionOne, the default; it appears as region_name in the client's clouds.yaml). A cloud can have more than one; this one has just the one.
- Availability zone: a grouping of compute (or storage) hosts that you choose. The test cloud lists nova (where the compute and volume services run) and internal (for the control services). See the AWS regions page for how the big clouds use the same words, with real datacentres behind them.
- Cell: a shard of Nova's database and message queue, for scaling. Invisible to users.
Mistakes people make early
- Looking at the dashboard first. Horizon is a convenience. The CLI and the API are the real interface, and the one you will automate. Learn openstack commands first.
- Reading "QEMU" and thinking there is no hardware acceleration. Check virt_type (kvm) and look for /dev/kvm.
- Forgetting the project. "I cannot see my server" is often a different project in the token. openstack token issue shows which one you are in.
- Treating DevStack as a small production cloud. The DevStack documentation says it "will make substantial changes to your system", to run only on servers or virtual machines dedicated to the purpose, and the project describes it as built from the latest of everything. It is a learning and development tool. For production people use packaged installers such as Kolla-Ansible or Canonical's Sunbeam, which the series may cover later.
- Expecting instant deletes and cheap mistakes. A cloud with many services remembers things in many places. A half-deleted network or a volume still attached can block a project's cleanup.
What this page did not cover
- Installing a cloud. The next page builds this test cloud with DevStack, including what the installer does and what it costs in RAM and time.
- Launching real instances: images, flavors, networks, key pairs, security groups and floating IPs (the page after that).
- Storage in depth (Cinder volumes, Swift), networking in depth (OVN, routers, floating IPs), orchestration and production deployment.
- Failure behaviour. The consequences of losing the database or the queue are from the design, not from a test.
The cheat sheet
openstack catalog list what services exist, and their URLs openstack endpoint list --interface public the URL of each openstack token issue who and which project am I openstack project list / user list who exists (admin) openstack role assignment list --names who may do what, where openstack compute service list Nova processes, up or down openstack volume service list Cinder processes openstack network agent list Neutron agents openstack hypervisor list where instances can run openstack resource provider inventory list ID what the host has (Placement) openstack image list / flavor list / network list what you can launch with openstack --debug COMMAND show the real HTTP requests openstack server list --all-projects (admin) every instance in the cloud journalctl -u 'devstack@*' | grep req-... follow a request through the logs (DevStack)
↑ All tutorials · Build a Test Cloud with DevStack: From a Blank Ubuntu to a Working Cloud →