Docker Swarm上的NGINX可在同一端口上服务多个应用程序

时间:2019-03-17 11:19:01

标签: docker nginx port reverse-proxy docker-swarm

我知道有人问过类似的问题,但是我发现的所有主题,文章和博客都无法解决我的问题。让我在这里非常简单明了:

1。我拥有的

Docker Swarm集群(1个本地节点),NGINX作为反向代理,在此示例中:apache,spark,rstudio和jupyter笔记本容器。

2。我想要的是:

我想要设置NGINX,使其只能向主机公开一个端口(80-NGINX),并通过NGINX在同一端口(80)但路径不同的情况下为这4个应用程序提供服务。在我的本地开发环境中,我希望apache在“ 127.0.0.1/apache”上可用,在rstudio在“ 127.0.0.1/rstudio”下,在spark UI在“ 127.0.0.1/spark”下,并且jupyter在“ 127.0.0.1/jupyter”下。所有这些应用程序内部都使用不同的端口,这不是问题(apache-80,spark-8080,rstudio-8787,jupyter-8888)。我希望他们在主机上从外部使用相同的端口。

3。我没有的东西:

我没有,也没有域名。当我所拥有的只是一个或多个我拥有的服务器的公共IP时,我的堆栈应该可以工作。没有域名。我看到了多个有关如何使用主机名执行操作的示例,但我不希望这样做。我只想按IP和路径访问堆栈,例如123.123.123.123/jupyter。

4。我想出了什么:

现在要解决我的实际问题-我有一个部分可行的解决方案。 具体来说,apache和rstudio可以正常工作,jupyter和spark不能正常工作。我不是说jupyter重定向正在引起问题。当我转到127.0.0.1/jupyter时,我被重定向到登录页面,但没有重定向到127.0.0.1/jupyter/tree,而是将我重定向到127.0.0.1/tree,这当然不存在。 Spark UI无法正确呈现,因为所有的css和js文件都位于127.0.0.1/spark/some.css之内,但是spark UI试图从127.0.0.1/some.css中获取它们,并且相同的故事基本上与其他所有内容相同仪表板

在我的实际堆栈中,我有更多的服务,例如色相,kafdrop等,但它们都不起作用。实际上,唯一起作用的是apache,tomcat和rstudio。 我很惊讶rstudio可以正常工作,没有身份验证,登录,注销等问题。完全可以。当其他所有方法都失败时,我实际上不知道它为什么起作用。

我尝试对Traefik做同样的事情-同样的结果。使用traefik,我什至无法设置rstudio,所有仪表板都遇到相同的问题-无法正确加载静态内容,或者仪表板具有登录页面-重定向错误。

5。问题:

所以我的问题是:

  • 我尝试完成的事情是否有可能?
  • 如果没有,为什么使用不同的主机名可以实现,但是同一主机上的不同路径不起作用?
  • 如果可能的话,我应该如何设置NGINX以使其正常工作?

我的最小工作示例如下: 首先初始化群组并创建网络:

docker swarm init


docker network create -d overlay --attachable bigdata-net

docker-compose.yml

version: '3'

services:
    nginx:
        image: nginx:alpine
        volumes:
            - ./nginx.conf:/etc/nginx/nginx.conf:ro
        ports:
            - 80:80
            - 443:443
        networks:
            - bigdata-net
        deploy:
            mode: replicated
            replicas: 1
            restart_policy:
                condition: any

    apache:
        image: httpd:alpine
        networks:
            - bigdata-net
        deploy:
            mode: replicated
            replicas: 1
            restart_policy:
                condition: any

    rstudio:
        image: rocker/rstudio:3.5.2
        networks:
            - bigdata-net
        environment:
            - PASSWORD=admin
        deploy:
            mode: replicated
            replicas: 1
            restart_policy:
                condition: any

    jupyter:
        image: jupyter/all-spark-notebook:latest
        networks:
            - bigdata-net
        deploy:
            mode: replicated
            replicas: 1
            restart_policy:
                condition: any

    spark:
        image: bde2020/spark-master:2.2.1-hadoop2.7
        networks:
            - bigdata-net
        deploy:
            mode: replicated
            replicas: 1
            restart_policy:
                condition: on-failure

nginx.conf

worker_processes auto;

events {
    worker_connections 1024; 
}

