如何在Docker自定义桥接网络中访问端口

3
新的Docker文档称,您仍然可以在默认的桥接网络中使用--link,但创建自己的桥接网络更加安全。然后它说,在自定义的桥接网络中,您不能再使用--link来映射端口。
因此,我想创建一个安全隔离的自定义桥接网络,可以互相通信的端口。
例如,我有一个nginx容器在桥接网络中,但也是私有网络的一部分,其中包含一个angular应用程序。如何从nginx代理调用到指定端口(例如端口8080)上的angular容器,而不会将angular端口全局公开?
更新:
我知道如何在同一网络中创建容器,然后使用其容器名称相互连接,使用ping。我不明白的是如何访问另一个容器的端口。例如,如果web2和nginx都在同一网络中,我可以从nginx ping web2,但如果我从nginx运行curl web2:4200,则会收到“无法连接到web2端口4200:连接被拒绝”的消息。如何打开端口4200而不将端口4200暴露给外部世界?
nginx配置文件
upstream web {
    server web2:4200;
}

upstream api {
    server api:3000;
}



server {
    listen       80;
    server_name  url.com;

    location /api {
        proxy_pass http://api;
    }

    location / {
        proxy_pass http://web;
    }
}

Web 2.0网络设置

 "NetworkSettings": {
        "Bridge": "",
        "SandboxID": "f290157dd8f9b181bd544ee0b9814b1581adf61cee05c07e67a93df6bf85ecd3",
        "HairpinMode": false,
        "LinkLocalIPv6Address": "",
        "LinkLocalIPv6PrefixLen": 0,
        "Ports": {},
        "SandboxKey": "/var/run/docker/netns/f290157dd8f9",
        "SecondaryIPAddresses": null,
        "SecondaryIPv6Addresses": null,
        "EndpointID": "",
        "Gateway": "",
        "GlobalIPv6Address": "",
        "GlobalIPv6PrefixLen": 0,
        "IPAddress": "",
        "IPPrefixLen": 0,
        "IPv6Gateway": "",
        "MacAddress": "",
        "Networks": {
            "application-network": {
                "EndpointID": "622f0afd4016eafc525b45c32c465c58b89ab543358ba860d31edac8ce877d83",
                "Gateway": "172.19.0.1",
                "IPAddress": "172.19.0.2",
                "IPPrefixLen": 16,
                "IPv6Gateway": "",
                "GlobalIPv6Address": "",
                "GlobalIPv6PrefixLen": 0,
                "MacAddress": "02:42:ac:13:00:02"
            }
        }
    }

nginx网络设置

"NetworkSettings": {
    "Bridge": "",
    "SandboxID": "94f2d21562f6af5334547110893470b3bece02a081620daec98446ecd7b3f14b",
    "HairpinMode": false,
    "LinkLocalIPv6Address": "",
    "LinkLocalIPv6PrefixLen": 0,
    "Ports": {
        "443/tcp": null,
        "80/tcp": null
    },
    "SandboxKey": "/var/run/docker/netns/94f2d21562f6",
    "SecondaryIPAddresses": null,
    "SecondaryIPv6Addresses": null,
    "EndpointID": "cfe8ec49e341aed2dd56bd61d1dff6867ddd0246c5a04ff8cebdeee571475bdb",
    "Gateway": "172.17.0.1",
    "GlobalIPv6Address": "",
    "GlobalIPv6PrefixLen": 0,
    "IPAddress": "172.17.0.3",
    "IPPrefixLen": 16,
    "IPv6Gateway": "",
    "MacAddress": "02:42:ac:11:00:03",
    "Networks": {
        "application-network": {
            "EndpointID": "6242229877c5a29bfae1c0742d558daedf50fbe607b42722449367e5dda79371",
            "Gateway": "172.19.0.1",
            "IPAddress": "172.19.0.3",
            "IPPrefixLen": 16,
            "IPv6Gateway": "",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "MacAddress": "02:42:ac:13:00:03"
        },
        "bridge": {
            "EndpointID": "cfe8ec49e341aed2dd56bd61d1dff6867ddd0246c5a04ff8cebdeee571475bdb",
            "Gateway": "172.17.0.1",
            "IPAddress": "172.17.0.3",
            "IPPrefixLen": 16,
            "IPv6Gateway": "",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "MacAddress": "02:42:ac:11:00:03"
        }
    }
}

