在 Docker 主机上使用浏览器

在 Docker 主机上使用浏览器

我在 SUSE Linux Enterprise Server 12 SP1 中使用 Docker 时遇到了一个奇怪的情况。

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

docker run -d -p 8081:80 nginx:alpine --name nginxtest

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

<!-- [...] -->
<title>Welcome to nginx!</title>
<!-- [...] -->

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

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

Serving HTTP on 0.0.0.0 port 8000 ...

当我从计算机上的浏览器访问它时,它就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)
  • brctl show docker0
bridge name     bridge id               STP enabled     interfaces
docker0         8000.0249143a607f       no              veth0e4b1f4
                                                        veth1f2fcc2
                                                        veth389f6fe
                                                        [[others]]
  • 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
  • (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
  • 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
  • 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
  • docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
20c691cc38e6        bridge              bridge              local
cd95c7d14c38        host                host                local
eb6d8228f366        none                null                local
  • 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": {}
    }
]
  • 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
  • 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

答案1

在这里,我们的 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

配置防火墙

假设您想要向 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

请注意,如果您重新启动系统或以某种方式重置防火墙,这些 iptables 规则将不会保留。对 Wicked 不太熟悉。

相关内容