docker - 使用 Dockerized NGINX 反向代理到 Dockerized REST API
问题描述
请看底部的后续
我是 NGINX 的新手,正在尝试为多个 REST API 和 SPA 应用程序入口点设置一个简单的内部开发 Ubuntu 服务器,因此我可以学习一些 NGINX 基础知识。
我想要服务的所有 API 和 SPA 都是 dockerized,并且每个都在 localhost(Docker 的主机)端口上公开其服务(用于 API)或页面(用于 SPA)。
例如,我有一个 APIlocalhost:60380
和一个 Angular SPA 应用程序localhost:4200
,每个都在自己的 Docker 容器中运行。
我可以确认这些工作正常,因为我可以通过它们基于 localhost 的 URL 访问它们。每个 API 还在其 URL 上提供了一个Swagger入口点,例如localhost:60380/swagger
(或者,更详细地说,localhost:60380/swagger/index.html
)。
我现在想让 NGINX 监听localhost:80
,并根据请求的 URL 对每个相应的服务进行反向代理请求。为了保持干净,NGINX 也是 dockerized,即从使用 NGINX 开源版本的容器运行。
为了对 NGINX 进行 dockerize,我按照https://docs.nginx.com/nginx/admin-guide/installing-nginx/installing-nginx-docker/的说明进行操作,即我从nginx
映像运行容器,使用卷指向主机的NGINX 配置和静态内容的文件夹。/
我刚刚更改了 Docker 命令,因为我在使用文档中建议的基于挂载的语法时遇到了问题(即使我指定了选项,这似乎不是一个允许的字符bind
;请注意以下命令是从 执行的/var
):
docker run --name mynginx -v $(pwd)/www:/usr/share/nginx/html:ro -v $(pwd)/nginx/conf:/etc/nginx/conf:ro -p 80:80 -d nginx
IE:
- 主机
/var/www
=> 容器/usr/share/nginx/html
; - 主机
/var/nginx/conf
=>/etc/nginx
。
作为测试,我在映射为卷源的主机文件夹中创建了几个静态网站,即:
/var/www/site1
/var/www/site2
这两个文件夹都只有一个静态网页 ( index.html
)。
我在主机的/var/nginx/conf
文件夹中放置了一个nginx.conf
文件来为这两个静态网站提供服务。这是我想出的配置:
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
# include imports configuration from a separate file.
# In this case it imports a types block, mapping each MIME type
# to a file extension, e.g.:
# types {
# text/html html htm shtml;
# text/css css;
# application/javascript js;
# ... etc
# }
include /etc/nginx/mime.types;
# the default type used if no mapping is found in types:
# here the browser will just download the file.
default_type application/octet-stream;
# log's format: the 1st parameter is the format's name (main);
# the second is a series of variables with different values
# for every request.
log_format main
'$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
# path to the log file and log format's name (main, defined above).
access_log /var/log/nginx/access.log main;
# set to on: do not block on disk I/O.
sendfile on;
# keep connection alive timeout. As a page usually has a lot of assets,
# this keeps the connection alive the time required to send them;
# otherwise, a new connection would be created for each asset.
keepalive_timeout 65;
# enable output compression. Recommendation is on.
gzip on;
# include all the .conf files under this folder:
include /etc/nginx/conf.d/*.conf;
}
server {
listen 80;
server_name localhost;
location /site1 {
root /usr/share/nginx/html/site1;
index index.html index.htm;
}
location /site2 {
root /usr/share/nginx/html/site2;
index index.html index.htm;
}
# redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
这很好用,我可以从localhost/site1
和浏览这两个站点localhost/site2
。
然后我开始了我的一个 dockerized API 暴露在localhost:60380
. 我在 NGINX 配置中,在同一个服务器块中添加了以下内容,以便在(及其在 处大摇大摆)location
到达它:localhost/sample/api
localhost/sample/api/swagger
location /sample/api {
proxy_pass_header Server;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://localhost:60380;
}
由于这是一个 ASP.NET Core Web API,我使用https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/linux-nginx?view建议的配置作为起点=aspnetcore-3.1。除了一些标头传递方向之外,这与在如何使用 nginx 在 Docker 容器上为 Web 应用程序提供服务中找到的并没有本质上的不同。
然后我将 NGINX 配置保存在主机文件夹中,并通知 NGINX 用docker kill -s HUP <mycontainername>
.
无论如何,虽然我仍然能够访问 API localhost:60380
,并且两个静态 Web 仍然可以工作,但在访问localhost/sample/api
或时我得到了 404 localhost/sample/api/swagger
。
我尝试按照此处proxy_redirect http://localhost:60380/ /sample/api/;
的建议添加,但没有任何变化。
你能建议我做错了什么吗?
更新 1
我尝试将尾随添加/
到 URI,但我仍然得到 404。如果这适用于 Kaustubh(请参阅下面的答案),这让我感到困惑,因为我仍在 404;或者我们做了一些不同的事情。让我也回顾一下,以帮助像我这样的其他没有经验的读者:
- 准备主机:
cd /var
mkdir nginx
cd nginx
mkdir conf
cd ..
mkdir www
cd www
mkdir site1
cd ..
mkdir site2
cd ..
然后index.html
在每个文件夹中添加一个页面/var/www/site1
,然后在/var/www/site2
下面添加一个页面:nginx.conf
var/nginx/conf
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
# include imports configuration from a separate file.
# In this case it imports a types block, mapping each MIME type
# to a file extension, e.g.:
# types {
# text/html html htm shtml;
# text/css css;
# application/javascript js;
# ... etc
# }
include /etc/nginx/mime.types;
# the default type used if no mapping is found in types:
# here the browser will just download the file.
default_type application/octet-stream;
# log's format: the 1st parameter is the format's name (main);
# the second is a series of variables with different values
# for every request.
log_format main
'$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
# path to the log file and log format's name (main, defined above).
access_log /var/log/nginx/access.log main;
# set to on: do not block on disk I/O.
sendfile on;
# keep connection alive timeout. As a page usually has a lot of assets,
# this keeps the connection alive the time required to send them;
# otherwise, a new connection would be created for each asset.
keepalive_timeout 65;
# enable output compression. Recommendation is on.
gzip on;
# include all the .conf files under this folder:
include /etc/nginx/conf.d/*.conf;
}
server {
listen 80;
server_name localhost;
location /site1 {
root /usr/share/nginx/html/site1;
index index.html index.htm;
}
location /site2 {
root /usr/share/nginx/html/site2;
index index.html index.htm;
}
# https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/linux-nginx?view=aspnetcore-3.1
# https://stackoverflow.com/questions/57965728/how-to-use-nginx-to-serve-a-web-app-on-a-docker-container
# https://serverfault.com/questions/801725/nginx-config-for-restful-api-behind-proxy
location /sample/api {
# proxy_redirect http://localhost:60380/ /sample/api/;
proxy_pass_header Server;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://localhost:60380/;
}
# redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
docker run --name mynginx -v $(pwd)/www:/usr/share/nginx/html:ro -v $(pwd)/nginx/conf:/etc/nginx/conf:ro -p 80:80 -d --net=host nginx
(注意添加--net=host
)导航到
localhost/site1
andlocalhost/site2
:这行得通。启动您的 API
localhost:60380
(这是我的示例中的 API 端口)。我可以看到它在工作localhost:60380
,它的招摇页面在localhost:60380/swagger
.导航到
localhost/sample/api
:404。对于localhost/sample/api/swagger/index.html
具有此前缀的任何其他 URI 或其他 URI 相同。
解决方案
我试图在我的最后尽可能地复制这一点。--net=host
只有在我在docker run
nginx 的命令中使用后,我才能让它工作。下面是我使用的命令。我不得不使用这个选项,因为 nginx docker 容器无法连接到我的 api docker 容器
$ docker run --name nginx -v $(pwd):/usr/share/nginx/html:ro -v $(pwd)/default.conf:/etc/nginx/conf.d/default.conf:ro -p 80:80 --net=host -id nginx
/etc/nginx/conf.d/default.conf
是 nginx 中的默认虚拟主机配置,显示Welcome to nginx page
.
我将其更改为以下配置:
server {
listen 80;
server_name localhost;
# For static files
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
# For reverse_proxy
location /sample/api {
proxy_pass http://localhost:8080/;
}
}
根据这个答案,端口号后面的斜杠应该解决这个问题。
我已经测试了相同的结果并且它有效。
推荐阅读
- android - Gradle 构建在启用与多模块的数据绑定时失败
- asp.net - 过滤下拉列表选项服务器端 asp.net
- python - 拆分多个(嵌套)python 子正则表达式定义
- python - Visual Studio Code 快速修复 & python
- javascript - 通过另一个数据属性作为标识符获取元素的数据属性
- python-3.x - matplotlib 动画在循环执行的文件更新中不起作用
- python - 将自定义生成器添加到 spaCy 的类
- android - 授予位置权限时,Android O 设备中的“位置方法”不会更改
- ag-grid - rowNode.setDataValue 方法的性能
- asp.net - 检查对 SOAP/REST Web 服务的访问而不调用它