结合Docker,你将了解到Nginx的核心用法:反向代理+负载均衡
Nginx是一个流行的服务器。一般用于托管静态资源,反向代理动态资源。
Docker 是一种流行的容器技术,可以运行任何服务。
如何结合使用Docker + Nginx?
我们来试试:
首先下载 Docker,直接安装 Docker Desktop:
它是用来管理容器和镜像的:
安装完成后,就可以使用 docker 命令了:
然后运行nginx 图像。
搜索nginx(这一步需要科学上网,需要访问网站http://hub.docker.com),点击运行:
输入要映射的容器名称和端口:
这里将主机的81端口映射到容器中的80端口,点击运行。
此时可以看到docker容器正在运行,并且正在打印日志文件:
用浏览器访问http://localhost:81,可以看到nginx欢迎页面:
这个当然是在容器中运行服务了。
但当前页面是默认页面。我想使用 nginx 来托管一些静态 html 页面。我应该怎么办?
首先我们需要知道当前的配置文件和页面位于哪里。
在文件面板中可以看到容器内的文件:
/usr/share/nginx/html/文件夹下都是静态文件。
双击打开index.html看看:
和我们在浏览器中看到的页面一模一样。
也就是说,这个文件夹就是存放静态文件的文件夹。
我们可以把自己的html放在这个文件夹里吗?
我们先复制这个文件夹:
docker cp nginx1:/usr/share/nginx/html ~/nginx-html

docker cp 该命令用于在主机和容器之间复制文件和文件夹。
比如我们把这个文件夹复制到容器中:
docker cp ~/nginx-html nginx1:/usr/share/nginx/html-xxx
可以看到容器里有这个文件夹:
然后我们在这个文件夹中添加两个html文件来试试:
echo aaa > aaa.html
echo bbb > bbb.html
docker cp ~/nginx-html nginx1:/usr/share/nginx/html

但是当目标文件夹存在时,docker会将其复制到目标文件夹:
我们需要先从容器中删除该文件夹,然后复制它:
docker cp ~/nginx-html nginx1:/usr/share/nginx/html
这样就可以了:
然后尝试使用浏览器访问它:
现在您可以访问容器中的这些文件夹。
即只要放在/usr/share/nginx/html下的文件是可以访问的。
但是为什么呢?
这是由于nginx默认配置造成的。
我们看一下nginx的配置文件,它是/etc/nginx/nginx.conf。
复制下来查看一下:
docker cp nginx1:/etc/nginx/nginx.conf ~/nginx-html
这是nginx的默认配置:
其实这个nginx.conf叫做主配置文件,里面一般包含一些全局配置比如错误日志目录、
可以看到http下有一个include,引入了/etc/nginx/conf.d/*.conf的配置。
一般来说,具体的路由配置都在这些子配置文件中。
目录conf.d表示配置目录。
我们复制这个文件夹看看:
docker cp nginx1:/etc/nginx/conf.d ~/nginx-html
localhost:80虚拟主机下的所有路由都配置在这里。
什么是虚拟主机?
可以使用一台nginx服务器为多个域名和端口提供服务。
只需添加一些服务器配置即可。
这里我们配置localhost:80虚拟主机。
下面的位置是路由配置。
例如这个配置:
它配置/下的所有路由,并将它们定位在root指定的目录中。
所以从/usr/share/nginx/html/aaa.html找到http://localhost/aaa.html。
位置支持不同的语法。让我们逐一尝试:
location = /111/ {
default_type text/plain;
return 200 "111 success";
}
location /222 {
default_type text/plain;
return 200 $uri;
}
location ~ ^/333/bbb.*\.html$ {
default_type text/plain;
return 200 $uri;
}
location ~* ^/444/AAA.*\.html$ {
default_type text/plain;
return 200 $uri;
}
删除之前的位置/并添加这些路由配置。
这些配置的具体含义稍后讨论。
将此文件复制到容器中:
docker cp ~/nginx-html/conf.d/default.conf nginx1:/etc/nginx/conf.d/default.conf
然后在容器中的终端中,运行:
nginx -s reload
重新加载配置文件。
然后看第一条路由:
在位置和路径之间添加=,代表精确匹配,即只有完全相同的URL才匹配此路由。
不带=表示根据前缀匹配,前缀后面可以跟任意路径。这里的
$uri是走当前路径。
如果你想支持正则表达式,可以使用~。
这里的常规语法并不难理解,以/333/bbb开头,然后中间有字符,最后url以.html结尾。
但区分大小写。例如,这不起作用:
更改为小写:
如果您希望正则表达式不区分大小写,您可以添加*
并尝试:
所有大写或小写字母都是可以接受。
另外,还有一种语法:
将此配置添加到配置文件中:
location /444 {
default_type text/plain;
return 200 'xxxx';
}
然后复制到容器中并重新加载:
docker cp ~/nginx-html/conf.d/default.conf nginx1:/etc/nginx/conf.d/default.conf

目前有两条 /444 路由:
At此时,浏览器访问还是和上面的路由一样:
如果想提高优先级,可以使用^~
,改成这样:
location ^~ /444 {
default_type text/plain;
return 200 'xxxx';
}
然后复制到容器中重新加载一下:
docker cp ~/nginx-html/conf.d/default.conf nginx1:/etc/nginx/conf.d/default.conf

这个 当找到相同的 URL 时,会找到以下路由:
也就是说:^~ 可以提高前缀匹配的优先级。
综上所述,一共有 4 种位置语法:
location = /aaa 是与 /aaa 完全匹配的路由。
location /bbb 是前缀与 /bbb 匹配的路由。
location ~ /ccc.*.html 是常规匹配。可以添加 * 表示位置不区分大小写 ~* /ccc.*.html
location ^~ /ddd 是前缀匹配,但优先级更高。
这四种语法的优先级如下:
精确匹配(=)>高优先级前缀匹配(^~)>普通匹配(~~*)>普通前缀匹配
我们现在的内容直接用return返回实际上应该返回一个html文件。
可以改成如下:
location /222 {
alias /usr/share/nginx/html;
}
location ~ ^/333/bbb.*\.html$ {
alias /usr/share/nginx/html/bbb.html;
}
然后复制到容器中,重新加载:
docker cp ~/nginx-html/conf.d/default.conf nginx1:/etc/nginx/conf.d/default.conf

可以正确返回对应的html:
我之前用过root:
root 和 root 有什么区别别名? ?例如
以下两个配置:
location /222 {
alias /dddd;
}
location /222 {
root /dddd;
}
也是/222/xxx/yyy.html。如果使用根配置,则整个uri在后面被分割为路径。
即会搜索文件/dddd/222/xxx/yyy.html。
如果是别名配置,去掉/222后会分割部分路径。
即查找文件/dddd/xxx/yyy.html。
也就是我们的root和alias的区别在于分割路径时是否包含满足条件的路径。
这是nginx的第一个特性:静态文件托管。
主配置文件位于/etc/nginx/nginx.conf,子配置文件位于/etc/nginx/conf.d目录。
默认的 HTML 路径是 /usr/share/nginx/html。
接下来我们看一下nginx的第二大特性:动态资源的反向代理。
什么是前进,什么是落后?
从用户的角度来看,方向一致的为正向,相反的方向为反向。
例如,有两个这样的代理:
第一个是正向代理,第二个是反向代理。
第一个代理是代理用户请求,它与用户请求运行方向相同,称为正向代理。
第二个代理是与用户请求相反方向处理用户请求的代理服务器。这称为反向代理。
在测试 nginx 作为反向代理服务器之前,我们先创建一个嵌套服务。
npx nest new nest-app -p npm

运行服务:
npm run start:dev

使用浏览器访问http://localhost:3000。如果看到 hello world,则说明 Nest 服务运行成功:
添加全局前缀 /api
更改为 nginx 配置并添加路由:
location ^~ /api {
proxy_pass http://192.168.1.6:3000;
}
此路由匹配以 /api 开头的 URL,基于前缀。 ^~ 用于提高优先级。
然后将其复制到容器中并重新加载:
docker cp ~/nginx-html/conf.d/default.conf nginx1:/etc/nginx/conf.d/default.conf

然后访问 http://localhost:81/api 可以看到 Nest 服务返回的响应:
即是这样的:
为什么我们需要更多的 nginx 代理?
当然在这个级别你可以做很多事情。
例如,更改标头:
然后将其复制到容器并重新加载:
docker cp ~/nginx-html/conf.d/default.conf nginx1:/etc/nginx/conf.d/default.conf

将标头注入嵌套服务处理程序,打印它:
,然后使用浏览器打开它。
如果直接访问 Nest 服务,则没有这样的 header:
访问 nginx 反向代理服务器并进行传输:
这就是反向代理服务器的作用,可以透明修改请求和回应。
而且,你还可以用它来实现负载均衡。
打印控制器中的访问日志:
停止nest服务并重新启动npm run restart
对3001和3002各执行一个端口:
浏览器打开后一切正常:
console还打印了访问日志:
问题来了。现在有一台 nginx 服务器和两台 Nest 服务器。 nginx应该如何响应?
nginx的解决方案是负载均衡,将请求按照一定的规则分配到不同的服务器上。
更改nginx配置文件:
配置代理上游的目标服务器的所有实例。
下面,proxy_pass 指定为名称upstream。
然后复制到容器并重新加载:
docker cp ~/nginx-html/conf.d/default.conf nginx1:/etc/nginx/conf.d/default.conf

现在我正在访问 http://localhost:81/api 并刷新页面 5 次:
您可以看到两个嵌套服务,一个 3 次, 1次2次。第二次评价。
因为默认是轮询。
共有四种任务分配策略:
- 轮询:默认方式。
- 权重:根据民意调查添加权重,即民意调查的概率不同。
- ip_hash:根据IP的哈希分布,保证每个访问者的请求都固定访问某个服务器,解决会话问题。
- 公平:根据响应时间分配。这需要安装 nginx-upstream-fair 插件。
我们来测试一下weight和ip_hash方法。
添加一个weight=2,默认为1,所以被两台服务器轮询的几率是2比1。
然后复制到容器中并重新加载:
docker cp ~/nginx-html/conf.d/default.conf nginx1:/etc/nginx/conf.d/default.conf

按command + k嵌套服务控制台日志:
然后我访问了http://localhost:81/api 8次
看打印的日志,民意调查的概率几乎是2:1。
这是一项加权民意调查。
我们再尝试一下ip_hash方法;
然后复制到容器中并重新加载:
docker cp ~/nginx-html/conf.d/default.conf nginx1:/etc/nginx/conf.d/default.conf

按 command + k 清除 Nest 服务控制台日志:
重新访问 http:// /localhost:81/api
可以看到请求已发送到服务器:
这是Nginx的负载均衡策略。
总结
我们通过docker运行nginx服务器,并使用静态资源托管功能和动态资源的反向代理功能。
nginx 配置文件位于 /etc/nginx/nginx.conf 中,默认情况下还会引入 /etc/nginx/conf.d 下的子配置文件。
HTML 默认放置在 /usr/share/nginx/html 下。
我们可以使用docker cp将容器中的文件复制到主机上进行修改。
更改nginx配置,在服务器上配置路由,根据不同的URL返回不同的静态文件。
有 4 种位置语法:
- location /aaa 匹配
- location by prefix ^~ /aaa 匹配前缀,优先级更高
- location = /aaa 精确匹配
- location ~ /aaa / .*html 正则匹配
- 位置 ~* /aaa/.*html 正则匹配且不区分大小写
优先级为精确匹配 (=) > 高优先级前缀 (^~) > 正则匹配 (~ ~*) > 常规前缀匹配
除了静态源托管之外,nginx 还可以对动态源进行反向代理。
即请求发送到nginx,nginx转发到应用服务器。该层也可以称为网关。
nginx反向代理可以更改请求和响应信息,例如设置标头。
如果有多个应用服务器,可以在上游配置负载均衡。有四种策略:轮询、加权轮询、ip_hash 和公平。
一旦掌握了静态资源托管和动态资源反向代理+负载均衡,你就掌握了Nginx的核心用法。
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。