Docker 端口似乎无法从外部服务器访问

Ped*_*o A 9 networking sles linux-networking docker sles12

我在 SUSE Linux Enterprise Server 12 SP1 中遇到了 Docker 的奇怪情况。

我使用 SSH 连接到服务器。首先,我尝试运行一个简单的 nginx 服务器来测试:

docker run -d -p 8081:80 nginx:alpine --name nginxtest
Run Code Online (Sandbox Code Playgroud)

容器启动成功。然后,跑步curl http://localhost:8081就可以了!

<!-- [...] -->
<title>Welcome to nginx!</title>
<!-- [...] -->
Run Code Online (Sandbox Code Playgroud)

但是,当我尝试从我的计算机上的浏览器访问它时,http://10.etc.etc.etc:8081请求超时。

但令人惊讶的是,如果我暂时忘记 docker,并直接从服务器使用简单的 HTTP 服务器,例如python3 -m http.server,我会得到:

Serving HTTP on 0.0.0.0 port 8000 ...
Run Code Online (Sandbox Code Playgroud)

当我从计算机上的浏览器访问它时,http://10.etc.etc.etc:8000它就可以工作了!

所以这一定是关于 docker 如何公开其端口的,但这很奇怪,因为它curl http://localhost:8081有效......

我该如何进一步排除故障并解决此问题?

注意:直到昨天我跑步时一切都运行良好systemctl restart wicked(我试图调查另一个不相关的问题)。我也尝试重新启动服务器,但没有帮助。


这是一些可能相关的更多输出......

  • ifconfig docker0
docker0   Link encap:Ethernet  HWaddr 02:49:68:4D:40:9B
          inet addr:172.17.0.1  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:8e6e:ee3f:6918/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:353842611 errors:0 dropped:0 overruns:0 frame:0
          TX packets:450340200 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:509803756314 (486186.7 Mb)  TX bytes:497391388709 (474349.3 Mb)
Run Code Online (Sandbox Code Playgroud)
  • brctl show docker0
bridge name     bridge id               STP enabled     interfaces
docker0         8000.0249143a607f       no              veth0e4b1f4
                                                        veth1f2fcc2
                                                        veth389f6fe
                                                        [[others]]
Run Code Online (Sandbox Code Playgroud)
  • docker ps | grep nginx0.0.0.0:8081->80/tcp

  • cat /etc/sysctl.conf

# net.ipv6.conf.all.disable_ipv6 = 1
# net.ipv6.conf.all.disable_ipv6 = 1
net.ipv4.ip_forward = 0
net.ipv6.conf.all.forwarding = 0
Run Code Online (Sandbox Code Playgroud)
  • (netstat -ltunp | head -2) && (netstat -ltunp | grep docker)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 :::9000                 :::*                    LISTEN      28216/docker-proxy
tcp        0      0 :::5000                 :::*                    LISTEN      28165/docker-proxy
tcp        0      0 :::8081                 :::*                    LISTEN      30341/docker-proxy
Run Code Online (Sandbox Code Playgroud)
  • iptables -n --list
Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination
DOCKER-ISOLATION  all  --  0.0.0.0/0            0.0.0.0/0
DOCKER     all  --  0.0.0.0/0            0.0.0.0/0
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Chain DOCKER (1 references)
target     prot opt source               destination
ACCEPT     tcp  --  0.0.0.0/0            172.17.0.11          tcp dpt:5000
ACCEPT     tcp  --  0.0.0.0/0            172.17.0.13          tcp dpt:9000
ACCEPT     tcp  --  0.0.0.0/0            172.17.0.2           tcp dpt:80

Chain DOCKER-ISOLATION (1 references)
target     prot opt source               destination
RETURN     all  --  0.0.0.0/0            0.0.0.0/0
Run Code Online (Sandbox Code Playgroud)
  • iptables -nt nat -L
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
DOCKER     all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
DOCKER     all  --  0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0
MASQUERADE  tcp  --  172.17.0.11          172.17.0.11          tcp dpt:5000
MASQUERADE  tcp  --  172.17.0.13          172.17.0.13          tcp dpt:9000
MASQUERADE  tcp  --  172.17.0.2           172.17.0.2           tcp dpt:80