http {

    log_format compression '$remote_addr - $remote_user [$time_local] '
        '"$request" $status $upstream_addr '
        '"$http_referer" "$http_user_agent" "$gzip_ratio"';

    server {
        listen 80;
        listen [::]:80;
        access_log /var/log/nginx/access.log compression;

        ######### APACHE
        location = /apache { # without this only URL with tailing slash would work
            return 301 /apache/;
        }

        location /apache/ {
            set $upstream_endpoint apache:80;
            resolver 127.0.0.11 valid=5s;
            rewrite ^/apache(/.*) $1 break;
            proxy_pass $scheme://$upstream_endpoint;
            proxy_redirect $scheme://$upstream_endpoint/ $scheme://$host/apache/;
        }

        ######### RSTUDIO
        location = /rstudio { # without this only URL with tailing slash would work
            return 301 /rstudio/;
        }

        location /rstudio/ {
            set $upstream_endpoint rstudio:8787;
            resolver 127.0.0.11 valid=5s;
            rewrite ^/rstudio(/.*) $1 break;
            proxy_pass $scheme://$upstream_endpoint;
            proxy_redirect $scheme://$upstream_endpoint/ $scheme://$host/rstudio/;
        }

        ######### JUPYTER
        location = /jupyter { # without this only URL with tailing slash would work
            return 301 /jupyter/;
        }

        location /jupyter/ {
            set $upstream_endpoint jupyter:8888;
            resolver 127.0.0.11 valid=5s;
            rewrite ^/jupyter(/.*) $1 break;
            proxy_pass $scheme://$upstream_endpoint;
            proxy_redirect $scheme://$upstream_endpoint/ $scheme://$host/jupyter/;
        }

        ######### SPARK
        location = /spark { # without this only URL with tailing slash would work
            return 301 /spark/;
        }

        location /spark/ {
            set $upstream_endpoint spark:8080;
            resolver 127.0.0.11 valid=5s;
            rewrite ^/spark(/.*) $1 break;
            proxy_pass $scheme://$upstream_endpoint;
            proxy_redirect $scheme://$upstream_endpoint/ $scheme://$host/spark/;
        }
    }
}

此外,我创建和修改此配置所基于的材料: https://medium.com/@joatmon08/using-containers-to-learn-nginx-reverse-proxy-6be8ac75a757 https://community.rstudio.com/t/running-shinyapps-from-rstudio-server-behind-nginx-proxy/17706/4

我希望有人可以帮助我,因为我无法解决此问题,所以我睡不着电;)

1 个答案:

答案 0 :(得分:1)

我无法帮助Jupyter和Spark,但希望这个答案对您有所帮助。

如果您打算将某些东西放在反向代理后面,则应验证它是否可以在反向代理后面起作用,如您所述。

  

127.0.0.1/jupyter/tree,它将我重定向到127.0.0.1/tree

因为Jupyter的根是/,而不是/jupyter,所以您需要在config中找到如何更改它,以Grafana为例。

# The full public facing url you use in browser, used for redirects and emails
# If you use reverse proxy and sub path specify full url (with sub path)
root_url = https://example.com/grafana

NGINX的配置可以简化,请看以下示例:

nginx配置

# /etc/nginx/conf.d/default.conf

server {
    listen 80 default_server;

    location = /echo1 {
        rewrite ^ /echo1/ permanent;
    }

    location = /echo2 {
        rewrite ^ /echo2/ permanent;
    }

    location /echo1/ {
        proxy_pass        http://echo1:8000/;
    }

    location /echo2/ {
        proxy_pass        http://echo2:8000/;
    }

    location / {
        return 404;
    }
}

docker-compose

version: "3.2"

services:
    nginx:
        image: ddmitrii/nginx-sample:echo2
        ports:
            - '80:80'
    echo1:
        image: ddmitrii/echo
        command: --url --id echo1

    echo2:
        image: ddmitrii/echo
        command: --url --id echo2

测试

$ curl -L localhost/echo1/
echo1   GET /
$ curl -L localhost/echo2
echo2   GET /

备注

变量

proxy_set_header  Host              $http_host;
proxy_set_header  X-Real-IP         $remote_addr;
proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;
proxy_set_header  X-Forwarded-Proto $scheme;

仅在软要求时才应放置在适当的位置,并且这些名称(如X-Real-IP可以不同,您需要根据软要求进行验证。

您不需要

  

重写^ / rstudio(/.*)$ 1休息;

由于nginx自动遵循正确的规则,因此您需要重写/path之类的路径的规则,以切断path,因此它将是/(或其他)

  

解析器127.0.0.11 valid = 5s;

因为您使用本地主机

  

设置$ upstream_endpoint jupyter:8888;

因为proxy_pass。

  

proxy_redirect $ scheme:// $ upstream_endpoint / $ scheme:// $ host / jupyter /;

因为proxy_pass。

其他一切看起来不错。