Ver Fonte

Merge pull request #2222 from rot169/support-hostnet-containers

Support containers running --net=host (#1537)
Nicolas Duchon há 2 anos atrás
pai
commit
c1a2b31f35

+ 6 - 0
README.md

@@ -182,6 +182,12 @@ docker network connect my-other-network my-nginx-proxy
 
 In this example, the `my-nginx-proxy` container will be connected to `my-network` and `my-other-network` and will be able to proxy to other containers attached to those networks.
 
+### Host networking
+
+`nginx-proxy` is compatible with containers using Docker's [host networking](https://docs.docker.com/network/host/), both with the proxy connected to one or more [bridge network](https://docs.docker.com/network/bridge/) (default or user created) or running in host network mode itself.
+
+Proxyed containers running in host network mode **must** use the [`VIRTUAL_PORT](#virtual-ports) environment variable, as this is the only way for `nginx-proxy` to get the correct port (or a port at all) for those containers.
+
 ### Custom external HTTP/HTTPS ports
 
 If you want to use `nginx-proxy` with different external ports that the default ones of `80` for `HTTP` traffic and `443` for `HTTPS` traffic, you'll have to use the environment variable(s) `HTTP_PORT` and/or `HTTPS_PORT` in addition to the changes to the Docker port mapping. If you change the `HTTPS` port, the redirect for `HTTPS` traffic will also be configured to redirect to the custom port. Typical usage, here with the custom ports `1080` and `10443`:

+ 18 - 0
nginx.tmpl

@@ -67,6 +67,24 @@
     #         {{ .Name }} (ignored)
             {{- continue }}
         {{- end }}
+        {{- if eq .Name "host" }}
+            {{- /* Handle containers in host nework mode */}}
+            {{- if (index $.globals.networks "host") }}
+    #         both container and proxy are in host network mode, using localhost IP
+                {{- $ip = "127.0.0.1" }}
+                {{- continue }}
+            {{- end }}
+            {{- range sortObjectsByKeysAsc $.globals.CurrentContainer.Networks "Name" }}
+                {{- if and . .Gateway }}
+    #         container is in host network mode, using {{ .Name }} gateway IP
+                    {{- $ip = .Gateway }}
+                    {{- break }}
+                {{- end }}
+            {{- end }}
+            {{- if $ip }}
+                {{- continue }}
+            {{- end }}
+        {{- end }}
         {{- if and (not (index $.globals.networks .Name)) (not $.globals.networks.host) }}
     #         {{ .Name }} (unreachable)
             {{- continue }}

+ 8 - 0
test/conftest.py

@@ -160,6 +160,10 @@ def container_ip(container: Container):
         net_info = container.attrs["NetworkSettings"]["Networks"]
         if "bridge" in net_info:
             return net_info["bridge"]["IPAddress"]
+        
+        # container is running in host network mode
+        if "host" in net_info:
+            return "127.0.0.1"
 
         # not default bridge network, fallback on first network defined
         network_name = list(net_info.keys())[0]
@@ -173,6 +177,10 @@ def container_ipv6(container):
     net_info = container.attrs["NetworkSettings"]["Networks"]
     if "bridge" in net_info:
         return net_info["bridge"]["GlobalIPv6Address"]
+    
+    # container is running in host network mode
+    if "host" in net_info:
+        return "::1"
 
     # not default bridge network, fallback on first network defined
     network_name = list(net_info.keys())[0]

+ 13 - 0
test/test_host-network-mode/test_host-network-mode.py

@@ -0,0 +1,13 @@
+import pytest
+
+
+def test_forwards_to_bridge_network_container(docker_compose, nginxproxy):
+    r = nginxproxy.get("http://bridge-network.nginx-proxy.tld/port")
+    assert r.status_code == 200   
+    assert r.text == "answer from port 80\n"
+
+
+def test_forwards_to_host_network_container(docker_compose, nginxproxy):
+    r = nginxproxy.get("http://host-network.nginx-proxy.tld/port")
+    assert r.status_code == 200
+    assert r.text == "answer from port 8080\n" 

+ 31 - 0
test/test_host-network-mode/test_host-network-mode.yml

@@ -0,0 +1,31 @@
+version: "2"
+
+networks:
+  net1:
+    internal: true
+  net2:
+
+services:
+  bridge-network:
+    image: web
+    environment:
+      WEB_PORTS: "80"
+      VIRTUAL_HOST: "bridge-network.nginx-proxy.tld"
+    networks:
+      - net2
+
+  host-network:
+    image: web
+    environment:
+      WEB_PORTS: "8080"
+      VIRTUAL_HOST: "host-network.nginx-proxy.tld"
+      VIRTUAL_PORT: "8080"
+    network_mode: host
+
+  sut:
+    image: nginxproxy/nginx-proxy:test
+    volumes:
+      - /var/run/docker.sock:/tmp/docker.sock:ro
+    networks:
+      - net1
+      - net2

+ 13 - 0
test/test_host-network-mode/test_proxy-host-network-mode.py

@@ -0,0 +1,13 @@
+import pytest
+
+
+def test_forwards_to_host_network_container_1(docker_compose, nginxproxy):
+    r = nginxproxy.get("http://host-network-1.nginx-proxy.tld:8888/port")
+    assert r.status_code == 200
+    assert r.text == "answer from port 8080\n"
+
+
+def test_forwards_to_host_network_container_2(docker_compose, nginxproxy):
+    r = nginxproxy.get("http://host-network-2.nginx-proxy.tld:8888/port")
+    assert r.status_code == 200
+    assert r.text == "answer from port 8181\n"

+ 26 - 0
test/test_host-network-mode/test_proxy-host-network-mode.yml

@@ -0,0 +1,26 @@
+version: "2"
+
+services:
+  host-network-1:
+    image: web
+    environment:
+      WEB_PORTS: "8080"
+      VIRTUAL_HOST: "host-network-1.nginx-proxy.tld"
+      VIRTUAL_PORT: "8080"
+    network_mode: host
+
+  host-network-2:
+    image: web
+    environment:
+      WEB_PORTS: "8181"
+      VIRTUAL_HOST: "host-network-2.nginx-proxy.tld"
+      VIRTUAL_PORT: "8181"
+    network_mode: host
+
+  sut:
+    image: nginxproxy/nginx-proxy:test
+    volumes:
+      - /var/run/docker.sock:/tmp/docker.sock:ro
+    environment:
+      HTTP_PORT: 8888
+    network_mode: host