In this project, traefik's ports are published using the mode=host
and
published=<PORT>
options. This ensures the following:
- Listening to both
tcp
(IPv4) andtcp6
(IPv6). - Getting the client IP (
X-Forwarded-For
/X-Real-IP
).
If you need to read the client IP in your applications/stacks using the
X-Forwarded-For
orX-Real-IP
headers provided by Traefik, you need to make Traefik listen directly, not through Docker Swarm mode, even while being deployed with Docker Swarm mode.For that, you need to publish the ports using "host" mode.
— Traefik Proxy with HTTPS - Docker Swarm Rocks > Getting the client IP
Using the mode=host
option, the service's ports are published directly on the
node where it is running.
❗ Note: If you publish a service’s ports directly on the swarm node using
mode=host
and also setpublished=<PORT>
this creates an implicit limitation that you can only run one task for that service on a given swarm node. You can work around this by specifyingpublished
without a port definition, which causes Docker to assign a random port for each task.In addition, if you use
mode=host
and you do not use the--mode=global
flag ondocker service create
, it is difficult to know which nodes are running the service to route work to them.
— Deploy services to a swarm | Docker Documentation > Publish ports
If you don't need the client IP in your applications/stacks, you can publish traefik's ports using the routing mesh.
sudo nano ~/docker/webproxy/docker-compose.yml
diff --git a/docker-compose.yml b/docker-compose.yml
index d3516bd..543b2d3 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -4,15 +4,9 @@ services:
traefik:
image: traefik:${TF_VERSION}
ports:
- - target: 80
- published: 80
- mode: host
- - target: 443
- published: 443
- mode: host
- #- target: 8080
- # published: 8080
- # mode: host
+ - '80:80'
+ - '443:443'
+ #- '8080:8080'
networks:
- webproxy
volumes:
Apply the changes to the service:
cd ~/docker/webproxy
env $(cat .env | grep "^[A-Z]" | xargs) docker stack deploy -c docker-compose.yml webproxy
Somehow, this setup only allows requests on tcp
(IPv4). Solution: Set up two
services to listen on tcp6
(IPv6) ports 80 and 443 and redirect the requests
to 127.0.0.1
(localhost) on tcp
(IPv4).
Set up service:
sudo nano /etc/systemd/system/swarm-ipv6@.service
sudo nano /etc/systemd/system/swarm-ipv6@.socket
Enable services for ports 80 and 443:
sudo systemctl daemon-reload
sudo systemctl enable swarm-ipv6@80.service
sudo systemctl enable swarm-ipv6@443.service
Reboot:
sudo reboot
Services can be reached via AAAA records for the public IPv6 address, while traefik forwards the requests to the containers based on their labels.
Containers can reach services using IPv6 - both on bridge
and overlay
networks.
Test using bridge
network:
docker run --rm -ti busybox ping6 -c 4 google.com
Test using overlay
network:
mkdir -p ~/docker/busybox
nano ~/docker/busybox/docker-compose.yml
cd ~/docker/busybox
docker stack deploy -c docker-compose.yml busybox
docker exec -ti $(docker ps -q -f name=busybox_ipv6) ping6 -c 4 google.com
Note: Setting net.ipv6.conf.eth0.accept_ra=2
in
/etc/sysctl.d/99-ipv6.conf
is required for this to work.
Containers can reach each other using IPv6 - both in bridge
and overlay
networks.
Test using overlay
network:
docker exec -ti $(docker ps -q -f name=busybox_ipv6) ping6 $(docker container inspect -f '{{ .NetworkSettings.Networks.webproxy.GlobalIPv6Address }}' $(docker ps -q -f name=webproxy_traefik))
However - and in contrast to IPv4 - containers can not reach each other
using IPv6 by service name in overlay
networks.
Test using overlay
network:
docker exec -ti $(docker ps -q -f name=busybox_ipv6) ping6 traefik
Note: IPv6 service discovery works perfectly well in bridge
networks,
though.
This means that docker containers in an overlay
network communicate via IPv4.
Note: Alpine-based containers seem to
have a problem with dual-stack overlay
networks.
Use the default version (e.g. nginx
instead of nginx:alpine
) to avoid any
problems.
The address block 2001:db8:1::/64
mentioned on Enable IPv6 support | Docker Documentation
is a subnet of 2001:db8::/32
, which is
a reserved prefix for use in documentation.
— RFC 3849: IPv6 Address Prefix Reserved for Documentation
Therefore, private fd00:[0, ffff]::/80
subnets are used in this project.
- Publish ports directly on the swarm node: Traefik Proxy with HTTPS - Docker Swarm Rocks, Deploy services to a swarm | Docker Documentation
- Alternative: Publish ports using the routing mesh: moby/moby#24379 (comment)
- IPv6 address range: Docker - ArchWiki > Configuration > IPv6