Docker Swarm 上的 NGINX 在同一端口上为多个应用程序提供服务
NGINX on Docker Swarm to serve multiple applicaions on the same port
我知道有人问过类似的问题,但是 none 我找到的主题、文章和博客让我解决了我的问题。让我在这里非常直接和具体:
1.我有什么:
Docker Swarm 集群(1 个本地节点),NGINX 作为反向代理,为了这个例子:apache、spark、rstudio 和 jupyter notebook 容器。
2。我想要的:
我想将 NGINX 设置为仅向主机公开一个端口 (80 - NGINX),并通过 NGINX 通过同一端口 (80) 但不同的路径为这 4 个应用程序提供服务。在我的本地开发环境中,我希望可以在“127.0.0.1/apache”上访问 apache,在“127.0.0.1/rstudio”下访问 rstudio,在“127.0.0.1/spark”下访问 spark UI,在“127.0.0.1”下访问 jupyter。 0.1/木星”。所有这些应用程序在内部使用不同的端口,这不是问题(apache - 80、spark - 8080、rstudio - 8787、jupyter - 8888)。我希望他们在外部主机上使用相同的端口。
3。我没有的:
我没有也不会拥有域名。当我只有一个 public 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 并且所有其他仪表板基本上都是同样的故事
在我的实际堆栈中,我有更多服务,如 hue、kafdrop 等,其中 none 可用。实际上,唯一有用的是 apache、tomcat 和 rstudio。
我很惊讶 rstudio 在身份验证、登录、退出等方面没有问题。这完全没问题。当其他一切都失败时,我实际上不知道它为什么有效。
我尝试对 Traefik 做同样的事情 - 同样的结果。使用 traefik,我什至无法设置 rstudio,所有仪表板都遇到了同样的问题——没有正确加载静态内容,或者带有登录页面的仪表板——错误的重定向。
5.问题:
所以我的问题是:
- 我正在尝试完成的事情有可能实现吗?
- 如果不是,为什么使用不同的主机名可以实现,但同一主机上的不同路径却不起作用?
- 如果可以,那么我应该如何设置 NGINX 才能正常工作?
我的最小工作示例如下:
首先初始化 swarm 并创建网络:
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(/.*) 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(/.*) 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(/.*) 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(/.*) 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
我希望有人能帮助我,我无法解决这个问题,所以睡不着;)
对于 Jupyter 和 Spark,我帮不上忙,但希望这个回答对您有所帮助。
如果您打算将某些东西放在反向代理后面,您应该验证它是否可以像您提到的那样在反向代理后面工作。
127.0.0.1/jupyter/tree, it redirects me to 127.0.0.1/tree
因为 Jupyter root 是 /
,而不是 /jupyter
,所以你需要在配置中找到如何更改它,以 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 8080 default_server;
location / {
proxy_pass http://echo:8080/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Request $request;
proxy_set_header X-Forwarded-Agent $http_user_agent;
}
location ~ /echo([0-9]+)/ {
rewrite ^/echo([0-9]+)(.*)$ break;
proxy_pass http://echo:8080;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Request $request;
proxy_set_header X-Forwarded-Agent $http_user_agent;
}
}
docker-撰写
version: "3.2"
services:
nginx:
image: nginx:alpine
ports:
- '8080:8080'
volumes:
- ./default.conf:/etc/nginx/conf.d/default.conf
echo:
image: caa06d9c/echo
测试
$ curl -L localhost:8080/echo1/
{
"method": "GET",
"path": "/",
"ip": "172.31.0.1",
"headers": {
"X-Forwarded-Host": "localhost",
"X-Forwarded-Port": "8080",
"X-Forwarded-Proto": "http",
"X-Forwarded-Agent": "curl/7.54.0",
"X-Forwarded-Request": "GET /echo1/ HTTP/1.1"
}
}
备注
变量
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
可以不一样,需要软要求验证。
你不需要
rewrite ^/rstudio(/.*) break;
因为 nginx 自动遵循正确的规则,你需要重写像 /path
这样的路径规则来切断 path
,所以它将是 /
(或其他)
resolver 127.0.0.11 valid=5s;
因为你使用本地主机
set $upstream_endpoint jupyter:8888;
因为 proxy_pass.
proxy_redirect $scheme://$upstream_endpoint/ $scheme://$host/jupyter/;
因为 proxy_pass.
其他一切看起来都不错。
我知道有人问过类似的问题,但是 none 我找到的主题、文章和博客让我解决了我的问题。让我在这里非常直接和具体:
1.我有什么:
Docker Swarm 集群(1 个本地节点),NGINX 作为反向代理,为了这个例子:apache、spark、rstudio 和 jupyter notebook 容器。
2。我想要的:
我想将 NGINX 设置为仅向主机公开一个端口 (80 - NGINX),并通过 NGINX 通过同一端口 (80) 但不同的路径为这 4 个应用程序提供服务。在我的本地开发环境中,我希望可以在“127.0.0.1/apache”上访问 apache,在“127.0.0.1/rstudio”下访问 rstudio,在“127.0.0.1/spark”下访问 spark UI,在“127.0.0.1”下访问 jupyter。 0.1/木星”。所有这些应用程序在内部使用不同的端口,这不是问题(apache - 80、spark - 8080、rstudio - 8787、jupyter - 8888)。我希望他们在外部主机上使用相同的端口。
3。我没有的:
我没有也不会拥有域名。当我只有一个 public 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 并且所有其他仪表板基本上都是同样的故事
在我的实际堆栈中,我有更多服务,如 hue、kafdrop 等,其中 none 可用。实际上,唯一有用的是 apache、tomcat 和 rstudio。 我很惊讶 rstudio 在身份验证、登录、退出等方面没有问题。这完全没问题。当其他一切都失败时,我实际上不知道它为什么有效。
我尝试对 Traefik 做同样的事情 - 同样的结果。使用 traefik,我什至无法设置 rstudio,所有仪表板都遇到了同样的问题——没有正确加载静态内容,或者带有登录页面的仪表板——错误的重定向。
5.问题:
所以我的问题是:
- 我正在尝试完成的事情有可能实现吗?
- 如果不是,为什么使用不同的主机名可以实现,但同一主机上的不同路径却不起作用?
- 如果可以,那么我应该如何设置 NGINX 才能正常工作?
我的最小工作示例如下: 首先初始化 swarm 并创建网络:
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(/.*) 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(/.*) 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(/.*) 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(/.*) 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
我希望有人能帮助我,我无法解决这个问题,所以睡不着;)
对于 Jupyter 和 Spark,我帮不上忙,但希望这个回答对您有所帮助。
如果您打算将某些东西放在反向代理后面,您应该验证它是否可以像您提到的那样在反向代理后面工作。
127.0.0.1/jupyter/tree, it redirects me to 127.0.0.1/tree
因为 Jupyter root 是 /
,而不是 /jupyter
,所以你需要在配置中找到如何更改它,以 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 8080 default_server;
location / {
proxy_pass http://echo:8080/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Request $request;
proxy_set_header X-Forwarded-Agent $http_user_agent;
}
location ~ /echo([0-9]+)/ {
rewrite ^/echo([0-9]+)(.*)$ break;
proxy_pass http://echo:8080;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Request $request;
proxy_set_header X-Forwarded-Agent $http_user_agent;
}
}
docker-撰写
version: "3.2"
services:
nginx:
image: nginx:alpine
ports:
- '8080:8080'
volumes:
- ./default.conf:/etc/nginx/conf.d/default.conf
echo:
image: caa06d9c/echo
测试
$ curl -L localhost:8080/echo1/
{
"method": "GET",
"path": "/",
"ip": "172.31.0.1",
"headers": {
"X-Forwarded-Host": "localhost",
"X-Forwarded-Port": "8080",
"X-Forwarded-Proto": "http",
"X-Forwarded-Agent": "curl/7.54.0",
"X-Forwarded-Request": "GET /echo1/ HTTP/1.1"
}
}
备注
变量
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
可以不一样,需要软要求验证。
你不需要
rewrite ^/rstudio(/.*) break;
因为 nginx 自动遵循正确的规则,你需要重写像 /path
这样的路径规则来切断 path
,所以它将是 /
(或其他)
resolver 127.0.0.11 valid=5s;
因为你使用本地主机
set $upstream_endpoint jupyter:8888;
因为 proxy_pass.
proxy_redirect $scheme://$upstream_endpoint/ $scheme://$host/jupyter/;
因为 proxy_pass.
其他一切看起来都不错。