Nginx是一个轻量级的高性能的Web、反向代理服务器,其在内存占用、并发等方面表现突出。这里基于Docker说明、实践其典型用法——反向代理、负载均衡、动静分离
反向代理
为便于演示,这里我们先在本地的hosts文件添加两条不同域名的映射。具体地,我们将service1.com、service2.com均映射到本地。如下所示
这里通过Docker Compose建立包含一个Nginx、两个Tomcat的服务,具体如下所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| version: '3.8'
services:
Nginx-Service-1: image: nginx:1.21 container_name: Nginx-Service-1 ports: - "80:80" volumes: - ./Config/Nginx/nginx.conf:/etc/nginx/nginx.conf networks: reverseProxy_service_net: ipv4_address: 123.115.107.80
Tomcat-Service-1: image: tomcat:jre8-temurin-focal container_name: Tomcat-Service-1 ports: - "9111:8080" volumes: - ./Config/Service1:/usr/local/tomcat/webapps/ROOT networks: reverseProxy_service_net: ipv4_address: 123.115.107.81
Tomcat-Service-2: image: tomcat:jre8-temurin-focal container_name: Tomcat-Service-2 ports: - "9222:8080" volumes: - ./Config/Service2:/usr/local/tomcat/webapps/ROOT networks: reverseProxy_service_net: ipv4_address: 123.115.107.82
networks: reverseProxy_service_net: ipam: config: - subnet: 123.115.107.0/24
|
这里我们将Nginx的配置文件挂载到宿主机当中,并在http块中添加两个server块,具体如下所示。不难看出Nginx会将来自service1.com、service2.com两个不同域名的请求转发至各自指定的Tomcat服务。这里目标服务的地址使用的均是Tomcat容器内部的IP、Port
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| ...
http { server { listen 80; server_name service1.com; location / { proxy_pass http://123.115.107.81:8080; } }
server { listen 80; server_name service2.com; location / { proxy_pass http://123.115.107.82:8080; } }
... }
|
Tomcat的两个容器服务Tomcat-Service-1、Tomcat-Service-2分别使用如下的HTML文件
1 2 3 4 5
| Hello, This is Tomcat Service 1
Hello, This is Tomcat Service 2
|
至此,所有相关文件的目录结构如下所示
在启动容器服务后,我们分别通过各自Tomcat服务的端口进行访问,确认各Tomcat服务是否均正常。效果如下所示
现在我们看下通过不同域名进行访问,Nginx是否会将相关请求转发至指定Tomcat服务。效果如下所示,符合预期
负载均衡
为便于演示,这里我们先在本地的hosts文件再添加一个域名的映射。具体地,我们将hello.com映射到本地。如下所示
类似地,我们再次通过Docker Compose建立包含一个Nginx、两个Tomcat的服务,具体如下所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| version: '3.8'
services:
Nginx-Service: image: nginx:1.21 container_name: Nginx-Service ports: - "80:80" volumes: - ./Config/Nginx/nginx.conf:/etc/nginx/nginx.conf networks: loadBalance_service_net: ipv4_address: 69.69.69.80
Tomcat-Service-A: image: tomcat:jre8-temurin-focal container_name: Tomcat-Service-A ports: - "8111:8080" volumes: - ./Config/ServiceA:/usr/local/tomcat/webapps/ROOT networks: loadBalance_service_net: ipv4_address: 69.69.69.81
Tomcat-Service-B: image: tomcat:jre8-temurin-focal container_name: Tomcat-Service-B ports: - "8222:8080" volumes: - ./Config/ServiceB:/usr/local/tomcat/webapps/ROOT networks: loadBalance_service_net: ipv4_address: 69.69.69.82
networks: loadBalance_service_net: ipam: config: - subnet: 69.69.69.0/24
|
这里我们将Nginx的配置文件挂载到宿主机当中,并在http块中添加一个server块,具体如下所示。
Nginx会将来自hello.com的请求转发至名为helloServerCluster的服务集群,然后通过upstream指定该服务集群下的各实例地址。这里实例服务的地址使用的均是Tomcat容器内部的IP、Port
这里补充说明下,Nginx支持如下的负载均衡策略:
- 轮询:默认策略
- weight:基于权重的策略,权重越高优先级越高
- fair:基于服务实例的响应时间策略,实例响应时间越短优先级越高
- ip_hash:根据访问IP的Hash值确定服务实例,可以保证同一个IP的访问请求总是被转发至同一个服务实例
显然这里我们采用Nginx默认的轮询策略
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| ...
http { server { listen 80; server_name hello.com; location / { proxy_pass http://helloServerCluster; } }
upstream helloServerCluster { server 69.69.69.81:8080; server 69.69.69.82:8080; }
... }
|
Tomcat的两个容器服务Tomcat-Service-A、Tomcat-Service-B分别使用如下的HTML文件
1 2 3 4 5
| [Tomcat Service A]: Hello~
[Tomcat Service B]: Hello~
|
至此,所有相关文件的目录结构如下所示
在启动容器服务后,我们分别通过各自Tomcat服务的端口进行访问,确认各Tomcat服务是否均正常。效果如下所示
现在我们看下通过80端口进行访问,Nginx是否会将相关请求依次转发至上述两个Tomcat服务。效果如下所示,符合预期
动静分离
既然Nginx本身就是一个Web服务器,那我们就可以通过动静分离将静态资源文件部署在Nginx上。为便于演示,这里我们在本地的hosts文件再添加一个域名的映射。具体地,我们将test.com映射到本地。如下所示
类似地,我们再次通过Docker Compose建立包含一个Nginx、一个Tomcat的服务,具体如下所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| version: '3.8'
services:
Nginx-Service-1: image: nginx:1.21 container_name: Nginx-Service-1 ports: - "80:80" volumes: - ./Config/Nginx/nginx.conf:/etc/nginx/nginx.conf networks: static_service_net: ipv4_address: 151.151.12.80
Tomcat-Service-1: image: tomcat:jre8-temurin-focal container_name: Tomcat-Service-1 ports: - "9111:8080" volumes: - ./Config/Service1:/usr/local/tomcat/webapps/ROOT networks: static_service_net: ipv4_address: 151.151.12.81
networks: static_service_net: ipam: config: - subnet: 151.151.12.0/24
|
这里我们将Nginx的配置文件挂载到宿主机当中,并在http块中添加一个server块,具体如下所示。这里我们配置了3个location规则。前两个分别是根据请求路径前缀、请求资源类型进行匹配的,同时通过root指定相关静态资源文件的父目录;最后一个location则是一个通用匹配,用于匹配之前两个location无法匹配的请求,具体地我们将其转发至Tomcat服务进行处理。同理,这里Tomcat服务的地址使用的是Tomcat容器内部的IP、Port
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| ...
http { server { listen 80; server_name test.com;
location ^~ /static/ { root /resource; }
location ~ .png$ { root /resource; }
location / { proxy_pass http://151.151.12.81:8080; } }
... }
|
Tomcat容器服务使用如下的HTML文件
1 2
| Hello, Welcome To Tomcat
|
然后我们进入Nginx容器,创建、存放相应的静态文件。首先我们在根目录下创建resource目录,然后在其中再分别创建两个子目录:fig、static。前者的目录中存放一张图片;后者的目录中存放了两个html文件。后面会解释为什么需要创建这两个子目录
至此宿主机环境中相关文件的目录结构如下所示
一切准备就绪后,我们进行访问测试。通过下述测试结果的红框不难看出,我们访问Nginx的静态资源文件成功,而蓝框结果则表明我们通过Nginx进行反向代理访问Tomcat服务成功。这里补充说明下,Nginx确定静态资源文件的路径,是通过相应location的root配置项 + 资源路径拼接后得到。例如对于 test.com/static/a.html 请求而言,相应location的root配置项为/resource,资源路径为/static/a.html。则该静态资源在Nginx中的存放路径就必须是/resource/static/a.html
同理,对于Nginx容器中/resource/fig目录下的图片dog.png,其完整的请求路径就应该是test.com/fig/dog.png
测试结果如下所示,符合预期