Oct 26, 2023 - Chris Aubuchon, Head of Customer Success

Running Containers On IPv6 Networks

What better motivation to start adopting a technology than the need to completely replace the alternative. From a world driven on limited resources like gas, coal, and oil to wind, hydro, nuclear, geothermal, and solar… we find ourselves, as a species, evolving past a first generation we envisioned as abundant, but turned sparse.

Adopting IPv6 networking is another version of this same story. Networking enthusiasts can spout off numerous wonderful reasons to adopt IPv6, but at the end of the day none of them compare to the absolute exhaustion of IPv4 space. There’s really just no room left.

The question: Is adopting IPv6 really so difficult?

The short answer is No.

Getting Started

For this post, I’d like to highlight what it takes to get a container set up to be run in an IPv6 network and then talk at a high level about what it takes to create that network.

The first thing we need is a container. For this I’ve created a companion repo with all necessary files. In this repo you’ll find a simple node server. On the development branch you can find the code for the IPv4 examples and the main branch will be set up to listen on dual stack (IPv4/IPv6) networking.

I don’t think it makes much sense to cover workloads such as batch jobs, CLI’s, scientific computing simulations, machine learning, or any other type of work that doesn’t need to “reply” over the network. However, you can apply the lessons in this blog to databases, in memory stores, queues, and anything else (not just http servers) that relies on traffic over IP.

Binding IPs

One of the simplest ways to identify if a container will work in an IPv6 network is to check the IP bindings for the container and the most straightforward way to do this is using the tool netstat.

Pull down the repo, and build the container by checking out the development branch and running docker build -t testserver . from the root of the repo.

Next run docker run -it -d –rm –name=server testserver and then docker exec -it server sh to grab a shell.

From here we can inspect the way the server is bound to the containers IP address space by running netstat -aln

output from running netstat.

You can see in the code and in the return that the server listens on 0.0.0.0, which is “bind all” IPv4. If you tried to use this container in an IPv6 network it would be “unreachable”.

To bind to the available IPv6 space within the container we can define “bind all” on ALL available IP addresses within the container by using the :: two colons. This is a relative standard in the industry and while in this case just adding “::” will work, I will mention that some servers may call for the colons to be wrapped in brackets like so “[::]”.

If you check out the main branch and rebuild the image you can see that I’ve already set this code change up. Simply rebuild the image, run it, and then use exec to connect to the running container. From here use netstat -aln to show that you’re now listening on :::3000.

output from running netstat showing bind all IPs.

This container can now be used in an IPv6 network.

Implementing Networks

At this point, things might feel pretty easy… You might even ask yourself, “Self, why haven’t we always used IPv6?”. And I think that's a fair question. The reason is probably, designing IPv6 network spaces, especially directly on top of existing IaaS providers, leaves quite a bit to be desired.

Some questions you’ll need to answer if you want to create your own IPv6 network space on top of say… AWS would be:

  1. Does my VPC have an IPv6 CIDR block enabled?
  2. How many public and private subnets would I like to create, and in what AZ’s/Regions?
  3. Are my route tables updated to use the new IPv6 nets?
  4. Are the security groups and ACL’s updated?
  5. Is my ELB set up to support IPv6 traffic?
  6. Should I configure AAAA records in Route 53?

Another route you can take is using a platform like Cycle that automates IPv6 networking by default. Spinning up a new environment will create a new private IPv6 network for your containers to be deployed to. If you’ve never done this before, check out this guide. Once you’ve created your new environment, deploy your container(s) the way you normally do, either through the deploy container form, programmatically through the API, or (soon) through the CLI.

In a Cycle environment, the environment itself will be assigned a IPv6 /80 CIDR, from this block each container will get a /96 and each instance a single IP. The load balancer service can be assigned public IPv4, IPv6, or both and its important to note that while IPv6 is rock solid for internal, private networks… if you’re not sure that end users will have access to IPv6 networks, you’ll need to enable IPv4 at the load balancer to ensure public access is reachable.

Whichever path you choose to go, start down it soon. IPv4 has been on its deathbed for 10+ years and it's not getting any healthier. While it's still needed for public facing endpoints, there will be a time very soon where it is not and those who have moved most of their private networks to IPv6 will be leagues ahead of the rest.

💡 Interested in trying the Cycle platform? Create your account today! Want to drop in and have a chat with the Cycle team? We'd love to have you join our public Cycle Slack community!