2.3 项目实践
在项目实践环节,我们会继续沿用第1章的待办任务列表Web应用示例。首先尝试将网关层组件从Kong切换到Nginx,看一下整体的效果变化;然后修改Nginx配置文件,添加黑白名单和限流功能,完善应用场景;最后将网关层组件从Nginx切换到Kong,同时保留这两项功能,对比一下这两个网关组件的异同点。
2.3.1 从Kong切换到Nginx
这里我们着重介绍Nginx的网关层功能,所以基于1.5.2节的示例进行改造,从Kong网关切换到Nginx,以达到同样的效果。项目目录结构调整为:
├── Readme.md ├── backend ├── docker-compose.yml ├── frontend └── nginx-gateway
这里我们删除了原有的kong-gateway项目及里面的文件,新增了一个nginx-gateway项目。首先修改docker-compose.yml启动文件,将原先的Kong启动项配置修改为Nginx,如代码清单2-2所示。
程序清单2-2 Nginx启动项配置
24 ... 25 ... 26 nginx: 27 build: 28 context: ./nginx-gateway 29 container_name: nginx 30 ports: 31 - '8000:8000' 32 volumes: 33 - ./nginx-gateway:/etc/nginx/conf.d 34 depends_on: 35 - backend
新增的nginx-gateway项目中包含两个配置文件:dockerfile和nginx.conf,其中dockerfile配置文件如下:
# nginx dockerfile FROM nginx:1.17.1
nginx.conf文件中增加了代理后端的一些相关配置,其中路由信息匹配的路径是/nginx/gateway/todos,对应的后端地址为http://backend:80/todos,这里我们将Nginx监听端口修改为8000(为了不与backend项目冲突)。nginx.conf配置文件如代码清单2-3所示。
程序清单2-3 nginx.conf配置文件
1 server { 2 listen 8000; 3 server_name _; 4 5 location / { 6 root /usr/share/nginx/html; 7 index index.html index.htm; 8 } 9 location /nginx/gateway/todos { 10 proxy_pass http://backend:80/todos; 11 } 12 }
在完成网关层配置之后,我们还需要对之前的前端项目做一些简单修改(变更接口访问地址),将BACKEND_URL修改为http://127.0.0.1:8000/nginx/gateway/todos,其中127.0.0.1:8000为Nginx网关层入口地址,这样请求便可先抵达网关层,匹配路由后再转发至后端服务,如代码清单2-4所示。
程序清单2-4 对前端项目修改后的配置文件
1 import Vue from 'vue'; 2 import BootstrapVue from 'bootstrap-vue'; 3 import axios from 'axios'; 4 import App from './App.vue'; 5 6 const http = axios.create({ 7 baseURL: process.env.BACKEND_URL ? process.env.BACKEND_URL : 'http:// 127.0.0.1:8000/nginx/gateway/todos', 8 }); 9 10 Vue.prototype.$http = http; 11 12 13 Vue.use(BootstrapVue); 14 15 Vue.config.productionTip = false; 16 17 new Vue({ 18 render: (h) => h(App), 19 }).$mount('#app');
至此,项目已经改造完成。读者使用docker-compose up-d指令启动服务后,在浏览器内输入http://127.0.0.1:8000访问界面,可以观察到后端服务访问地址已经变更。效果如图2-3所示。
图2-3 Nginx网关页面控制台信息
2.3.2 添加黑白名单
在完成上述步骤后,我们对接口控制方案进行升级。首先引入黑白名单功能,这个功能在实际应用中非常常见,是接口管控的基本功能。在Nginx中添加黑白名单非常简单,只需在nginx.conf配置文件中添加代码清单2-5所示的代码。
程序清单2-5 在nginx.conf配置文件中添加黑名单
9 ... 10 proxy_pass http://backend:80/todos; 11 deny 172.20.0.1; 11 allow all; 12 ...
第11行代码表示该Nginx服务器的路由规则为此后不再接收IP地址为172.20.0.1的服务器(即frontend服务所在服务器)发出的任务请求。在2.3.1节中,我们没有对黑白名单做任何限制,默认允许所有请求访问。此时重启Nginx服务器,在浏览器中输入http://127.0.0.1:8000,发现原先正常的接口现在已经访问不通了,效果如图2-4所示。
图2-4 Nginx配置黑名单生效
接下来,我们再修改配置,仅允许前端项目通过网关层访问后端接口,如代码清单2-6所示。
程序清单2-6 nginx.conf配置文件配置白名单
9 ... 10 proxy_pass http://backend:80/todos; 11 allow 172.20.0.1; 12 deny all; 13 ...
该配置中表示该Nginx服务器的路由规则为仅允许接收IP地址为172.20.0.1的服务器发出的请求。需要注意的是,在配置多规则情况下,Nginx默认自上而下读取规则,所以配置顺序不能写错,在配置较多规则时,可以使用ngx_http_geo_module模块变量。
2.3.3 添加限流
这一节中,我们继续在接口上添加限流功能。限流的目的在于防止恶意请求攻击和请求流量超过系统峰值,保障服务器可以正常运行。这里我们主要针对请求URI进行限流(不包括请求URI中的参数)。整体项目结构依旧不做更改,继续修改nginx.conf配置文件,如代码清单2-7所示。
程序清单2-7 在nginx.conf配置文件中添加限流功能
1 limit_req_zone $uri zone=api_read:10m rate=3r/m; 2 3 server { 4 listen 8000; 5 server_name _; 6 7 location / { 8 root /usr/share/nginx/html; 9 index index.html index.htm; 10 } 11 location /nginx/gateway/todos { 12 proxy_pass http://backend:80/todos; 13 limit_req zone=api_read; 14 limit_req_status 503; 15 } 16 }
·第1行代码:表示根据请求URI,限制其请求速率为每分钟3次,zone为存储的空间,空间名为api_read,大小为10MB。
·第13行代码:表示在当前location配置块中使用这个限流组件。
·第14行代码:表示限流生效时返回的状态码(状态码可自定义,默认返回503)。
图2-5 Nginx限流效果
修改完成后,使用docker restart nginx指令使配置文件生效。打开浏览器访问http://127.0.0.1:8000,发现该接口已经无法正常访问,效果如图2-5所示。
但是,使用浏览器并不能直接地体会限流功能(也有可能是其他因素导致功能无法使用)。我们可以使用curl指令查看接口的响应状态码来分辨接口是否真被限流了。这里执行如下指令进行对比:
$ curl -I -m 10 -o /dev/null -s -w %{http_code} http://127.0.0.1:8000/ nginx/gateway/todos/ 200 $ curl -I -m 10 -o /dev/null -s -w %{http_code} http://127.0.0.1:8000/ nginx/gateway/todos/ 503
可以发现,第一次调用接口成功返回200,紧接着第二次调用接口返回503,表示该接口已经被限流。
2.3.4 从Nginx切换到Kong
在2.3.2节和2.3.3节中,我们已经使用Nginx服务器实现了简单的黑白名单和限流功能,本节我们将切换为Kong网关,看一下Kong网关是如何实现这些功能的。这里我们沿用1.5.2节中的案例,在此基础上进行改造。项目目录结构保持不变,修改其中的kong.yml配置文件,如代码清单2-8所示。
程序清单2-8 kong.yml配置文件
14 ... 15 plugins: 16 - name: rate-limiting 17 config: 18 minute: 3 19 policy: local 20 route: route_todolists 21 - name: ip-restriction 22 config: 23 whitelist: ["172.21.0.1"] 24 route: route_todolists
在上述配置文件中,我们添加了名为rate-limiting和ip-restriction的插件(插件会在第11章做重点介绍),表示只允许访问172.21.0.1(即frontend地址),且每分钟只能访问3次。配置完成后,使用docker-compose up-d指令重新启动示例服务,在浏览器中输入http://127.0.0.1:8000,对比添加完插件之后接口响应内容与原先的差异。效果如图2-6和图2-7所示。
图2-6 Kong限流效果图一
图2-7 Kong限流效果图二
响应头中的X-RateLimit-Limit-Minute表示限流的次数,即每分钟3次;X-RateLimit-Remaining-Minute表示限流剩余的次数;RateLimit-Reset表示还需要多长时间才能重置限流插件、恢复访问,单位为秒。
2.3.5 小结
同第1章一样,笔者将上述三个示例都封装成独立的项目,运行docker-compose up-d指令即可启动。
我们从这几个例子中已经可以分辨出Kong网关与Nginx服务器之间的一些异同。首先,它们从大的功能层面上趋于一致,都能用比较简单的方式满足一般的定制化需求,但是在功能实现细节上略有不同。具体到限流插件,Nginx服务器配置每分钟访问3次,系统默认会将该配置转化为每20秒访问1次。Kong网关在限流上相对人性化,效果与预想的保持一致。再如黑白名单功能,Nginx支持更加灵活的设定,同时开放黑白名单功能,并全部交由开发者配置。Kong网关则在单个插件上仅支持黑名单或白名单,限定了使用场景。
这些功能点差异本身并没有优劣之分,用户仅需根据业务场景做出调整即可。