1. 前言
说到web服务的开源网关,我首先想到的是Nginx,最早使用的就是它,现在都还在使用它。系统上线了Docker Swarm集群之后,不继续使用Nginx直接做Docker服务的网关,是因为Nginx毕竟比Docker Swarm出现的早,其集成度还是不高。
我们经过技术调研对比后,选择了Traefik作为微服务API网关,也是因为Traefik和Docker集成比较好,通过在各个应用程序的docker-compose.yml里设置labels,把Traefik声明清楚,服务能够被Traefik自动接管,用不着我们在nginx.conf里那样手工进行配置,这大大简化了我们的配置工作。
当然nginx ingress controller和k8s的搭配,我并没有亲自搭建过,虽然有几台AI服务器是采用这样的部署方式,都是厂家预安装好的。
2. 简介
Traefik是一个高性能、易用的API网关,支持多种后端服务,如Docker、Kubernetes等,它采用Go语言开发。
Traefik官网文档地址是:Traefik Proxy Documentation - Traefik。
Traefik基于EntryPoints入口点、Routers路由器、Middlewares 中间件和Services服务的概念。它主要功能包括动态配置、自动服务发现以及对多个后端和协议的支持。
-
EntryPoints: EntryPoints对Traefit是一个网络入口点,它定义了接收数据包的端口port, 包括TCP和UDP。
-
Routers: 路由器负责将传入的请求连接到可以处理这些请求的服务。
-
Middlewares: 中间件附着于路由器上,它能够修改经过路由器的请求包和应答包。
-
Services: 服务组件负责配置请求怎样达到实际的后端服务。
3. 安装
各种安装方法说明参见官网:Traefik Installation Documentation - Traefik, 这里仅仅贴一下Docker Swarm集群里的安装方式,主要是docker-compose.yml编排:
version: "3.2"
services:
gateway:
image: traefik:v2.3.2
command:
- "--log.level=INFO"
- "--api=true"
- "--api.dashboard=true"
- "--api.insecure=true"
# 启用swarm模式支持
- "--providers.docker.swarmMode=true"
# 默认不公开容器
- "--providers.docker.exposedbydefault=false"
# 为traefik-net网络启用代理
- "--providers.docker.network=gateway"
# 开发环境:创建名为`web-dev`的入口点,并为其暴露于80端口。该入口点会指示其它容器在哪个端口公开
- "--entrypoints.web-dev.address=:80"
# 测试环境:创建名为`web-test`的入口点,并为其暴露于81端口。该入口点会指示其它容器在哪个端口公开
- "--entrypoints.web-test.address=:81"
# 预发布环境:创建名为`web-staging`的入口点,并为其暴露于82端口。该入口点会指示其它容器在哪个端口公开
- "--entrypoints.web-stagin.address=:82"
ports:
- 2080:80
- 2081:81
- 2082:82
- 1080:8080
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- gateway
deploy:
placement:
constraints:
- node.labels.traefik == true
networks:
gateway:
external: true
安装的操作不外乎在docker-compose.yml所在目录执行:
docker-compose up -d
docker ps | grep traefik
docker service ls | grep traefik
如果安装成功,则管理web地址是:http://127.0.0.1:1080/dashboard/#/,肯定不是127.0.0.1,换上实际IP地址即可。
4. EntryPoints
上图说明了EntryPoints可以支持多个端口,它向外部网络提供服务访问的入口点,架构上和功能细节上不用去细分析,那么配置上体现在哪里,我们怎么配置多个EntryPoint。
- "--entrypoints.web-dev.address=:80"
# 测试环境:创建名为`web-test`的入口点,并为其暴露于81端口。该入口点会指示其它容器在哪个端口公开
- "--entrypoints.web-test.address=:81"
# 预发布环境:创建名为`web-staging`的入口点,并为其暴露于82端口。该入口点会指示其它容器在哪个端口公开
- "--entrypoints.web-stagin.address=:82"
ports:
- 2080:80
- 2081:81
- 2082:82
就是上面这几行,我们有3个环境,那可以配置3个EntryPoint,Traefik也是一个docker服务,也是以容器运行,所以它的内部端口是80,81,82,暴露给外部的是2080,2081,2082, 我们想怎么做端口规划就怎么配置。
我们的3个EntryPoint配置应该在traefik dashboard界面上看得见,上图我的实际配置稍有不同而涂抹掉了,方法是一样的。
5. Routers
路由器在EntryPoint和Service之间,自然是路由分发的作用, 同理,我们不要去纠结它的架构和功能细节,主要在使用上怎么配置让路由正确生效。
这里不需要在Traefik的docker-compose.yml里配置,而是在各个Docker Swarm上部署的应用程序docker-compose.yml里配置,Traefik会自动扫描发现并让路由配置生效,这个方式非常好,也是一种自动注册与发现。例如我在用户中心管理系统的docker-compose.yml里这样配置:
labels:
- "traefik.enable=true"
# 路由规则
- "traefik.http.routers.usercenter-${SCOPE}.rule=PathPrefix(`/uc`)"
# 中间件引用
- "traefik.http.routers.usercenter-${SCOPE}.middlewares=auth-${SCOPE}"
# 入口点
- "traefik.http.routers.usercenter-${SCOPE}.entrypoints=web-${SCOPE}"
# 服务负载均衡
- "traefik.http.services.usercenter-${SCOPE}.loadbalancer.server.port=80"
# 中间件定义:委派认证中间件(此处定义,其他服务直接引用,不能重复定义)
- "traefik.http.middlewares.auth-${SCOPE}.forwardauth.address=http://usercenter-${SCOPE}_authservice/auth/"
- "traefik.http.middlewares.auth-${SCOPE}.forwardauth.authResponseHeaders=user_id,user_name"
- "traefik.http.middlewares.auth-${SCOPE}.forwardauth.trustForwardHeader=true"
Routers和其它三个模块都有交互,处在中心位置,所以它的配置涉及了入口点EntryPoint、路由规则rule、中间件Middlewares和服务services负载均衡的配置,每个应用程序服务配置只需前面5行,下面的中间件定义,下面再讲。
我们在traefik dashboard上可以看到路由器的生效配置:
6. Middlewares
Middleware中间件附着于路由器上,它能够修改经过路由器的请求包和应答包,而且可以配置很多个。有两类中间件:HTTP和TCP,官网文档:Traefik Proxy Middleware Overview - Traefik
例如,我利用ForwardAuth中间件来做认证鉴权,上面docker-compose.yml的中间件定义就是如此:
# 中间件定义:委派认证中间件(此处定义,其他服务直接引用,不能重复定义)
- "traefik.http.middlewares.auth-${SCOPE}.forwardauth.address=http://usercenter-${SCOPE}_authservice/auth/"
- "traefik.http.middlewares.auth-${SCOPE}.forwardauth.authResponseHeaders=user_id,user_name"
- "traefik.http.middlewares.auth-${SCOPE}.forwardauth.trustForwardHeader=true"
中间件定义只要在用户认证中心的系统里定义一次就可以了,具体你在哪个服务里定义随你的便,但是要符合架构定义。
在其它业务系统里如果需要进行用户认证鉴权,就在docker-compose.yml加入一行引用即可。例如:
# 中间件引用
- "traefik.http.routers.usercenter-${SCOPE}.middlewares=auth-${SCOPE}"
也就是我的usercentor服务引用了auth中间件,外部进来的HTTP请求会被Router先发往http://usercenter-${SCOPE}_authservice/auth/,
auth组件返回200才前传给后面的service组件,不然就会返回认证失败,如401、403错误码。
我们在traefik dashboard上可以看到中间件的生效配置:
7. Services
这里的服务是Traefik的服务组件,负责把请求分发到后端实际的服务组件去,同时做好负载均衡,具体参见官方文档:Traefik Services Documentation - Traefik。
# 容器内的入口点,treafik无法获知你的服务的访问入口点,所以你必须以此告诉Traefik
# Traefik同时会在此对横向拓展的容器建立负载均衡
# 更多见https://docs.traefik.io/routing/services/
- "traefik.http.services.demo-service-${SCOPE}.loadbalancer.server.port=80"
同样,在traefik dashboard界面上可以看到服务的配置:
8. 云原生部署架构
Traefik的功能细节有很多,具体不再累述,那么云原生知识点讲的网关这里,基本的环境部署技术点也算出来了,对一个小型云原生应用系统基本可以运作了。例如我们可能有这样一个部署架构:
我们的系统已经容器化、集群化、支持服务编排、具有服务注册和发现机制、具有负载均衡能力、对外提供API网关能力,使用的技术也比较简单,小团队都可以hold得住。
9. 总结
Traefik是一个采用Go语言开发的高性能、易用的微服务API网关,支持多种后端服务,如Docker、Kubernetes等,它有4个主要组件EntryPoints、Routers、Middlewares和Services, 提供路由、服务发现、负载均衡和大量好用的中间件功能。