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 IDs 5, 6, 7 in MaaS/Juju) to our openstack 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 the hacluster 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.

  1. 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
    
  2. 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.

  1. 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
    
  2. 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
    
  3. 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>"
      
  4. 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.

  1. 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
    
  2. 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
    
  3. 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
    
  4. 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
    
  5. 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
    
  6. 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
    
  7. 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 and integrate 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.

0
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.