Great question, @pal-arlos!
Spaces, bindings, and relations are all interrelated as you’ve found. Let’s see if I can provide a base description of how they work and try to answer some of your questions.
Spaces are defined in juju as one or more L3 networks (MAAS subnets) that provide a logical manifestation of contiguous networks that provide separate functions per space (like openstack-internal traffic, external (api and/or FIP) traffic, overlay SDN traffic, ceph-replication traffic, admin/operating system traffic.)
Note that you’ll find the space is defined at the L2 (VLAN) layer within MAAS, but you must define an IP on the NIC/BOND/VLAN device in the physical host configuration in MAAS for juju to recognize that the server has a “leg” in a given space (this is due to the slight L2 vs L3 disconnect between juju and MAAS, and is due to juju supporting cloud providers other than MAAS).
You can see which subnets are defined for each space within juju by running juju spaces
once you’ve bootstrapped a controller on the MAAS cloud.
To determine which spaces are supported by a charm, if there is not specific documentation, look at the metadata.yaml and each “requires,” “provides,” and “extra-bindings” key is a network-binding point that you can specify which space/subnet is used for communicating with remote units related to those interfaces.
For instance, if I want my nova-cloud-controller to talk to mysql on the “internal” space, I’d define in the bundle:
applications:
mysql:
bindings:
"": default-space
shared-db: internal-space
nova-cloud-controller:
bindings:
"": default-space
shared-db: internal-space
relations:
- - nova-cloud-controller:shared-db
- mysql:shared-db
note that this example does not include charm names, other critical options or bindings and is just a demonstration to nighlight spaces/bindings
In the above example, when the mysql application encounters a relation-joined/relation-changed on it’s shared-db interface, it will query it’s interfaces (based on charm code) for an IP address on the unit (metal/lxd/kvm) that is within the internal-space subnet(s) and announce that particular IP over the relation to the remote-unit (such as the nova-cloud-controller in this case.)
So, for each relation in your bundle, you can define which subnets’ IPs will be used for communication between the two (or more) applications within that relation based on the bindings used on both ends. It’s important that you set the bindings of both the provides and requires end of the relation to the same space, as demonstrated above.
This hopefully clearly answers your questions about “how to tie them together via spaces?” It is the bindings definition within the applications section of the bundle that defines which IP a charm will announce to related applications on that relation’s interface.
Regarding how to define your public IPs, the Openstack charms use a standard 3 extra-bindings which are named “public” “internal” and “admin” which allow you to define which space or spaces to use for these 3 service endpoints when registering to Keystone. These allow you to define spaces to determine the IPs which will be used for registering to keystone’s service endpoint database. These three bindings also relate directly to the optional “os-public-hostname” “os-internal-hostname” and “os-admin-hostname” configuration variables on Openstack API charms if you’re utilizing DNS and Virtual IPs for the service.
If not all of your servers have interfaces on all spaces, it would be important to tag your hosts within MAAS and define those tags and provide “to:” directives in your bundle to ensure that services that need “public” IP connectivity are deployed to machines with public interfaces. Typically this looks like (assuming machines tagged with “compute” don’t have external network ips, and those with “control” do):
machines:
0:
tags: compute
1:
tags: control
applications:
neutron-gateway:
options:
num_units: 1
to:
- 1
nova-compute:
options:
num_units: 1
to:
- 0
nova-cloud-controller:
options:
num_units: 1
to:
- lxd:1
bindings:
"": default-space
public: external-space
For a list of which relations are made in a deployment and and would be available for assignment of bindings, deploy your cloud with one space, and then run juju export-bundle
to view all bindings of each application. Also, running juju status --relations
will give you a list of relations and the “interfaces” (which are the same as the bindings names) used for those relations on each application.
I hope this explanation has cleared up some of your questions.
Cheers,
-Drew