Using Triton Container Name Service with Docker and vanity domain names

October 26, 2016 - by Alexandra White

Triton Container Name Service (CNS) is designed to do two things: serve address records for instances by instance name and serve address records for instances grouped by service tag. The latter means that multiple instances can share the same address record.

If you've previously managed the process of mapping DNS names to IP numbers, you know what a hassle it can be. It's one of the reasons some servers turn into pets. And, when scaling your application up or down, you need to re-update all your DNS to IP mappings.

When traffic is exploding because your website has the latest viral image that will "break the internet," you don't want it to actually break the internet. If anything, it will never be more important to be able to scale quickly than in that moment. Having to map IPs addresses to DNS names takes precious time that you may not have. Plus, when you scale back down when people have moved on, you need to remember which IPs were associated with which instance and remove only the IP addresses of the instances that no longer exist. Does your head hurt yet?

Now add immutible and disposable infrastructure, where each new deploy can change the IP numbers for the running app. Wouldn't it be convenient if there was a way to automatically update DNS for any IP address change?

Imagine you have friends on a road trip. If this road trip was in 1972, before the age of cellphones for every person, pet, and peanut, you would have to learn a new hotel number every time your friends changed their location. A cell phone makes that change irrelevant; no matter where your friends are on their trip, the cell phone number remains the same. Triton CNS is your cell phone; it gives a constant name to a changing infrastructure.

Triton CNS knows when containers are running. DNS names are automatically updated as containers start and stop so that requests are only sent to running containers.

I'm going to offer an example of how I use CNS with a custom domain name with WordPress, or you can jump to the bottom for the basics about using CNS.

I built a WordPress website using the Autopilot Pattern. Each of the different components, including MySQL, Memcached, WordPress in PHP, and others are running in separate containers. At the front of the site is Nginx, which I load balance using CNS. When one of those containers is updated, the container is replaced and the IP behind it is changed. It's the job of your Domain Name Servers (DNS) to translate those IP addresses to allow your browser to communicate with the web. When an address changes, the browser would be lost without the DNS being re-mapped.

New WordPress releases come so frequently, it can be hard to keep up. Triton CNS will spare me the headache of worrying about re-mapping the updated containers.

When enabled, Triton CNS automatically generates DNS names for every container, but the generated names may not be the names you want your customers or visitors to use. Read below for how to assign your own domain to CNS so that it automatically updates with changes to your containers, or jump down to how to find the CNS names for your containers.

Using vanity domains with Triton CNS

Using a custom domain name is easy with Triton CNS. There are several providers who sell domain names including Namecheap (my registrar of choice), Hover, Name.com, and too many more to list.

New top-level domain extensions like .codes, .rocks, .llp, and .wtf make it especially fun to find the perfect name for your app or website. Any of these domain extensions will work with Triton CNS. Being fond of space, I decided to purchase "alexandra.space" and wait for an opportunity to put it to good use.

I can use the "Advanced DNS settings" within Namecheap to map "alexandra.space" to my WordPress website on Triton as a CNAME. This process will look different depending on your domain provider, but the concept remains the same.

My dashboard assigning DNS names to CNAMEs

For my WordPress website, I want visitors to be directed to the frontend of my application. The Autopilot Pattern implementation of WordPress uses Nginx as an HTTP server to serve content, so my CNAME points to the CNS-generated DNS for the Nginx containers. When I scale or update the Nginx containers, the IP numbers may change (new container=new IP), but the generated CNS name for the Nginx service remains the same. The new IPs will be reflected in the DNS without having to lift a finger. I had to manually set the CNAME for my custom domain once, Triton CNS takes care of everything from there.

No matter how many times I rebuild or update WordPress, you will still be able to open alexandra.space in your browser and interact with the website.

The Autopilot Pattern WordPress implementation has the tags and labels to use Triton CNS baked-in, but read on for how to enable CNS in your apps.

Enable Triton CNS

In order to use vanity domains, it's important to enable Triton CNS for your Joyent account. This is easy to turn on, both using Triton CLI and in the Joyent portal.

Triton CLI

To enable Triton CNS using Triton CLI, set your terminal environment to Triton.

eval $(triton env)

Once you're in the Triton environment, update your account to enable Triton CNS.

triton account update triton_cns_enabled=true

You now will be able to run new containers with Triton CNS or add that feature to preexisting containers.

Joyent portal

Sign into my.joyent.comAccount where you'll see a summary of information about your account. To enable Triton CNS, edit your profile and check the box next to "Use Container Name Service".

enable Triton CNS in the portal

