OpenStack
neutron and DNS
Overview
It's complicated. There's the internal DNS service being managed by dnsmasq and there's the (limited) interaction you can have with the external DNS service (see Designate and External DNS).
We're reading the Neutron Administration Guide and starting at the section on DNS Integration. There's a little table one who gets to define components of a DNS name:
Resource | dns_name | dns_domain |
---|---|---|
Ports | Yes | Yes |
Networks | No | Yes |
Floating IPs | Yes | Yes |
dns_name would be bob in bob.example.com.
What it really means is that when I create a port (for the most part, on the command line as the Train GUI hasn't caught up yet) I can define dns_name and/or dns_domain for a port, network or floating IP.
neutron.conf
The DNS Integration document also notes you can (re-)define the dns_domain in neutron.conf which is slightly separate to the above. This internal DNS name service is what dnsmasq is playing with. You're most likely to have seen it in /etc/resolv.conf with its default value of openstacklocal as discovered by your DHCP client service.
Let's have a quick play with that. If we set that to something, say, openstack.runscripts.com. (a DNS domain name which we own or control), restart neutron-server and create an instance called bob and then look at the port associated with that instance:
$ openstack port show $PORT-GUID -f shell | grep dns dns_assignment="[{u'hostname': u'bob', u'ip_address': u'172.16.1.216', u'fqdn': u'bob.openstack.runscripts.com.'}]" dns_domain="" dns_name="bob"
My port has inherited some info from the instance. I have a dns_name (but no dns_domain) and a dns_assignment which includes our neutron.conf dns_domain.
At this point, depending on how your instance chooses to construct /etc/resolv.conf you can merrily interrogate the dnsmasq resolver for yourself and other hosts. Here, for convenience, I'll force the full domain name and explicitly use the dnsmasq resolver:
bob$ host sue.openstack.runscripts.com. 172.16.1.2 sue.openstack.runscripts.com has address 172.16.1.233
If resolve.conf has the right contents you can simply say:
bob$ host sue sue.openstack.runscripts.com has address 172.16.1.233
But this hasn't affected the external DNS in any way. All we done is have OpenStack, through dnsmasq, manage an internal domain.
Port Data
Let's try being a bit more specific about the port. We'll create a rita port and add it to bob:
$ openstack port create --network $MY-NET --dns-name rita rita-port ... $ openstack port show rita-port -f shell | grep dns dns_assignment="[{u'hostname': u'rita', u'ip_address': u'172.16.1.195', u'fqdn': u'rita.openstack.runscripts.com.'}]" dns_domain="" dns_name="rita"
Looks plausible.
If we now delete the existing interface from bob and add rita-port we get a failure and trawling about we find the following in nova-api.log:
Value rita assigned to dns_name attribute does not match instance's hostname bob
Hmm. The subtlety here is that during instance creation the port will have its dns_name attribute munged into some (DNS-safe) variant of the instance's own name. Here, we're post-creation and we're trying to coerce port rita onto instance bob and OpenStack is drawing the line.
In fact, we continue to get the same error if we try to use port rita when creating an instance whose name is not rita.
We're left wondering why (other than the implicit use by the Compute service during instance creation) this is available to use at all.
Network Data
OK, let's try the next step and fiddle with networks. The documentation has three cases studies:
- Floating IPs are published with associated port DNS attributes
- Floating IPs are published in the external DNS service
- Ports are published directly in the external DNS service
1. Floating IPs are published with associated port DNS attributes
In this use case, the address of a floating IP is published in the external DNS service in conjunction with the dns_name of its associated port and the dns_domain of the port’s network.
Let's give our FIPs network a dns_domain. Again, let's use a different DNS domain name to we can see what's happening:
$ openstack network set --dns-domain fips.runscripts.com. $FIPS-NET ... $ openstack network show $FIPS-NET -f shell | grep dns dns_domain="fips.runscripts.com."
Nothing exciting so far. Let's create a floating ip and associate it with bob.
$ openstack floating ip create $FIPS-NET --port $BOB-PORT-UUID
Warning
The output from the initial creation of the floating IP will not (necessarily) show any subsequently modified attributes like DNS bits.
However, I don't get any:
$ openstack floating ip show $FIP-PORT_GUID -f shell | grep dns dns_domain="" dns_name=""
Hmm, a bit of rummaging finds the following in /var/log/neutron/server.log:
DNSDomainNotFound: Domain network.runscripts.com. not found in the external DNS service
Wait, that is a) not the fips domain name I thought we were using and is b) the DNS domain name I set on the tenant's network whilst I was mucking about...
OK, in for a penny, let's create the zone, delete the floating IP and try again:
$ openstack zone create --email hostmaster@runscripts.com network.runscripts.com. $ openstack floating ip create $FIPS-NET --port $BOB-PORT-UUID ... $ openstack floating ip show $FIPS-PORT-GUID -f shell | grep dns dns_domain="" dns_name=""
Oh. But something has happened:
$ openstack recordset list network.runscripts.com. | grep bob | a7bd50ec-3bd7-470b-9e88-c81e057c22f2 | bob.network.runscripts.com. | A | 192.168.2.55 | ACTIVE | NONE |
Which we can check with:
$ host bob.network.runscripts.com. bob.network.runscripts.com has address 192.168.2.55
and, even more impressively, a reverse domain has appeared (assuming you configured neutron to do so):
$ host 192.168.2.55 55.2.168.192.in-addr.arpa domain name pointer bob.network.runscripts.com.
At this point we have two domain names for this host depending on whom we ask. If we query the internal DNS service (dnsmasq) we can get answers for bob.openstack.runscripts.com and if we query the external DNS service (bind9) then we can get answers for bob.network.runscripts.com.
So it looks like the external DNS domain name associated with the floating IP is a combination of the instance name and the tenant network's dns_domain name. Nothing to do with the external FIP network at all. Therefore, if you give your tenant network a dns_domain name then you must create the zone as well. Something like:
$ openstack network set --dns-domain $DOMAIN-NAME $TENANT-NET $ openstack zone create --email hostmaster@some.where $DOMAIN-NAME
(adjust as appropriate for your DNS environment)
2. Floating IPs are published in the external DNS service
In this use case, the user assigns dns_name and dns_domain attributes to a floating IP when it is created. The floating IP data becomes visible in the external DNS service as soon as it is created. The floating IP can be associated with a port on creation or later on.
The nominal command is:
$ openstack floating ip create --dns-domain fips.runscripts.com. --dns-name my-fip $FIPS-NET
but I wonder if, having already set the dns-domain for the FIPs network to be fips.runscripts.com. we can get away with:
$ openstack floating ip create --dns-name my-fip $FIPS-NET Error while executing command: BadRequestException: 400, Bad floatingip request: dns_name cannot be specified without a dns_domain.
Bah! OK, let's try YADN (Yet Another Domain Name?):
$ openstack floating ip create --dns-domain flying-fips.runscripts.com. --dns-name rita $FIPS-NET
Note
This time the immediate command output will include dns_domain and dns_name as, uh, we just set them.
Again we get the DNSDomainNotFound: Domain flying-fips.runscripts.com. not found in the external DNS service complaint.
Finally, if we have created fips.runscripts.com. in the external DNS then the creation will succeed:
$ openstack zone create --email hostmaster@runscripts.com fips.runscripts.com. $ openstack floating ip create --dns-domain fips.runscripts.com. --dns-name rita $FIPS-NET ... $ host rita.fips.runscripts.com ...
At this point, rita.fips.runscripts.com (external) and bob.openstack.runscripts.com (internal) are independent so we can finally(?) associate rita with bob. That's been a long time coming.
3. Ports are published directly in the external DNS service
In this case, the user is creating ports or booting instances on a network that is accessible externally.
This is arguably the most obvious case although most clouds will not allow users to create ports directly on external networks. Of course, you'll also need to be an administrator to modify the network and create ports.
At this point, we're no different to when we were playing with Port Data above. I can't get it to work -- although maybe that's not the end of the world.
One thing to note is that my "externally accessible networks" are actually external which violates rule one in the rules on Configuration of the externally accessible network for use case 3.
Maybe I should start there. Maybe I'll just leave it be.
Specific Floating IPs
Just as a side-note, in passing, regular tenants can't create specific floating IPs, that is, with a specific floating IP address. They'll get the slightly cryptic message:
tenant$ openstack floating ip create --floating-ip-address a.b.c.d $FIPS-NET Error while executing command: HttpException: 403, (rule:create_floatingip and rule:create_floatingip:floating_ip_address) is disallowed by policy
They can only get a floating IP generated at random (from within the pool of the chosen network). An admin user can create specific floating IPs and, with an extra flag, can create them on behalf of other projects:
admin$ openstack floating ip create --floating-ip-address a.b.c.d --project $TENANT-PROJECT $FIPS-NET
Which is great unless you're playing with Designate in which case the admin user must be a member of the same Project. Why? If I run the following as regular admin:
$ openstack floating ip create --floating-ip-address a.b.c.d --dns-name bob --dns-domain tenant.runscripts.com. --project $TENANT-PROJECT $FIPS-NET
Then OpenStack will try to update the tenant.runscripts.com. zone as regular admin. But we created the tenant.runscripts.com. zone as $tenant. We can't have two Projects managing the same Designate DNS zone so whilst OpenStack maintains that it is using the (external) DNS name bob.tenant.runscripts.com. in fact nothing will have happened.
You'll need an admin account in the Project which owns the Designate DNS zone -- at which point you don't need to specify --project $TENANT-PROJECT anymore.
I suspect that as the reverse zone is created automatically it too will be owned by a specific Project. That means you can't have two Projects using FIPs on the same external network is you're using Designate.
Document Actions