The Cloud Foundry documentation recommends configuring a wildcard DNS entry so that the routes to all apps deployed to the PaaS will be known by the DNS. But many corporate IT departments and cloud providers prohibit the use of wildcard entries in their DNS services.
This blog looks at the use of wildcard DNS in Cloud Foundry and discusses alternatives for environments where wildcards are not an option.
Cloud Foundry Routing: A Primer
When an app is deployed to Cloud Foundry, an associated route is created. The route is a standard URI string, and is the identifier used by all clients to access the application over HTTP.
This route, like most good URLs, includes a hostname and a domain name.
For example, I just deployed the Python currency converter application to my openstack-hosted Stackato instance. The URI it created looks like this:
Here, the hostname part is "bottle-currency" and the domainname part is "demo.stacktest.io".
When I type this into my browser, the browser consults the DNS which maps "bottle-currency.demo.stacktest.io" to the IP address of the PaaS. The Cloud Controller (CC) is sitting on that IP address listening on ports 80 and 443. When my request comes in, the CC examines the HTTP headers to extract the incoming URL string, matches this with the route assigned to the application, and directs the request to an instance of this app running in the PaaS.
HTTP/S Only, and No Ports
The Cloud Foundry router only supports the HTTP protocol. Currently Cloud Foundry's router does not support non-HTTP traffic, although this feature is currently under development for diego.
You'll note that the route URI string doesn't specify a port. This is because Cloud Foundry only listens on the standard http/s ports (80 and 443), and doesn't use ports to distinguish target applications.
It's worth mentioning that Stackato's Harbor component extends Cloud Foundry to support any protocol over both TCP and UDP, and Harbor does expose additional ports in order to enable this.
For all of this to work, the DNS obviously must be able to resolve the hostname/domainname. The hostname part corresponds to the application, and since application names aren't necessarily known in advance, it would sure be handy if the DNS were able to match any hostname in that subdomain, instead of requiring a DNS update every time a new application is pushed.
This is where wildcard DNS comes in. As the name suggests, wildcard DNS records match arbitrary hostnames which are specified by an asterisk in the DNS record.
For the example above, the DNS record for demo.stacktest.io looks like:
*.demo IN CNAME demo.stacktest.io.
Which maps any hostname in the demo.stacktest.io subdomain to my PaaS IP address.
When Wildcard DNS is Banished
Wildcard DNS works very well for this purpose, but unfortunately many IT policies prohibit the use of wildcard DNS. The reasons I hear are varied, most stemming from security concerns. For example, a few years ago eBay was the target of phishing attacks that exploited wildcard DNS. Consequently many IT departments are reluctant to allow wildcards, even for internal-only DNS.
Others shun wildcard DNS as it can obscure errors, and mislead users.
Regardless of the reasons, if your provider or IT department prohibits wildcard DNS, you'll need a workaround to allow the PaaS to create arbitrary app names.
I’ll get this out of the way first. It can be tempting to try to access PaaS-hosted applications directly via the PaaS IP address, bypassing name resolution altogether. This is a natural technique that developers using tomcat, WSGI, and other containers have successfully used for ages. But this will not work with Cloud Foundry. Requests that include only an IP address instead of a fully qualified domain name will correctly route to the PaaS, but the URL doesn’t embed the actual appname so the PaaS is unable to determine which hosted application the request is meant for. Thus a name is required, and that name must be resolved somehow.
Here are several techniques that will work to ensure application names are properly resolved.
1. Maintain static pool of app names (host names) in the DNS
A quick but inflexible workaround is for IT to allocate and maintain a pool of static app names in the DNS, and inform developers that they must use one of these names when deploying apps. This is rigid and cumbersome as it prevents developers from dynamically creating app names for experimentation or versioning, unless appnames are meaningless (like app1, app2, app9999) in which case mappings are difficult to manage and comprehend.
2. Use xip.io to resolve names
From their site xip.io is a "magic domain name that provides wildcard DNS for any IP address." It works by parsing the passed host/domain name, and extracting and returning the embedded IP address.
For example, say your PaaS is at IP address 18.104.22.168. You can name your PaaS 22.214.171.124.xip.io, and all references to *.126.96.36.199.xip.io will be correctly resolved by the xip.io resolver.
Handy as this is, it's generally not a good solution. Any IT department that refuses wildcard DNS would presumably be skeptical of sending DNS requests offsite every time an application is accessed internally. Also this relies on xip.io being available. And the naming scheme imposed by xip.io, with embedded IP address, is cumbersome and breaks if/when the cluster moves around the network.
3. Dynamically add app names using IT-supported DNS API (if available)
Some IT departments expose API for management of their DNS, allowing (among other things) new hostnames to be added and deleted dynamically. If such is available, you can arrange to invoke this API to dynamically map a new hostname/appname to DNS during app deployment.
Note, if you're using Stackato, you can make use of hooks to accomplish this. A staging_hook embedded in the manifest can include a direct call to the DNS API to add the hostname for the application being deployed.
4. Use DNS delegation With DNS delegation, a unique subdomain is designated for the PaaS cluster, and a separate, non-IT managed DNS server on the internal network is used to resolve all requests for this subdomain. This requires a single "IN NS" record to be added to the IT-managed DNS server that points to a DNS server dedicated to PaaS name resolution.
Many IT departments will allow wildcard DNS in the delegated DNS server, in which case this solution works very well. But even without wildcard DNS, adding new hostnames to a local team-managed DNS server is usually much quicker than submitting a service ticket.
5. Tweaking /etc/hosts
For completeness I should mention that if you have access to and control of all clients that will access the PaaS, you might be able to get away with adding host entries for each application to the /etc/hosts (or equivalent) file on each client. This is not recommended, or even possible, in most production setups, but can be helpful in many development and experimental environments.
6. Wildcard DNS
Of course, the sanctioned DNS wildcard solution suggested above is the best bet if your IT department allows for it. It's simple to configure and requires no additional API calls, separate DNS servers, or manual maintenance of hostnames.
To successfully provision apps to Cloud Foundry it's helpful to have a good grasp on how DNS is used, and some of the options for configuring DNS. Additional DNS considerations include configuring the PaaS for apex (root) domain support, and fallback routes. See the Cloud Foundry Domain-routes docs for more detail.