Run a container with Triton CNS

Once you know your account is set to use Triton CNS, then you're ready to create a Triton CNS powered container. Use Triton CLI to set your terminal to the Triton environment.

To create a new instance with Triton CNS enabled, use docker run:

docker run -d -p 80 --label triton.cns.services= /

Let's break down this command step by step:

  • docker run creates a container.
  • -d detaches the container, which means it's running in the background. You can continue to run commands from outside of the container so you don't have to login to the container or start/stop it.
  • -p 80 tells Triton to use port 80. This declaration ensures your container will receive an external IP address that is reachable over the public internet.
  • --label triton.cns.services= tells Triton CNS to give your application a specific title, which will be used in the DNS string.
  • / is the format for a Docker Hub image that is being pulled. If you're using a different registry, it may be formatted different.

The most important part of that command is triton.cns.services=. Use any DNS-safe name that has meaning for what the container does in your application. For example, if you were to create your personal portfolio you could use triton.cns.services=myportfolio.

Using Triton CNS with Docker Compose

Docker Compose makes it easy to start a number of Docker containers all at once. The WordPress example above uses our Autopilot Pattern WordPress implementation to make starting WordPress— Nginx, MySQL, Memcached, PHP, and other services each running in separate containers—as easy as docker-compose up -d.

The docker-compose.yml file includes Docker labels that set the CNS service name for each of the different containers. Here's the CNS services label set for the Nginx container:

  labels:
    - triton.cns.services=nginx

That Docker Compose syntax has the same effect as setting a label with docker run as described above.

Using Triton CNS on preexisting instances

If you already have an instance up and running that you'd like to add Triton CNS power to, never fear. Run the following command:

