<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>IPv6 on  rlang // tech</title>
    <link>https://blog.rlang.tech/tags/ipv6/</link>
    <description>Recent content in IPv6 on  rlang // tech</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <copyright>Rico Lang (CC BY 4.0)</copyright>
    <lastBuildDate>Mon, 20 Jan 2025 20:18:32 +0100</lastBuildDate>
    <atom:link href="https://blog.rlang.tech/tags/ipv6/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>How to run Docker on IPv6</title>
      <link>https://blog.rlang.tech/posts/docker-on-ip-v6/</link>
      <pubDate>Mon, 20 Jan 2025 20:18:32 +0100</pubDate>
      <guid>https://blog.rlang.tech/posts/docker-on-ip-v6/</guid>
      <description>Overcoming IPv6 challenges with Docker? This tutorial shows you how to seamlessly run Docker containers on an IPv6-only host, enabling you to leverage the benefits of IPv6 networking.</description>
      <content:encoded><![CDATA[<p>When running Docker on an IPv6 only host it can be quite complicated to set it up properly. This blog post will help you
to get your container running on an IPv6 only infrastructure and avoid the most common gotchas.</p>
<h2 id="prerequisites">Prerequisites</h2>
<ul>
<li>An IPv6 global prefix</li>
<li>Root permissions on the host</li>
</ul>
<h2 id="a-word-of-caution">A word of caution</h2>
<p>The first thing to note is that running on an IPv6 only host, it means that only v6 networking is generally possible.
So any communication running over v4 won&rsquo;t be possible. For example lets try DNS resolution. If I try to get the IP for
google.com on my IPv6 host I get the following response:</p>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ dig www.google.com
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>...
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>;; ANSWER SECTION:
</span></span><span style="display:flex;"><span>www.google.com.		217	IN	A	142.250.186.68
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>;; Query time: <span style="color:#ae81ff">0</span> msec
</span></span><span style="display:flex;"><span>;; SERVER: 2a01:4ff:ff00::add:2#53<span style="color:#f92672">(</span>2a01:4ff:ff00::add:2<span style="color:#f92672">)</span> <span style="color:#f92672">(</span>UDP<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>...</span></span></code></pre></div><p>One thing we can immediately see is, that the DNS server that answered our request has an IPv6 address, but what happens
now if
I tell dig to resolve the query via an IPv4 DNS server ?</p>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ dig @1.1.1.1 www.google.com
</span></span><span style="display:flex;"><span>;; communications error to 1.1.1.1#53: timed out</span></span></code></pre></div><p>The request timed out as we expected because our host is not capable of using the IPv4 protocol. The same behavior will
be observable in our Docker containers unless we explicitly tell Docker to run in IPv6 mode. So, let&rsquo;s get going!</p>
<h2 id="configure-the-docker-daemon">Configure the docker daemon</h2>
<p>To configure the daemon(assuming you use dockerd), we need to edit the <code>daemon.json</code>. On linux hosts you can find the
file under <code>/etc/docker/daemon.json</code>, if you&rsquo;re running on another system consult
the <a href="https://docs.docker.com/engine/daemon/">documentation</a> of docker engine. If the file does not exist simply create
it.</p>
<p>In order to fix the problem with the DNS resolution we need to tell the daemon to use IPv6 DNS servers. In this scenario
I provided cloudflares DNS server. Additionally, we also instruct the daemon to enable v6 networking, as well as
creating
the default network with <a href="https://en.wikipedia.org/wiki/Unique_local_address">ULA</a> addresses.</p>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;IPv6&#34;</span>: <span style="color:#66d9ef">true</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;fixed-cidr-v6&#34;</span>: <span style="color:#e6db74">&#34;fd00:dead:beef::/48&#34;</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;dns&#34;</span>: [
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;2606:4700:4700::1111&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;2606:4700:4700::1001&#34;</span>
</span></span><span style="display:flex;"><span>  ],
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;ip6tables&#34;</span>: <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div><h2 id="retrieving-the-prefix">Retrieving the prefix</h2>
<p>To make your container globally reachable, we have to create an IPv6 network based on the global prefix of your host. In
simplified terms, the global prefix is a 48-bit unique prefix that is used to route packets to your network. To find
your IPv6 global prefix, you can execute <code>ip -6 addr show</code>. You want to search for a similar entry like this:</p>





<pre tabindex="0"><code>2: eth0: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc fq_codel state UP group default qlen 1000
   ...
    inet6 2a01:4f8:1c0c:66b3::1/64 scope global noprefixroute
       valid_lft forever preferred_lft forever
   ...</code></pre><p>As you can see, my hoster assigned me a /64 prefix. That means that the first 64 bits of the IPv6 address are fixed. So,
in my example, <code>2a01:04f8:1c0c:66b3</code> is the fixed part. If we would fully write out the IP, it would look like this <code>2a01: 04f8:1c0c:66b3:0000:0000:0000:0001</code>.</p>
<h2 id="creating-the-ipv6-network">Creating the IPv6 network</h2>
<p>Now let&rsquo;s choose a smaller subnet for our public network. For example lets choose a /80 subnet like
<code>2a01:4f8:1c0c:66b3:1::/80</code> . This will ensure containers in that network will receive a globally routable address,
which means that those containers can be reached from the outside, unless blocked by a firewall or something similar.</p>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ docker network create --IPv6 --subnet 2a01:4f8:1c0c:66b3:1::/80 public</span></span></code></pre></div><h2 id="run-your-container">Run your container</h2>
<p>Last but not the least run a container and attach it to our public network:</p>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>docker run --rm --network public -p <span style="color:#f92672">[</span>::<span style="color:#f92672">]</span>:8080:80 traefik/whoami</span></span></code></pre></div><p>And if we now have a look at our container it has been assigned a globally routable IPv6 address. That we can reach from
the internet.</p>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ docker inspect 31cb810f7c00
</span></span><span style="display:flex;"><span>...
</span></span><span style="display:flex;"><span>            <span style="color:#e6db74">&#34;Networks&#34;</span>: <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>                <span style="color:#e6db74">&#34;public&#34;</span>: <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>                    ...
</span></span><span style="display:flex;"><span>                    <span style="color:#e6db74">&#34;IPv6Gateway&#34;</span>: <span style="color:#e6db74">&#34;2a01:4f8:1c0c:66b3:1::1&#34;</span>,
</span></span><span style="display:flex;"><span>                    <span style="color:#e6db74">&#34;GlobalIPv6Address&#34;</span>: <span style="color:#e6db74">&#34;2a01:4f8:1c0c:66b3:1::3&#34;</span>,
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>...</span></span></code></pre></div>]]></content:encoded>
    </item>
  </channel>
</rss>
