1.5 使用Kong网关搭建Web应用
区别于传统的HelloWorld示例(仅简单打印一句语句),本节将介绍如何使用Kong网关搭建一个前后端分离的Web应用。通过这个示例,读者将对Kong网关全局有一个更好的认识。
1.5.1 示例项目介绍
该示例项目为搭建一个简单的待办任务列表Web应用(todos),前端使用Vue框架,后端基于Node.js的Express框架,数据库使用MongoDB。项目目录结构如下所示。
├── Readme.md ├── backend ├── docker-compose.yml └── frontend
其中,frontend和backend目录分别对应项目的前后端应用。整个项目基于Docker容器启动。docker-compose.yml为启动配置文件,配置项如代码清单1-3所示。
程序清单1-3 docker-compose.yml文件
1 version: "3" 2 services: 3 backend: 4 container_name: backend 5 build: 6 context: ./backend 7 depends_on: 8 - db 9 volumes: 10 - ./backend:/usr/app 11 - /usr/app/node_modules 12 environment: 13 - MONGO_URL=mongodb://db:27017/todos 14 - APP_PORT=80 15 ports: ['80:80'] 16 db: 17 container_name: db 18 image: mongo:4.0 19 restart: always 20 frontend: 21 container_name: frontend 22 build: 23 context: ./frontend 24 volumes: 25 - ./frontend:/app 26 - /app/node_modules 27 ports: 28 - '8080:8080' 29 environment: 30 - BACKEND_URL=http://127.0.0.1/todos
frontend和backend应用中各自包含Dockerfile文件,如代码清单1-4和代码清单1-5所示。
程序清单1-4 frontend应用的Dockerfile文件
# frontend dockerfile FROM node:12.2.0-alpine # set working directory WORKDIR /app COPY package*.json ./ RUN npm install COPY . . # start app CMD ["npm", "run", "serve"]
程序清单1-5 backend应用的Dockerfile文件
# backend dockerfile FROM node:12.2.0-alpine # set working directory WORKDIR /usr/app COPY package*.json ./ RUN npm install COPY . . # start app CMD [ "npm", "start" ]
这里,前端应用使用vue-cli-service serve命令启动,后端应用使用node app.js命令启动。关于前后端应用中的源码和细节,此处不再赘述,有兴趣的读者可以自行下载阅读。读者可以直接运行docker-compose up-d命令启动项目,启动完成后在浏览器中输入地址http://127.0.0.1:8080访问页面,如图1-10所示。
图1-10 todos页面
1.5.2 后端服务路由
在成功执行完第一个示例后,我们接下来对后端服务架构进行改造。整体架构改造如下。
项目目录结构调整为:
├── Readme.md ├── backend ├── docker-compose.yml ├── frontend └── kong-gateway
这里新增了一个kong-gateway目录,首先修改docker-compose.yml启动文件,添加Kong的启动项配置,如代码清单1-6所示。
程序清单1-6 docker-compose.yml启动文件
29 ... 30 ... 31 kong: 32 build: 33 context: ./kong-gateway 34 container_name: kong 35 environment: 36 KONG_DATABASE: 'off' 37 KONG_DECLARATIVE_CONFIG: /usr/local/kong/declarative/config.yml 38 KONG_PROXY_ACCESS_LOG: /dev/stdout 39 KONG_ADMIN_ACCESS_LOG: /dev/stdout 40 KONG_PROXY_ERROR_LOG: /dev/stderr 41 KONG_ADMIN_ERROR_LOG: /dev/stderr 42 KONG_ADMIN_LISTEN: 0.0.0.0:8001, 0.0.0.0:8444 ssl 43 ports: 44 - '8000:8000' 45 - '8443:8443' 46 - '8001:8001' 47 - '8444:8444' 48 volumes: 49 - ./kong-gateway:/usr/local/kong/declarative 50 depends_on: 51 - backend
新增的kong-gateway目录中包含两份配置文件:dockerfile和config.yml(Kong启动项配置文件)。其中,dockerfile配置文件指定了Kong服务器的版本,这里使用的是2.0.5版本。我们在之后的示例中同样基于这个版本进行介绍,以保证版本信息统一。Dockerfile配置文件如下。
1 # kong dockerfile 2 FROM kong:2.0.5
config.yml配置文件指定了网关层的路由配置以及路由对应的后端服务地址。读者这里可以先做一些简单了解,后续章节会对该配置文件做详细介绍。此处,网关层路由匹配路径是/kong/gateway,对应的后端服务地址为backend:80,即原应用后端服务地址。详细配置如代码清单1-7所示。
程序清单1-7 config.yml配置文件
1 _format_version: "1.1" 2 3 services: 4 - name: service_todolists 5 host: host_todolists 6 routes: 7 - name: route_todolists 8 paths: 9 - /kong/gateway 10 11 upstreams: 12 - name: host_todolists 13 targets: 14 - target: backend:80
在网关层配置好之后,我们还需要对之前的前端应用做一些简单修改:变更接口访问地址,将BACKEND_URL修改为http://127.0.0.1:8000/kong/gateway/todos。其中,127.0.0.1:8000为网关层入口地址,这样请求便可先抵达网关层,待匹配路由后再转发至原后端服务,如代码清单1-8所示。
程序清单1-8 前端应用修改
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 baser: process.env.BACKEND_URL ? process.env.BACKEND_URL : 'http://127.0.0. 1:8000/kong/gateway/todos', 8 }); 9 10 Vue.prototype.$http = http; 11 12 Vue.use(BootstrapVue); 13 14 Vue.config.productionTip = false; 15 16 new Vue({ 17 render: (h) => h(App), 18 }).$mount('#app');
至此,整个项目已改造完成。后端应用在这次改造过程中保持不变。重新运行docker-compose up-d命令,待容器重启后打开浏览器控制台,观察请求细节的变化。
原先的请求详情如图1-11所示。
引入Kong网关之后的请求详情如图1-12所示。
图1-11 原先的请求详情
图1-12 引入Kong网关之后的请求详情
1.5.3 静态页面代理
在完成上述步骤后,我们继续对部署方案进行升级。之前前端应用使用vue-cli-service serve启动,但其仅适用于本地开发环境或测试环境。在真实的生产环境中,我们会将前端应用打包成静态文件,然后部署在服务器中,或者上传至CDN。这里,我们对整体架构再做一些调整,让Kong服务器既作为Web服务器,又作为代理服务器。
项目目录结构与1.5.2节保持一致。
├── Readme.md ├── backend ├── docker-compose.yml ├── frontend └── kong-gateway
我们还是从docker-compose.yml文件开始修改,主要新增第24~25行、第46~48行和第50~51行。这些配置的作用是将前端应用编译出来的静态文件通过Docker卷共享,以便直接被Kong服务器访问到。此处创建的卷名称为static,用户可以自定义名称。该Docker卷映射到前端应用和Kong服务器的路径分别为/app/dist和/static,如代码清单1-9所示。
程序清单1-9 docker-compose.yml文件
19 ... 20 frontend: 21 container_name: frontend 22 build: 23 context: ./frontend 24 volumes: 25 - static:/app/dist 26 environment: 27 - BACKEND_URL=http://127.0.0.1:8000/kong/gateway/todos 28 kong: 29 build: 30 context: ./kong-gateway 31 container_name: kong 32 environment: 33 KONG_DATABASE: 'off' 34 KONG_DECLARATIVE_CONFIG: /usr/local/kong/declarative/config.yml 35 KONG_PROXY_ACCESS_LOG: /dev/stdout 36 KONG_ADMIN_ACCESS_LOG: /dev/stdout 37 KONG_PROXY_ERROR_LOG: /dev/stderr 38 KONG_ADMIN_ERROR_LOG: /dev/stderr 39 KONG_ADMIN_LISTEN: 0.0.0.0:8001, 0.0.0.0:8444 ssl 40 ports: 41 - '8000:8000' 42 - '8443:8443' 43 - '8001:8001' 44 - '8444:8444' 45 - '8080:8080' 46 volumes: 47 - ./kong-gateway:/usr/local/kong/declarative 48 - static:/static 49 depends_on: 50 - backend 51 volumes: 52 static:
接下来,我们对kong-gateway项目进行改造,在原有目录结构下新增一个todolists.conf文件。
├── Dockerfile ├── config.yml └── todolists.conf
先来看一下改造后的Dockerfile文件,如代码清单1-10所示。
程序清单1-10 改造后的Dockerfile文件
1 FROM kong:2.0.5 2 VOLUME ["/static"] 3 ADD ./todolists.conf /etc/kong 4 CMD ["kong","start","--nginx-conf","/etc/kong/todolists.conf","&"]
第2行代码:在容器内挂载之前在docker-compose.yml配置文件中创建的static卷。
第3行代码:将新增的todolists.conf文件添加到Docker容器内部的/etc/kong目录下备用。
第4行代码:执行kong start命令,并携带命令行参数--nginx-conf,指定Nginx配置文件,即之前的todolists.conf文件。
todolists.conf文件中的内容如代码清单1-11所示。
程序清单1-11 todolists.conf文件
1 # --------------------- 2 # custom_nginx.template 3 # --------------------- 4 5 worker_processes ${{NGINX_WORKER_PROCESSES}}; 6 daemon ${{NGINX_DAEMON}}; 7 8 pid pids/nginx.pid; 9 error_log logs/error.log ${{LOG_LEVEL}}; 10 11 events { 12 use epoll; # custom setting 13 multi_accept on; 14 } 15 16 http { 17 # 引入默认的Nginx配置文件 18 include 'nginx-kong.conf'; 19 # 引入默认的mime.type配置文件 20 include /usr/local/openresty/nginx/conf/mime.types; 21 default_type application/octet-stream; 22 23 # 自定义server块 24 server { 25 server_name _; 26 listen 8080; 27 location / { 28 default_type text/css; 29 root /static; 30 index index.html; 31 } 32 } 33 }
我们将在第5章中详细讲解该文件内容的细节,此处仅需知道我们通过该配置文件,暴露了8080端口作为Kong Web服务器的入口地址。前端静态文件的根目录为/static。
最后,我们对前端应用进行改造,修改其中的dockerfile文件,如代码清单1-12所示。
程序清单1-12 修改前端应用中的Dockerfile文件
1 FROM node:12.2.0-alpine 2 WORKDIR /app 3 VOLUME ["/static"] 4 # set working directory 5 COPY package*.json ./ 6 7 RUN npm install 8 9 COPY . . 10 11 # build app 12 CMD ["npm", "run", "build"]
第3行代码:与kong-gateway项目中的功能一致。
第12行代码:将CMD["npm","run","serve"]命令修改为CMD["npm","run","build"],之前是前端项目直接启动服务,现变更为编译成静态文件,供Web服务器使用。打包后的静态文件目录结构如下。
├── css │ └── app.0305fdfa.css ├── favicon.ico ├── index.html └── js ├── app.2a6813cb.js ├── app.2a6813cb.js.map ├── chunk-vendors.3c424d74.js └── chunk-vendors.3c424d74.js.map
至此,整个项目已经改造完毕,用户输入http://127.0.01:8080即可访问页面。此时,Kong服务器已兼具Web服务器和代理服务器的功能。