When I tried to support IPv6 easily with Docker-proxy, I couldn't do it before I knew it.

(Memorandum for myself)

Thing you want to do

I want to use Docker proxy on a dual stack Docker host to provide IPv6 services in an IPv4 single stack Docker container.

Common environment

Ubuntu 20.04

# cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=20.04
DISTRIB_CODENAME=focal
DISTRIB_DESCRIPTION="Ubuntu 20.04.1 LTS"
# uname -a
Linux server 5.8.0-36-generic #40~20.04.1-Ubuntu SMP Wed Jan 6 10:15:55 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

Expected behavior

Start an appropriate Docker container with docker-compose as shown below, and perform port forwarding with ports.


version: '3'
services:
  grafana:
    image: grafana/grafana
    ports:
    - 3000:3000

After starting the container, the docker-proxy process that performs the corresponding port forwarding is started at the same time.

root      120970  0.0  0.0 475320  3912 ?        Sl   18:27   0:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 3000 -container-ip 172.18.0.4 -container-port 3000

--IPv4 traffic The following DNAT rules will appear in iptables, so they will be processed before reaching the docker-proxy process.

# iptables -t nat -L DOCKER
Chain DOCKER (2 references)
target     prot opt source               destination
RETURN     all  --  anywhere             anywhere
RETURN     all  --  anywhere             anywhere
DNAT       tcp  --  anywhere             anywhere             tcp dpt:3000 to:172.18.0.3:3000

By the way, the return packet is IP masqueraded by POSTROUTING.

# iptables -t nat -L POSTROUTING 

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  172.17.0.0/16        anywhere
MASQUERADE  all  --  172.18.0.0/16        anywhere
MASQUERADE  tcp  --  172.18.0.3           172.18.0.3           tcp dpt:3000
MASQUERADE  tcp  --  172.18.0.4           172.18.0.4           tcp dpt:8888

--IPv6 traffic In the case of IPv6, unlike IPv4, DNAT rules are not inserted, and the above docker-proxy process performs conversion at the L4 level.

Actual behavior

So far

Confirmed version: Docker version 19.03.14, build 5eb3275d40

It can be seen that Type is IPv6 and listens on both IPv4/IPv6.

reference: A trap that can be accessed with IPv4 even if the address port LISTENed by netstat or lsof is displayed as IPv6

# lsof -i:3000
COMMAND      PID USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
docker-pr 120970 root    4u  IPv6 1065660      0t0  TCP *:3000 (LISTEN)

Recently

Confirmed version: Docker version 20.10.2, build 2291f61

Type is IPv4, and only listens on IPv4. ** Therefore, the service cannot be provided by IPv6 **

# lsof -i:3000
COMMAND     PID USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
docker-pr 14845 root    4u  IPv4 6231154      0t0  TCP *:3000 (LISTEN)

Workaround

If you set the Docker version to less than 19.0 (probably unverified), it will return to the previous behavior. Refer to the official documentation and install older versions of docker-ce and docker-ce-cli.

Install Docker Engine

--Check the version of docker-ce that can be installed

# apt-cache madison docker-ce
 docker-ce | 5:20.10.2~3-0~ubuntu-focal | https://download.docker.com/linux/ubuntu focal/stable amd64 Packages
 docker-ce | 5:20.10.1~3-0~ubuntu-focal | https://download.docker.com/linux/ubuntu focal/stable amd64 Packages
 docker-ce | 5:20.10.0~3-0~ubuntu-focal | https://download.docker.com/linux/ubuntu focal/stable amd64 Packages
 docker-ce | 5:19.03.14~3-0~ubuntu-focal | https://download.docker.com/linux/ubuntu focal/stable amd64 Packages

--Uninstall new docker-ce

# apt-get remove docker docker-engine docker.io containerd runc

--Install old docker-ce, docker-ce-cli

# apt-get install docker-ce=<VERSION_STRING> docker-ce-cli=<VERSION_STRING> containerd.io

Impressions and future

We haven't investigated how such a specification change was made, but ** it's really troublesome **

In the first place, IPv4 is converted by DNAT of iptables, so proxy is not required, so why does docker-proxy listen with TYPE: IPv4 ... What if listen with TYPE: IPv6? Can provide services with IPv4 ...

Recommended Posts

When I tried to support IPv6 easily with Docker-proxy, I couldn't do it before I knew it.
When I tried to use a Wacom tablet with ubuntu 20.04, I didn't recognize it.
roman numerals (I tried to simplify it with hash)
When I tried to run Azure Kinect DK with Docker, it was blocked by EULA
I tried to summarize iOS 14 support
I tried to interact with Java
When I try to sign up with devise, it automatically redirects to root_path
I tried to get started with WebAssembly
I tried to implement ModanShogi with Kinx
When I tried to start GlassFish, I got an internal error while "Publishing to GlassFish 4.0 on localhost ...". What to do when it becomes
[JavaScript] The strongest case when I tried to summarize the parts I do not understand
What to do when is invalid because it does not start with a'-'
I tried to verify AdoptOpenJDK 11 (11.0.2) with Docker image
I tried to make Basic authentication with Java
I tried to manage struts configuration with Coggle
I tried to manage login information with JMX
I tried to break a block with java (1)
I tried to summarize the points to consider when acquiring location information with the iOS application ③
[Beginner's point of view] I tried to solve the FizzBuzz problem "easily" with Ruby!
I called YouTube video from DB with haml and tried to embed and display it
I tried to summarize the points to consider when acquiring location information with the iOS application ①
When I tried to unit test with IntelliJ, I was told "java.lang.OutOfMemoryError: Java heap space"
I tried to summarize the points to consider when acquiring location information with the iOS application ②
I tried to investigate the mechanism of Emscripten by using it with the Sudoku solver
I tried what I wanted to try with Stream softly.
I tried to implement file upload with Spring MVC
Things to check when it doesn't work with proguard
I tried to read and output CSV with Outsystems
I tried to implement TCP / IP + BIO with JAVA
[Java 11] I tried to execute Java without compiling with javac
I started MySQL 5.7 with docker-compose and tried to connect
I tried to get started with Spring Data JPA
I tried to draw animation with Blazor + canvas API
I tried to implement Stalin sort with Java Collector
Error ExecJS :: RuntimeUnavailable: What to do when it occurs
When I tried to scroll automatically with JScrollBar, the event handler was drawn only once.
[It takes 3 minutes] When I tried to install VS Code on Ubuntu 18.04, it was unexpectedly easy.
Bluemix Infrastructure VPN does not connect because it does not support NPAPI! What to do when [Mac]