triton instance tag set -w  triton.cns.services=</code></pre>
<p>Your container now has Triton CNS enabled and you can carry on to the next step.</p>
<h2 id='finding-your-dns-name'>Finding your DNS name</h2>
<p>To find out the important details for your Triton CNS-powered instance, use <code>docker ps</code> to list all of your Docker containers, or <code>triton instances</code> to list all of your instances running on Triton.</p>
<p>For any of your instances started after enabling CNS (or for which you've since added a CNS service tag to), you can get the full list of CNS-generated DNS names by running:</p>
<pre><code class="language-sh">triton instance get <container name></code></pre>
<p>Triton will tell you a lot of information about your instance, the CNS-generated DNS names are at the bottom:</p>
<pre><code class="language-sh">{
    "id": "a216675d-acf9-42b4-a3bf-3079f7cfc92e",
    "name": "spacewordpress_nginx_1",
    "type": "smartmachine",
    [...]
    "dns_names": [
        "a216675d-acf9-42b4-a3bf-3079f7cfc92e.inst.d9a01feb-be7d-6a32-b58d-ec4a2bf4ba7d.us-east-1.cns.joyent.com",
        "spacewordpress-nginx-1.inst.d9a01feb-be7d-6a32-b58d-ec4a2bf4ba7d.us-east-1.cns.joyent.com",
        "nginx.svc.d9a01feb-be7d-6a32-b58d-ec4a2bf4ba7d.us-east-1.cns.joyent.com",
        "a216675d-acf9-42b4-a3bf-3079f7cfc92e.inst.d9a01feb-be7d-6a32-b58d-ec4a2bf4ba7d.us-east-1.triton.zone",
        "spacewordpress-nginx-1.inst.d9a01feb-be7d-6a32-b58d-ec4a2bf4ba7d.us-east-1.triton.zone",
        "nginx.svc.d9a01feb-be7d-6a32-b58d-ec4a2bf4ba7d.us-east-1.triton.zone"
    ]
}</code></pre>
<p>The last section of details about the container, <code>dns_names</code>, has our necessary information. Some of the DNS names point to the public IP address and some point to a private IP. The DNS structure for a Triton CNS powered instance is as follows:</p>
<pre><code><service name>.svc.<account uuid>.<data center name>.triton.zone</code></pre>
<p>The many different names have different uses.</p>
<ul>
<li>Names beginning with <code>*.svc...</code> are service names. All containers by the same user in the same data center sharing the same service tag will be part of the service name, and will be round-robin load-balanced.</li>
<li>Names beginning with <code>*.inst...</code> are instance names. Only one container by the same user in the same data center can have a given instance name. CNS automatically generates instance names using the container name and UUID.</li>
<li>Names ending with <code>*.cns.joyent.com</code> point to a private IP address for the instance or service. These names can only be used inside the Triton data center, since the IP addresses are not internet-routable.</li>
<li>Names ending with <code>*.triton.zone</code> point to public IP addresses for the instance or service. These names will only be provided if the container has a public IP address</li>
</ul>
<p>For the CNS service address my WordPress site is <code>nginx.svc.d9a01feb-be7d-6a32-b58d-ec4a2bf4ba7d.us-east-1.triton.zone</code>. No matter how many times I redeploy my WordPress site or you redeploy your Triton CNS powered application, Triton CNS will keep that DNS information the same and up-to-date. Because <a href="#using-vanity-domains-with-triton-cns">my vanity domain name is CNAME'd to that CNS-generated name</a>, I never have to update DNS.</p>
<h2 id='look-up-your-dns'>Look up your DNS</h2>
<p>It may take a while for your domain to propagate the new CNAME. You can check in on it by running <code>dig <yoururlname.com></code>. This will reveal the record information about your domain, including where it is pointing and its TTL i.e. time to live (the timespan for which the record will be cached).</p>
<pre><code class="language-sh">; <<>> DiG 9.8.3-P1 <<>> www.alexandra.space
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 46281
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;www.alexandra.space.       IN  A

;; ANSWER SECTION:
www.alexandra.space.    1799    IN  CNAME   nginx.svc.d9a01feb-be7d-6a32-b58d-ec4a2bf4ba7d.us-east-1.triton.zone.
nginx.svc.d9a01feb-be7d-6a32-b58d-ec4a2bf4ba7d.us-east-1.triton.zone. 30 IN A 165.225.139.145
nginx.svc.d9a01feb-be7d-6a32-b58d-ec4a2bf4ba7d.us-east-1.triton.zone. 30 IN A 72.2.113.203

;; Query time: 152 msec
;; SERVER: 10.0.1.1#53(10.0.1.1)
;; WHEN: Tue Oct 25 13:34:54 2016
;; MSG SIZE  rcvd: 151</code></pre>
<p>We care most of all about <code>ANSWER SECTION</code>. This tells me that my domain, alexandra.space, has 1799 seconds left before the cache expires and is pointing to the CNAME nginx.svc.d9a01feb-be7d-6a32-b58d-ec4a2bf4ba7d.us-east-1.triton.zone. If I were to make changes right now to my CNAME, it would take at least 1799 seconds to propogate.</p>
<h2 id='where-to-be-cautious-about-using-dns'>Where to be cautious about using DNS</h2>
<p>DNS isn't the perfect solution for every application. DNS client problems are surprisingly common, including clients that refuse to respect TTLs and clients that don’t recognize multiple IPs in an A record. These problems are frustrating in a web browser (though modern browsers now have advanced DNS implementations that avoid these problems), but they can lead to applications failures when they occur inside the data center between the components of an application. </p>
<p>One way around those problems is using <a href="http://containersummit.io/articles/active-vs-passive-discovery">active discovery</a> where possible. If you can't modify your app or runtime environment to ensure good DNS client behavior, then you should consider using an alternative to DNS for discovery of application components. <a href="https://www.joyent.com/containerpilot">ContainerPilot</a> automates the processes of service registration, health checking, and discovery for this purpose.</p>

                                
                <div class="clearfix"></div>
            </div>
        </div>
        <div class="col-sm-4">
            <div class="sidebar first imgad">
    <a href="https://mnx.io"><img src="/assets/img/ads/mnx-io-triton-public-cloud-720x600.png" class="img-responsive"></a>
</div>

            <div class="sidebar second hidden-xs">
                <ul class="social clearfix">
  <li><a href="http://www.linkedin.com/company/joyent" class="linkedin" target="_blank"></a></li>
  <li><a href="https://www.facebook.com/joyentcloud" class="facebook" target="_blank"></a></li>
  <li><a href="http://twitter.com/joyent" class="twitter" target="_blank"></a></li>
  <li><a href="https://www.instagram.com/joyenttriton/" class="instagram" target="_blank"></a></li>
  <li><a href="/blog/feed" class="rss"></a></li>
</ul>

                <h4>More From CNS</h4>
                <ul class="events">
                                        <li><a href="/blog/reintroducing-bhyve">Reintroducing Bhyve</a></li>
                                        <li><a href="/blog/running-triton-on-equinix-metal">Running Triton on Equinix Metal</a></li>
                                        <li><a href="/blog/video-blog-flexible-disk-space">Video Blog: Flexible Disk Space</a></li>
                                        <li><a href="/blog/joyent-cloud-firewall-logging-in-a-proper-triton-deployment">Video Blog: Joyent Cloud Firewall Logging</a></li>
                                        <li><a href="/blog/setting-up-a-manta-triton-development-environment">Video Blog: Setting up a Manta/Triton development environment</a></li>
                    
                </ul>
            </div>
        </div>
    </div>
</div>
<script type="text/javascript">
  $(document).ready(function() {
    $('table').each(function() {
        $(this).addClass('table').addClass('table-bordered').addClass('table-striped');
    });
   });
</script>
</div>



    <link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700|Inconsolata" rel="stylesheet">
<script type="text/javascript" src="https://www.tritondatacenter.com/site/themes/joyent/js/bootstrap.min.js"></script>
<script type="text/javascript" src="https://www.tritondatacenter.com/site/themes/joyent/js/combined.js"></script>

<!-- <div class="offerings-cta wrap footer">
    <div class="container">
        <div class="row">
            <div class="col-xs-12">
                <p>Want to learn more about our cloud offerings? <a href="https://www.mnxsolutions.com/triton-contact-us" title="" class="getstarted">Request a Cloud Specialist</a></p>

            </div>
        </div>
    </div>
</div> -->
<footer class="footer" id="footer">
<div class="container hidden-print">
		<div class="foot-logo row">
				<div class="col-sm-12">
						<p><img src="/assets/img/triton-logo.svg" alt="Triton Logo" class="footer-logo"></p>
				</div>
				<div class="col-sm-8">
						<p class="foot-tag">Hybrid, Modern and Open, Triton is engineered to run the world’s largest cloud native applications</p>
				</div>
				<!-- <div class="col-sm-3 col-sm-offset-1">
						<p>Connect with Joyent</p>
						<ul class="social clearfix">
  <li><a href="http://www.linkedin.com/company/joyent" class="linkedin" target="_blank"></a></li>
  <li><a href="https://www.facebook.com/joyentcloud" class="facebook" target="_blank"></a></li>
  <li><a href="http://twitter.com/joyent" class="twitter" target="_blank"></a></li>
  <li><a href="https://www.instagram.com/joyenttriton/" class="instagram" target="_blank"></a></li>
  <li><a href="/blog/feed" class="rss"></a></li>
</ul>

				</div> -->
		</div>
</div>
<div class="container hidden-xs" id="footer">
		<div class="row hidden-xs hidden-print">
				<div class="col-sm-3 col-md-2 column">
						<h4>Open Source</h4>
						<ul>
								<!-- <li><a href="http://github.com/joyent" id="foot-github">Github/joyent</a></li> -->
								<li><a href="/triton/compute" id="foot-triton-open-source">Triton Compute Service</a></li>
								<li><a href="/smartos" id="foot-smartos-open-source">SmartOS</a></li>
								<li><a href="/triton/object-storage" id="foot-triton-object-storage">Object Storage</a></li>
								<!--<li><a href="http://github.com/autopilotpattern" id="foot-github-autopilotpattern">Github/autopilotpattern</a></li>
								<li><a href="/containerpilot" id="foot-containerpilot-open-source">ContainerPilot</a></li>
								<li><a href="/node-js" id="foot-node-open-source">Node.js</a></li>-->
						</ul>
				</div>
				<div class="col-sm-2 col-md-2 column">
						<h4>Documentation</h4>
						<ul>
								<!-- <li><a href="/blog" id="foot-blog">Joyent Blog</a></li> -->
								<li><a href="/getting-started" id="foot-triton-getting-started">Triton Getting Started</a></li>
								<!-- <li><a href="https://docs.tritondatacenter.com/public-cloud" id="foot-triton-compute-docs">Triton Compute</a></li> -->
								<li><a href="https://wiki.smartos.org" id="foot-triton-smartos-docs">Triton SmartOS</a></li>
								<!-- <li><a href="https://apidocs.tritondatacenter.com/manta/index.html" id="foot-object-storage-docs">Object Storage</a></li> -->
								<!--<li><a href="https://docs.tritondatacenter.com/public-cloud/instances/docker/containerpilot" id="foot-containerpilot-docs">ContainerPilot</a></li>-->
								<!--<li><a href="/node-js/production" id="foot-node-docs">Node.js Production Practices</a></li>-->
						</ul>
				</div>
				<!-- <div class="col-sm-2 col-md-2 column">
						<h4>About</h4>
						<ul>
								<li><a href="/about/press" id="foot-press">Press Room</a></li>
								<li><a href="/about/events" id="foot-events">Events</a></li>
								<li><a href="/about/management" id="foot-management">Management</a></li>
								<li><a href="/about/careers" id="foot-careers">Careers</a></li>
								<li><a href="/contact" id="foot-contact">Contact Us</a></li>
						</ul>
				</div> -->
				<div class="col-sm-2 column">
						<h4>Support</h4>
						<ul>
								<!-- <li><a href="https://portal.mnxsolutions.com/" id="footer-help-desk">Support Center</a></li> -->
								<!--<li><a href="https://status.tritondatacenter.com" id="footer-system-status">System Status</a></li>-->
								<!-- <li><a href="#" id="footer-feedback" data-toggle="modal" data-target="#feedback">Site Feedback</a></li> -->
								<li><a href="/search" id="footer-search">Site Search</a></li>
						</ul>
				</div>
		</div>
		<div class="row copyright">
				<!-- <div class="col-sm-6 logorow">
					<p>© 2022 MNX Cloud, Inc. | <a href="/about/policies">Policies</a></p>

				</div> -->
		</div>
</div>

<link rel="stylesheet" href="https://www.tritondatacenter.com/site/themes/joyent/css/MyFontsWebfontsKit.css">
</footer>
</div>
<div class="modal" id="feedback">
<div class="modal-dialog">
		<div class="modal-content">
				<div class="modal-header">
						<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
						<h2>Joyent.com Feedback</h2>
				</div>
				<div class="modal-body">
					<div class="thankyou alert-success" style="display: none;">
							<h4>Thank You</h4>
							<p>Thank you for helping us improve tritondatacenter.com.</p>
					</div>
						<div class="alert-danger feedback" style="display: none;">
								<h4>Forms are blocked</h4>
								<p>It appears you have an ad or script blocker that won't allow us to load our feedback form from <code>app-sjf.marketo.com</code>. To submit feedback, you can either temporarily unblock that domain, or email <a href="mailto:info@tritondatacenter.com">info@tritondatacenter.com</a>. Email may take longer to get to the relevant people.</p>
						</div>
					<form id="mktoForm_1244"></form>
					<script>
						try {
						MktoForms2.loadForm("//app-sjf.marketo.com", "993-RJQ-253", 1244, function(form){
								form.onSuccess(function(values, followUpUrl){
									//get the form's jQuery element and hide it
									form.getFormElem().hide();
									//return false to prevent the submission handler from taking the lead to the follow up url.
									$('.thankyou').show();
									return false;
								});
							});
						} catch(err) {
								$('.alert-danger.feedback').show();
						}
					</script>
				</div>
		</div>
</div>
</div>



    <!-- OneTrust Cookies Consent Notice start -->
    <!-- <script src="https://cdn.cookielaw.org/consent/9802b854-894a-4fdc-a636-c078e2129a19.js" type="text/javascript" charset="UTF-8"></script>
    <script type="text/javascript">
        function OptanonWrapper() { }
    </script> -->
    <!-- OneTrust Cookies Consent Notice end -->

    <script type="text/javascript">
        $(document).ready(function() {
            $('#toggle-menu').on('touchstart click',menu);
            $('.x').on('touchstart click',menu);
            $('#page').on('touchstart click',function(e) {
                var $bod = $('body');
                if ($bod.hasClass('menu-visible')) {
                    menu(e);
                }
            });
            $('#menu .main-nav li.top.subs > a').on('touchstart click', function() {
                var theClass = $(this).attr('id');
                if($(this).parent().hasClass('dropped')) {
                    $('li.top').removeClass('dropped');
                    $('ul.nav-drop').hide(300);
                } else {
                    $('li.top').removeClass('dropped');
                    $('ul.nav-drop').hide(300);
                    $(this).parent().addClass('dropped');
                    $('ul.nav-drop.' + theClass).show(300);
                }
                return false;
            });
        });
        function menu(e) {
            e.preventDefault();

            var $body = $( 'body' ),
                $page = $( '#page' ),
                $menu = $( '#menu' ),
                transitionEnd = 'transitionend webkitTransitionEnd otransitionend MSTransitionEnd';

            $body.addClass( 'animating' );

            if ( $body.hasClass( 'menu-visible' ) ) {
                $body.addClass( 'right' );
            } else {
                $body.addClass( 'left' );
            }

            $page.on( transitionEnd, function() {
                $body.removeClass( 'animating right left' ).toggleClass( 'menu-visible' );
                $page.off( transitionEnd );
            });
            e.stopPropagation();
        };
    </script>

    
    
<script async src="//static.getclicky.com/101367490.js"></script>
<noscript><p><img alt="Clicky" width="1" height="1" src="//in.getclicky.com/101367490ns.gif" /></p></noscript>
</body>
</html>