Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: basic implementation of IPv6 for IPv6 docker networks #2437

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

Murazaki
Copy link

@Murazaki Murazaki commented May 3, 2024

Just adds IPv6 as upstream IP if available. Might come in handy for people that rely on IPv6 only docker networks.

@buchdag buchdag added type/feat PR for a new feature status/pr-needs-tests This PR needs new or additional test(s) labels May 5, 2024
@buchdag
Copy link
Member

buchdag commented May 14, 2024

@Murazaki are IPv6 only Docker network a possibility ?

Last time I checked it wasn't, but that was a while (ie a few years) ago.

@Murazaki
Copy link
Author

It works, and I'm using it right now. Though there is a couple of tricks to it.

Here's a lengthy explanation that I used to set it up.
https://github.com/docker-mailserver/docker-mailserver/blob/5bd8df68eb06b0f8879f7a953a6da607b77a4730/docs/content/config/advanced/ipv6.md

@Murazaki
Copy link
Author

You might also have to be ready to dive a bit more into iptables on your server, to make sure local ipv6 addresses are properly routed.

@buchdag
Copy link
Member

buchdag commented May 15, 2024

I've tried to create an IPv6 only Docker network with the instructions you provided but did not manage to, whatever I do Docker always affect an IPv4 subnet to my network. This seems to be possible with Podman, but the same solution does not work with Docker.

Could you provide a docker network inspect of an IPv6 only Docker network / do you remember how you managed to create it ?

Regardless of this, I have two small issues with this PR:

  • the fact that it add two server directive to the upstream block per container (one for each type of IP address) might accidentally inflate the effective round-robin weight (for a given upstream) of containers that have both IPv4 and IPv6 addresses over those who don't. We already prevent the creation of multiple server directive for containers that can be reached from multiple networks for the same reason, I feel like we should do the same here. Ideally I'd say to prioritise IPv6 when available over IPv4, but given the current state of IPv6 in Docker I think prioritising IPv4 might be a safer choice for everyone, while still enabling IPv6 support when using networks without IPv4.
  • we should avoid printing warning to the configuration if there is nothing preventing it from working. We should not be printing /!\ No IPv6 for this network! when a container does not have an IPv6 address (ie to the vast majority of users), because it can work perfectly fine with an IPv4 address.

Suggested changes:

--- nginx.tmpl	2024-05-15 17:19:23.000000000 +0200
+++ nginx.mod.tmpl	2024-05-15 17:26:06.000000000 +0200
@@ -92,31 +92,30 @@
         {{- end }}
         {{- /*
              * Do not emit multiple `server` directives for this container if it
-             * is reachable over multiple networks.  This avoids accidentally
-             * inflating the effective round-robin weight of a server due to the
-             * redundant upstream addresses that nginx sees as belonging to
+             * is reachable over multiple networks or multiple IP stacks. This avoids 
+             * accidentally inflating the effective round-robin weight of a server due
+             * to the redundant upstream addresses that nginx sees as belonging to
              * distinct servers.
              */}}
-        {{- if $ip }}
+        {{- if or $ip $ipv6 }}
     #         {{ .Name }} (ignored; reachable but redundant)
             {{- continue }}
         {{- end }}
     #         {{ .Name }} (reachable)
         {{- if and . .IP }}
             {{- $ip = .IP }}
-        {{- else }}
-    #             /!\ No IPv4 for this network!
         {{- end }}
         {{- if and . .GlobalIPv6Address }}
             {{- $ipv6 = .GlobalIPv6Address }}
-        {{- else }}
-    #             /!\ No IPv6 for this network!
+        {{- end }}
+        {{- if and (empty $ip) (empty $ipv6) }}
+    #             /!\ No IPv4 or IPv6 for this network!
         {{- end }}
     {{- else }}
     #         (none)
     {{- end }}
     #     IPv4 address: {{ if $ip }}{{ $ip }}{{ else }}(none usable){{ end }}
-    #     IPv6 address: {{ if $ipv6 }}{{ $ipv6 }}{{ else }}(none usable){{ end }}
+    #     IPv6 address: {{ if $ipv6 }}{{ $ipv6 }}{{ if $ip }} (ignored; reachable but redundant){{ end }}{{ else }}(none usable){{ end }}
     {{- $_ := set $ "ip" $ip }}
     {{- $_ := set $ "ipv6" $ipv6 }}
 {{- end }}
@@ -330,8 +329,7 @@
             {{- end }}
             {{- if $ip }}
     server {{ $ip }}:{{ $args.port }};
-            {{- end }}
-            {{- if $ipv6 }}
+            {{- else if $ipv6 }}
     server [{{ $ipv6 }}]:{{ $args.port }};
             {{- end }}
         {{- end }}

This result in this upsteam block for a dual stack container:

upstream whoami.example {
    # Container: nginx-proxy-whoami-1
    #     networks:
    #         nginx-proxy_default (reachable)
    #     IPv4 address: 172.31.0.2
    #     IPv6 address: fd00:cafe:face:feed::2 (ignored; reachable but redundant)
    #     exposed ports: 8000/tcp
    #     default port: 8000
    #     using port: 8000
    server 172.31.0.2:8000;
}

@Murazaki
Copy link
Author

Ok you are right, unless anything has changed, docker networks are either ipv4 or "ipv4 and ipv6', which is a difference with Podman, that authorizes ipv4, ipv6, and "ipv4 and ipv6" networks.

I don't see major issues with the changes you mentioned, I'm gonna test them and push them if everything goes well.

@Murazaki
Copy link
Author

Okay it does deactivate ipv6 though if you have ipv4 addresses. What if we want to use IPv6 rather than IPv4 ?

@buchdag
Copy link
Member

buchdag commented May 15, 2024

I was thinking about that, maybe we could introduce a PREFER_IPV6 environment variable or something similar. It could also make the PR easier to test even if we can't create IPv6 only Docker networks.

Out of curiosity, what would be the use cases for preferring IPv6 on a dual stack Docker network ?

@Murazaki
Copy link
Author

I won't argue around IPv6 benefits in the local network.
I just think people might have the preference to go for IPv6 rather than IPv4, maybe simply by simplification or because it helps them getting used to it ?
It might also be a way for people to move out of NAT methodology, which might open the road to per docker stack proxy, or to move out of proxying entirely ? I do not think I have a complete answer as the world has been delaying moving to IPv6 for all this time.

@buchdag

This comment was marked as outdated.

@buchdag buchdag self-assigned this May 15, 2024
@Murazaki
Copy link
Author

This works. do you want me to push it ?

@buchdag
Copy link
Member

buchdag commented May 15, 2024

Nope, I made a mistake on that version, I think it won't work on IPv6 only networks.

I'm working on another version and adding tests (but I won't be able to test IPv6 only networks as I don't use Podman).

@buchdag buchdag changed the title Basic implementation of IPv6 for IPv6 docker networks feat: basic implementation of IPv6 for IPv6 docker networks May 15, 2024
@buchdag
Copy link
Member

buchdag commented May 15, 2024

Ok, I got pretty much everything except documentation on this branch.

Could you take a look at it and test it ? If everything is okay for you, I'll push the commits here.

@buchdag buchdag linked an issue May 16, 2024 that may be closed by this pull request
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status/pr-needs-tests This PR needs new or additional test(s) type/feat PR for a new feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Cannot reach container in IPv6 network
2 participants