Part 6: Juju Deploys the Cloud Brain


In the previous post, we successfully set up Juju, bootstrapped its controller onto machine i44
via MaaS, and created our openstack
model.
Juju is now ready and waiting to orchestrate our cloud deployment.
In this post, we'll deploy the essential "brain" of OpenStack โ the core control plane services responsible for identity, databases, messaging, and managing compute, network, and image APIs.
Strategy: LXD Containers & High Availability (HA)
Instead of deploying these control services directly onto bare metal machines, we'll leverage Linux Containers (LXD) managed by Juju. This provides lightweight isolation, efficient resource usage, and simplifies management. Juju will automatically create and manage these LXD containers on designated bare-metal machines provisioned by MaaS.
Based on our plan and commands:
We first add the bare-metal machines
i45
,i46
,i47
(Machine IDs5
,6
,7
in MaaS/Juju) to ouropenstack
model. These will host the LXD containers.Many core services (Database, Message Queue, Compute Controller) will be deployed with multiple units (
-n 3
) across these machines (--to lxd:5,lxd:6,lxd:7
) for High Availability (HA).We'll use Virtual IPs (VIPs) defined in our
config.yaml
(discussed in Part 2) so users and other services have a single, highly available endpoint to talk to, managed via thehacluster
charm (often related implicitly).
# Make sure you're in the right Juju model
juju switch maas-controller:openstack
# Add the machines designated for control plane containers
# (These should be 'Ready' in MaaS with tag 'openstack-miscellaneous')
juju add-machine -n 3 --constraints tags="openstack-miscellaneous"
# Note the machine IDs assigned (e.g., 5, 6, 7)
Foundation: HA Database & Message Queue
Almost all OpenStack services need a database and a message queue to communicate. We deploy these first.
Database (MySQL InnoDB Cluster): Provides data persistence.
# Deploy 3 units across our 3 misc machines inside LXD juju deploy -n 3 --to lxd:5,lxd:6,lxd:7 --channel 8.0/stable mysql-innodb-cluster mysql-innodb-cluster # Note: We'd typically apply '--config mysql-config.yaml' here # containing the tuning options like pool size from our main config.yaml
Message Queue (RabbitMQ): Facilitates communication between services.
# Deploy 3 units across our 3 misc machines inside LXD juju deploy -n 3 --to lxd:5,lxd:6,lxd:7 --channel 3.9/stable rabbitmq-server rabbitmq-server # Note: We'd typically apply '--config rabbitmq-config.yaml' here # containing clustering options from our main config.yaml
Vault: Secrets Management & Internal PKI ๐
Modern deployments require secure handling of passwords, keys, and especially TLS certificates for internal communication. Vault is our tool for this.
Deploy Vault & Router:
# Deploy Vault itself into LXD on machine 5 juju deploy --to lxd:5 --channel 1.8/stable vault vault # Deploy a MySQL router for Vault's backend storage (optional, depends on charm) juju deploy --channel 8.0/stable mysql-router vault-mysql-router
Integrate Vault's Router:
juju integrate vault-mysql-router:db-router mysql-innodb-cluster:db-router # Relation for Vault's own data storage if needed by the charm juju integrate vault-mysql-router:shared-db vault:shared-db
CRITICAL: Initialize & Unseal Vault (Manual Steps): The Vault service starts in a sealed state for security. You MUST manually initialize and unseal it. The keys and token generated here are extremely sensitive - store them securely! The examples below are for illustration ONLY.
Install Vault CLI (on your workstation/management node): Bash
sudo snap install vault
Set Vault Address (Find Vault unit's IP using
juju status vault
):# Replace <vault_unit_ip> with the actual IP shown in juju status export VAULT_ADDR="http://<vault_unit_ip>:8200"
Initialize Vault:
vault operator init -key-shares=5 -key-threshold=3 # !!! SAVE THE 5 UNSEAL KEYS AND THE INITIAL ROOT TOKEN SECURELY !!! # Example Output (YOURS WILL BE DIFFERENT): # Unseal Key 1: Nb8VLbPmNlqkKfWpojH9lJ2EccXuVS0ZBlHRD+LCF5Q9 # ... (Keys 2-5) ... # Initial Root Token: s.tvHFWsbnDSCWBbbyN6A8Iolm
Unseal Vault (using 3 of the 5 keys):
vault operator unseal <paste_unseal_key_1_here> vault operator unseal <paste_unseal_key_2_here> vault operator unseal <paste_unseal_key_3_here>
(Vault should now report itself as unsealed).
Authorize Juju Charm: Juju needs permission to interact with Vault. Generate a temporary token and pass it to the charm:
# Use the Initial Root Token you saved export VAULT_TOKEN="<paste_initial_root_token_here>" # Create a short-lived token for Juju vault token create -ttl=10m # Copy the 'token' value from the output (e.g., s.M8vYOcaz8PRrPSFqjO26RGPT) # Authorize the charm using the leader unit juju run vault/leader authorize-charm token="<paste_short_lived_token_here>"
Configure Vault as Internal CA: Now, tell Vault to generate a Root CA and integrate it with MySQL for TLS.
juju run vault/leader generate-root-ca # Integrate Vault's PKI with MySQL cluster juju integrate mysql-innodb-cluster:certificates vault:certificates
Vault will now be able to issue TLS certificates for secure internal communication between OpenStack services!
graph TD
subgraph "Vault as PKI for Internal TLS"
V(Vault);
DB(MySQL);
KS(Keystone);
NV(Nova API);
GL(Glance API);
NT(Neutron API);
Oth(...)
V -- Issues Cert --> DB;
V -- Issues Cert --> KS;
V -- Issues Cert --> NV;
V -- Issues Cert --> GL;
V -- Issues Cert --> NT;
V -- Issues Cert --> Oth;
end
style V fill:#d4edda
Deploying Core APIs (Using Juju & Integrating)
Now we deploy the main OpenStack API services, integrating them with our foundation (DB, MQ, Vault) and each other. Each typically requires its own MySQL router instance managed by Juju.
Keystone (Identity): Authentication, authorization, service catalog.
juju deploy --to lxd:6 --channel 2023.2/stable keystone keystone juju deploy --channel 8.0/stable mysql-router keystone-mysql-router juju integrate keystone-mysql-router:db-router mysql-innodb-cluster:db-router juju integrate keystone-mysql-router:shared-db keystone:shared-db juju integrate keystone:certificates vault:certificates
Placement (Resource Tracking): Tracks resource provider inventories.
juju deploy --to lxd:7 --channel 2023.2/stable placement placement juju deploy --channel 8.0/stable mysql-router placement-mysql-router juju integrate placement-mysql-router:db-router mysql-innodb-cluster:db-router juju integrate placement-mysql-router:shared-db placement:shared-db juju integrate placement:identity-service keystone:identity-service juju integrate placement:certificates vault:certificates
Glance (Image Service API): Stores and serves VM images.
juju deploy --to lxd:6 --channel 2023.2/stable glance glance juju deploy --channel 8.0/stable mysql-router glance-mysql-router juju integrate glance-mysql-router:db-router mysql-innodb-cluster:db-router juju integrate glance-mysql-router:shared-db glance:shared-db juju integrate glance:identity-service keystone:identity-service juju integrate glance:certificates vault:certificates # We'll integrate Glance with Ceph storage in Part 7
Neutron (Network Service API): Manages virtual networks.
# We apply config using '--config neutron.yaml' containing VIP etc. juju deploy --to lxd:5 --channel 2023.2/stable --config neutron.yaml neutron-api juju deploy --channel 8.0/stable mysql-router neutron-api-mysql-router juju integrate neutron-api-mysql-router:db-router mysql-innodb-cluster:db-router juju integrate neutron-api-mysql-router:shared-db neutron-api:shared-db juju integrate neutron-api:identity-service keystone:identity-service juju integrate neutron-api:amqp rabbitmq-server:amqp juju integrate neutron-api:certificates vault:certificates # OVN plugin deployment and integrations deferred to Part 9
Nova (Compute Service Controller): Manages VM lifecycle (API and scheduler parts).
# We apply config using '--config ncc.yaml' containing VIP etc. juju deploy -n 3 --to lxd:5,lxd:6,lxd:7 --channel 2023.2/stable --config ncc.yaml nova-cloud-controller juju deploy --channel 8.0/stable mysql-router ncc-mysql-router juju integrate ncc-mysql-router:db-router mysql-innodb-cluster:db-router juju integrate ncc-mysql-router:shared-db nova-cloud-controller:shared-db juju integrate nova-cloud-controller:identity-service keystone:identity-service juju integrate nova-cloud-controller:amqp rabbitmq-server:amqp juju integrate nova-cloud-controller:placement placement:placement # Integrate with Placement juju integrate nova-cloud-controller:neutron-api neutron-api:neutron-api juju integrate nova-cloud-controller:image-service glance:image-service # Needs Glance juju integrate nova-cloud-controller:certificates vault:certificates # Integration with nova-compute nodes deferred to Part 8 # Integration with nova-cell-controller deferred to Part 9
Horizon (Dashboard): The Web UI.
# We apply config using '--config horizon.yaml' containing VIP etc. juju deploy --to lxd:5 --channel 2023.2/stable --config openstack-dashboard.yaml openstack-dashboard juju deploy --channel 8.0/stable mysql-router dashboard-mysql-router juju integrate dashboard-mysql-router:db-router mysql-innodb-cluster:db-router juju integrate dashboard-mysql-router:shared-db openstack-dashboard:shared-db juju integrate openstack-dashboard:identity-service keystone:identity-service juju integrate openstack-dashboard:certificates vault:certificates
Barbican (Secrets Management): For storing secrets like TLS certs used by Octavia.
juju deploy --to lxd:5 --channel 2023.2/stable barbican barbican juju deploy --channel 8.0/stable mysql-router barbican-mysql-router juju deploy --channel 2023.2/stable barbican-vault # Subordinate charm juju integrate barbican-mysql-router:db-router mysql-innodb-cluster:db-router juju integrate barbican-mysql-router:shared-db barbican:shared-db juju integrate barbican:certificates vault:certificates juju integrate barbican:identity-service keystone:identity-service juju integrate barbican:amqp rabbitmq-server:amqp juju integrate barbican-vault:secrets barbican:secrets juju integrate barbican-vault:secrets-storage vault:secrets
(Note: Deployment of Heat & Magnum from your config requires similar
deploy
andintegrate
steps, omitted here for brevity but would follow the same pattern).
Checking the Status
After running these commands, Juju works in the background. Check progress with:
juju status --relations
This command shows the deployed applications, their units, IP addresses, agent status, workload status, and the relations between them. Initially, some services might show as "blocked" or "waiting" if they depend on relations not yet established (like Cinder needing Ceph, or Neutron needing OVN fully configured). This is normal at this stage.
Conclusion โ
We've just deployed the core brain and nervous system of our OpenStack cloud!
Using Juju, we deployed highly available databases, message queues, identity services, APIs for compute, network, image management, the dashboard, secrets management, and set up Vault as our internal Certificate Authority, all primarily within isolated LXD containers.
We also tackled the essential manual steps for Vault initialization.
While not all relations are complete yet, the control plane foundation is laid. In Part 7, we'll deploy the powerful Ceph storage cluster using Juju, providing the resilient backend for our images and block storage.
Subscribe to my newsletter
Read articles from Faiz Ahmed Farooqui directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Faiz Ahmed Farooqui
Faiz Ahmed Farooqui
Principal Technical Consultant at GeekyAnts. Bootstrapping our own Data Centre services. I lead the development and management of innovative software products and frameworks at GeekyAnts, leveraging a wide range of technologies including OpenStack, Postgres, MySQL, GraphQL, Docker, Redis, API Gateway, Dapr, NodeJS, NextJS, and Laravel (PHP). With over 9 years of hands-on experience, I specialize in agile software development, CI/CD implementation, security, scaling, design, architecture, and cloud infrastructure. My expertise extends to Metal as a Service (MaaS), Unattended OS Installation, OpenStack Cloud, Data Centre Automation & Management, and proficiency in utilizing tools like OpenNebula, Firecracker, FirecrackerContainerD, Qemu, and OpenVSwitch. I guide and mentor a team of engineers, ensuring we meet our goals while fostering strong relationships with internal and external stakeholders. I contribute to various open-source projects on GitHub and share industry and technology insights on my blog at blog.faizahmed.in. I hold an Engineer's Degree in Computer Science and Engineering from Raj Kumar Goel Engineering College and have multiple relevant certifications showcased on my LinkedIn skill badges.