Node.js® Enterprise Support
New comprehensive plans availableLearn More
Thank you for contacting us. We will get back to you shortly.
November 03, 2015 - by Tim Gross
Joyent introduced Triton Container Name Service (CNS) on 8 March 2016 along with an updated version of our modern application blueprint demonstrating how to run Node.js applications in Docker with Nginx and Couchbase.
Triton CNS eliminates the need to run the CloudFlare watcher container described here. See the CNS readme for details about how to use CloudFlare with CNS.
Mentions of Containerbuddy in this post should be read as references to ContainerPilot.
In a container-native project, we need to balance the desire for ephemeral infrastructure with the requirement to provide a predictable load-balanced interface with the outside world. By updating DNS records for a domain based on changes in the discovery service, we can make sure our users can reach the load-balancer for our project at all times.
As discussed in a previous post, we can use Containerbuddy to listen for changes to an application and make updates to a downstream service. This time, instead of making changes to our load balancing tier based on the changes in the application servers, we're going to push changes to DNS records via the CloudFlare API based on changes in the load balancing tier.
In our application, we'll be using Nginx as our stateless load-balancing tier. We could just as easily use HAProxy here, but for purposes of the example it's easier if we have a web server serving a static file. Containerbuddy in the Nginx containers will update Consul with the containers' public IP. We'll have a container named
cloudflare that will use Containerbuddy to watch for changes in the Nginx service.
cloudflare container will have a Containerbuddy
onChange handler that updates CloudFlare via their API. The handler is just a bash script that queries the CloudFlare API for existing A records, and then diffs these against the IP addresses known to Consul. If there's a change, we add the new records first and then remove any stale records.
You can find a demonstration of this architecture in the
example directory of the Github repo. Running this example on your own requires that you have a CloudFlare account and a domain that you've delegated DNS authority to CloudFlare. Note that if you just want to try it out without actually updating your DNS records you can go through the whole process of getting CloudFlare in front of your site (on their free tier) and so long as you don't update your nameservers with your registrar there will be no actual changes to the DNS records seen by the rest of the world. Once you're ready:
docker-compose) on your laptop or other environment, as well as the Joyent CloudAPI CLI tools (including the
curl -O https://raw.githubusercontent.com/joyent/sdc-docker/master/tools/sdc-docker-setup.sh && chmod +x sdc-docker-setup.sh ./sdc-docker-setup.sh -k us-east-1.api.joyent.com <ACCOUNT> ~/.ssh/<PRIVATE_KEY_FILE>
At this point you can run the example on Triton:
cd ./examples make .env ./start.sh
or in your local Docker environment:
cd ./examples make # at this point you'll be asked to fill in the values of the .env # file and make will exit, so we need to run it again make ./start.sh -f docker-compose-local.yml
.env file that's created will need to be filled in with the values describe below:
CF_API_KEY=<your CloudFlare API key> CF_AUTH_EMAIL=<the email address associated with your CloudFlare account> CF_ROOT_DOMAIN=<the root domain you want to manage. ex. example.com> SERVICE=nginx <the name of the service you want to monitor> RECORD=<the A-record you want to manage. ex. my.example.com> TTL=600 <the DNS TTL you want>
The Consul UI will launch and you'll see the Nginx node appear. The script will also open your CloudFlare control panel at https://www.cloudflare.com/a/dns/example.com (using your own domain, of course) and then you'll see the domain or subdomain you provided in the
Let's scale up the number of
docker-compose scale nginx=3
As the nodes launch and register themselves with Consul, you'll see them appear in the Consul UI. You'll also see the A records in your CloudFlare console update.
Although we remove stale records after we add new records, in a production environment we won't want to simply swap out one of our Nginx containers for another immediately. Because clients or recursive DNS resolvers will be respecting the TTL of our A record, we'll want to add a new container, wait for DNS propagation (you can do this by monitoring traffic flow), and only once the new container is receiving traffic remove the old container.
The problem is that if we simply remove the old container we'll have a period of lost traffic between the time we remove the container and the TTL expires. We need a way to signal Containerbuddy to mark the node for planned maintenance. I'll circle back to that in a revision to Containerbuddy and discuss this change in an upcoming post.
If you've been following the request-for-discussion on the Triton Container Naming Service (TCNS) you'll know that Joyent is working on adding a feature to our platform that will simplify some of what we've discussed here. When that feature is available, we can simply add a CNAME in our external DNS provider that points to the TCNS-assigned name for the service. This example has an added advantage of connecting our containers to a global CDN for faster performance.
So far in this series I've talked about the expectations of container-native applications, introduced Containerbuddy as a means of shimmming existing applications, dynamic load balancing via Nginx, and now updating DNS providers so we can have zero-downtime deploys. In upcoming posts I'll tie these components together into a production-ready multi-tier application.
The following video offers a walkthrough of how to automate application discovery and configuration using Containerbuddy and demonstrates the process in the context of a complete, Dockerized application.