Chain DOCKER (2 references)
target     prot opt source               destination
RETURN     all  --  0.0.0.0/0            0.0.0.0/0
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:5000 to:172.17.0.11:5000
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:9000 to:172.17.0.13:9000
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:8081 to:172.17.0.2:80
Run Code Online (Sandbox Code Playgroud)
  • docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
20c691cc38e6        bridge              bridge              local
cd95c7d14c38        host                host                local
eb6d8228f366        none                null                local
Run Code Online (Sandbox Code Playgroud)
  • docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "20c691cc38e65be9bf0a377fd8560d49430f523608094b68145e8769e24b1764",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Containers": {
            "26887c686d3c8612e460b923692f371bef881065a525496dff9af993ed4b7949": {
                "Name": "sleepy_fermi",
                "EndpointID": "3e79d8c15423b2e145a900e796d316159d2dc51dcc10ced2099b77d1111b03e7",
                "MacAddress": "02:49:68:4D:40:9B",
                "IPv4Address": "172.17.0.6/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]
Run Code Online (Sandbox Code Playgroud)
  • iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-N DOCKER
-N DOCKER-ISOLATION
-A FORWARD -j DOCKER-ISOLATION
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A DOCKER -d 172.17.0.11/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 5000 -j ACCEPT
-A DOCKER -d 172.17.0.13/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 9000 -j ACCEPT
-A DOCKER -d 172.17.0.2/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 80 -j ACCEPT
-A DOCKER-ISOLATION -j RETURN
Run Code Online (Sandbox Code Playgroud)
  • docker version
Client:
 Version:      1.12.6
 API version:  1.24
 Go version:   go1.6.2
 Git commit:   78d1802
 Built:        Thu Mar  2 12:26:00 2017
 OS/Arch:      linux/amd64

Server:
 Version:      1.12.6
 API version:  1.24
 Go version:   go1.6.2
 Git commit:   78d1802
 Built:        Thu Mar  2 12:26:00 2017
 OS/Arch:      linux/amd64
Run Code Online (Sandbox Code Playgroud)

SYN*_*SYN 4

在这里,我们的 Docker 容器可以通过 docker0 访问(网络:172.17.xx)

您正在尝试从浏览器连接到某个 10.xxx 地址。

在 Docker 主机上使用浏览器

假设您只想从浏览器连接到本地托管的容器,那么更简单的方法就是访问您的容器地址 (172.17.xx)。

在某些情况下,您甚至可以ssh -X连接到 Docker 主机,然后启动 Web 浏览器,而无需将它们暴露在 LAN 中。

使用 HTTP 代理

假设您想向 LAN 上的客户端公开 http/https 服务,那么您可以使用一些反向代理(nginx、traefik、apache,...)。

dnf install httpd
setsebool -P httpd_can_network_connect on
cat <<EOF >/etc/httpd/conf.d/welcome.conf
<VirtualHost *:80>
    ServerName my-application.example.com
    LogLevel debug
    ErrorLog logs/tunnel_error.log
    CustomLog logs/tunnel_access.log combined
    <Location />
        Require all granted
    </Location>
    ProxyPass / http://<container-address>:8080/
    ProxyPassReverse / http://<container-address>:8080/
</VirtualHost>
EOF
systemctl enable httpd
systemctl start httpd
Run Code Online (Sandbox Code Playgroud)

配置防火墙

假设您想向 LAN 上的客户端公开 tcp/udp 服务,您可以相应地设置防火墙:

sysctl -w net.ipv4.conf.all.forwarding=1
echo net.ipv4.conf.all.forwarding=1 >>/etc/sysctl.conf
iptables -A FORWARD -i docker0 -o eth0 -j ACCEPT
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
iptables -t nat -A PREROUTING -p tcp -d <my-eth0-address> --dport 8080 -j DNAT --to <my-container-address>:8080
Run Code Online (Sandbox Code Playgroud)

请注意,如果您重新启动系统或以某种方式重置防火墙,这些 iptables 规则将不会持续存在。对《恶人》不太熟悉。