我已将此问题移至此处,以更好地隔离问题:docker容器在同一网络中无法访问同一网络中的其他容器

-H 参数仅适用于守护进程,用于指定 API 可访问的 IP 地址。对于官方的 nginx 镜像,无需进行任何配置即可正常使用。以下命令可以实现此功能:docker network create a docker run -d --name=web2 --net=a nginx docker run --rm --net=a ubuntu sh -c "apt-get install -yq curl && curl web2" - thaJeztah
此时,它已超出了Docker配置的范围,并在nginx配置中。nginx是否有像listen 80;这样的行在server指令内? - Andy Shinn
web2是一个基于node的镜像。其中包含有http-server,返回一个简单的index.html文件。 - monty_lennie
@AndyShinn 我在上面写了一条评论,命令是 http-server ./ -p 4200 -a 0.0.0.0 index.html - monty_lennie
您能否发布每张图像使用的图像和配置,以便我可以尝试在本地复制?这应该可以正常工作,而无需暴露任何端口。 - Andy Shinn
显示剩余8条评论
2个回答

3
如果两个容器都连接到同一个网络,它们可以通过名称相互访问。
例如:
  1. Create your own "bridge" network (bridge is the default)

    docker network create mybridge
    
  2. Start a container on this network, and name it containera

    docker run -d --net=mybridge --name=containera nginx
    
  3. Start another container on the same network, and try to "ping" containera

    docker run -it --rm --net=mybridge ubuntu
    
    root@1331cebaa93a:/# ping -w 4 containera
    PING containera (172.20.0.2) 56(84) bytes of data.
    64 bytes from containera.mybridge (172.20.0.2): icmp_seq=1 ttl=64 time=0.087 ms
    64 bytes from containera.mybridge (172.20.0.2): icmp_seq=2 ttl=64 time=0.129 ms
    64 bytes from containera.mybridge (172.20.0.2): icmp_seq=3 ttl=64 time=0.130 ms
    64 bytes from containera.mybridge (172.20.0.2): icmp_seq=4 ttl=64 time=0.130 ms
    
    --- containera ping statistics ---
    4 packets transmitted, 4 received, 0% packet loss, time 3130ms
    rtt min/avg/max/mdev = 0.087/0.119/0.130/0.018 ms
    

在这里阅读更多有关Docker网络的信息:https://docs.docker.com/engine/userguide/networking/dockernetworks/

Docker 1.10中的容器“别名”

目前(docker 1.9.1),只能使用容器的“名称”作为主机来访问容器。然而,docker 1.10将支持添加别名来访问容器,可以是网络范围或容器范围,使用与当前--link相同的语法;--link <container>:<alias>

有关容器别名即将推出的功能的更多信息,请参见此处: https://github.com/docker/docker/blob/master/docs/userguide/networking/work-with-networks.md#linking-containers-in-user-defined-networks


2

在自定义网络中,链接并不是必要的,因为通过 DNS 可以发现自定义网络中的容器(它们的条目被填充到 /etc/hosts 文件中)。以下是一个示例:

创建一个新的网络:

docker network create test

在该网络中启动一个什么都不做的容器:
docker run -d --name sleeper --net test alpine sh -c "while true; do echo $(date); sleep 20; done"

运行另一个带有交互式 shell 的容器,并查看 hosts 文件和与 sleeper 容器的连接:

docker run -i -t --net test alpine sh
/ # cat /etc/hosts
172.18.0.4  cc90db123006
127.0.0.1   localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.18.0.2  test3
172.18.0.2  test3.test
172.18.0.3  sleeper
172.18.0.3  sleeper.test
/ # ping sleeper
PING sleeper (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.103 ms
64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.107 ms
^C
--- sleeper ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.103/0.105/0.107 ms

因此,在这个例子中,sleeper容器类似于您的angular容器。Nginx只需代理到angular及其容器内运行的端口即可,无需进行端口映射。
您使用的端口应该是angular应用程序正在侦听的端口。因此,如果该应用程序在端口80上运行nginx,则只需连接到端口80即可。

哦,哈哈,看起来你比我快,我没有刷新页面。 - thaJeztah
1
哦,注意在Docker 1.10中,/etc/hosts将不再用于发现,因为发现现在是基于DNS的。请参见https://github.com/docker/libnetwork/pull/841和https://github.com/docker/libnetwork/issues/767。 - thaJeztah
2
也许你等待那些大的Ubuntu镜像拉取太慢了 :p - Andy Shinn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接