科普一个 Star 数为 28.5k 的云原生网关 —— Traefik

科普一个 Star 数为 28.5k 的云原生网关 —— Traefik

Traefik (发音和 traffic 相同,采用 Golang 编写)是一个云原生的新型的 HTTP 反向代理、负载均衡软件。它负责接收系统的请求,然后使用合适的组件来对这些请求进行处理。Traefik 兼容所有主流的集群技术,比如 Kubernetes,Docker,Docker Swarm,AWS,Mesos,Marathon,等等;并且可以同时处理多种方式。(甚至可以用于在裸机上运行的比较旧的软件。)

官网地址:https://docs.traefik.io/。代码托管地址:https://github.com/containous/traefik,截止目前 Star 数为 28.5k。

使用 Traefik,不需要维护或者同步一个独立的配置文件:因为一切都会自动配置,实时操作的(无需重新启动,不会中断连接)。使用 Traefik,你可以花更多的时间在系统的开发和新功能上面,而不是在配置和维护工作状态上面花费大量时间。

Traefik 也被称之为边缘路由器(Edge Router),是你整个平台的大门,拦截并路由每个传入的请求:它知道所有的逻辑和规则,这些规则确定哪些服务处理哪些请求;传统的反向代理需要一个配置文件,其中包含路由到你服务的所有可能路由,而 Traefik 会实时检测服务并自动更新路由规则,可以自动服务发现。

当启动 Traefik 时,需要定义 Entrypoints(入口点),然后根据连接到这些 Entrypoints 的路由(Routes)来分析传入的请求,来查看他们是否与一组规则(Rules)相匹配,如果匹配,则路由可能会将请求通过一系列中间件(Middlewares,相当于Java中的拦截器Interceptor/过滤器Filter的概念)转换过后再转发到你的服务上去。在了解 Traefik 之前有几个核心概念我们必须要了解:

  • Providers: 用来自动发现平台上的服务,可以是编排工具、容器引擎或者 key-value 存储等,比如 Docker、Kubernetes、File
  • Entrypoints: 监听传入的流量(端口等…),是网络入口点,它们定义了接收请求的端口(HTTP 或者 TCP)。
  • Routers:分析请求(host, path, headers, SSL, …),负责将传入请求连接到可以处理这些请求的服务上去。
  • Services: 将请求转发给你的应用(load balancing, …),负责配置如何获取最终将处理传入请求的实际服务。
  • Middlewares: 中间件,用来修改请求或者根据请求来做出一些判断(authentication, rate limiting, headers, …),中间件被附件到路由上,是一种在请求发送到你的服务之前(或者在服务的响应发送到客户端之前)调整请求的一种方法。

Traefik 主要特征如下:

  • 支持动态加载配置文件和优雅重启
  • 自动的服务发现与负载均衡
  • 自动配置ACME(Let’s Encrypt)证书功能
  • 支持熔断、重试
  • 内置Web UI,管理相对方便
  • 支持WebSocket、HTTP/2、gRPC
  • metrics 的支持(Rest、Prometheus、Datalog、Statsd、InfluxDB)
  • 支持K8S、docker swarm等,和容器结合比较紧密

接下来讲一下它的安装、基本功能以及配置。Traefik 在 v1 与 v2 版本间差异过大,本文采用了 v2。Traefik v2.0 之后的版本在修改了很多bug之后也增加了新的特性,比如增加了TCP的支持,并且更换了新的WEB UI界面。

快速开始

我们使用 traefik:v2.2.0 作为镜像启动 traefik 服务。新建 traefik-v2.2.0.yaml 配置文件,内容如下:

version: '3'
services:
reverse-proxy:
image: traefik:2.2.0
# Enables the web UI and tells Traefik to listen to docker
# 启用 webUI 并告诉 Traefik 去监听docker的容器实例
command: --api.insecure=true --providers.docker
ports:
# Traefik暴露的http端口
- "80:80"
# webUI暴露的端口(必须指定--api.insecure=true才可以访问)
- "8080:8080"
volumes:
# 指定docker的sock文件来让traefik获取docker的事件,从而实现动态负载均衡
- /var/run/docker.sock:/var/run/docker.sock

使用 docker-compose 命令开启 Traefik 服务:

$ docker-compose -f traefik-v2.2.0.yaml up -d reverse-proxy

查看使用 docker-compose启动的应用:

$ docker-compose -f traefik-v2.2.0.yaml ps
Name Command State Ports
-------------------------------------------------------------------------------------------------------------
traefik_reverse-proxy_1 /entrypoint.sh --api.insec ... Up 0.0.0.0:80->80/tcp, 0.0.0.0:8080->8080/tcp

Traefik 一般需要一个配置文件来管理路由、服务、证书等。上面示例中,我们可以通过 docker 启动 Traefik 时来挂载配置文件。在 Traefik 中的配置可以使用两种不同的方式:

  • 动态配置:完全动态的路由配置
  • 静态配置:启动配置

静态配置中的元素(这些元素不会经常更改)连接到 Providers 并定义 Treafik 将要监听的 Entrypoints。在 Traefik 中有三种方式定义静态配置:在配置文件中、在命令行参数中、通过环境变量传递。动态配置包含定义系统如何处理请求的所有配置内容,这些配置是可以改变的,而且是无缝热更新的,没有任何请求中断或连接损耗。

Traefik 的配置结构图如下:

使用 docker run traefik[:version] --help可查看 Traefik 的配置参数。

我们可以使用 http://localhost:8080/ 来访问 Traefik 官方Dashboard,效果图如下:

路由

接下来我们使用 docker-compose 启动一个简单的 http 服务,配置文件(test-service.yaml)如下:

version: '3'
services:
whoami:
image: containous/whoami
labels:
- "traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)"

启动服务:

$ docker-compose -f test-service.yaml up -d whoami
$ docker-compose -f test-service.yaml ps
Name Command State Ports
-------------------------------------------
traefik_whoami_1 /whoami Up 80/tcp

whoami 这个 http 服务做了什么事情呢?1. 暴露了一个 http 服务,主要提供一些 header 以及 ip 信息;2. 配置了容器的 labels,设置该服务的 Host 为 whoami.docker.localhost,给 traefik 提供标记。

此时我们可以通过 curl -H Host:whoami.docker.localhost http://localhost 来访问 whoami 服务,我们使用 curl 做测试:

$ curl -H Host:whoami.docker.localhost http://localhost
Hostname: e9a4bd2e0a7a
IP: 127.0.0.1
IP: 172.19.0.3
RemoteAddr: 172.19.0.2:33358
GET / HTTP/1.1
Host: whoami.docker.localhost
User-Agent: curl/7.54.0
Accept: */*
Accept-Encoding: gzip
X-Forwarded-For: 172.19.0.1
X-Forwarded-Host: whoami.docker.localhost
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Server: f660478db1e4
X-Real-Ip: 172.19.0.1

服务正常访问。此时如果把 Host 配置为自己的域名,则已经可以使用自己的域名来提供服务。在Dashboard中可以看到对应的 HTTP Routers:

如果不设置 Host,访问是会失败的。

$ curl -i http://localhost
HTTP/1.1 404 Not Found
Content-Type: text/plain; charset=utf-8
X-Content-Type-Options: nosniff
Date: Wed, 29 Apr 2020 09:44:56 GMT
Content-Length: 19

404 page not found

细表罗列了 Traefik 可用的路由规则:

规则 描述
Headers(key, value) 检查 headers 中是否有一个键为 key值为value`的键值对
HeadersRegexp(key, regexp) 检查 headers 中是否有一个键为 key,值匹配正则表达式 regexp的键值对
Host(example.com, …) 检查请求的域名是否包含在给定的 domains 域名中
HostRegexp(example.com, {subdomain:[a-z]+}.example.com, …) 检查请求的域名是否匹配给定的 regexp正则表达式
Method(GET, …) 检查请求的方法是否包含在给定的 methods (GET, POST, PUT, DELETE, PATCH)
Path(/path, /articles/{cat:[a-z]+}/{id:[0-9]+}, …) 匹配确定的请求路径,它接受一系列文字和正则表达式路径
PathPrefix(/products/, /articles/{cat:[a-z]+}/{id:[0-9]+}) 匹配请求前缀路径,它接受一系列文字和正则表达式前缀路径
Query(foo=bar, bar=baz) 匹配查询字符串参数,接受key=value的键值对序列

我们可以使用 docker-compose up --scale命令来对容器横向扩容,下面将单机扩容成2台:

$ docker-compose -f test-service.yaml up -d --scale whoami=2
WARNING: Found orphan containers (traefik_reverse-proxy_1) for this project. If you removed or renamed this service in your compose file, you can run this command with the --remove-orphans flag to clean it up.
Starting traefik_whoami_1 ... done
Creating traefik_whoami_2 ... done

此时再访问curl http://localhost -H Host:whoami.docker.localhost时就会自动负载均衡到2个不同的实例上去了。

在 Dashboard 中也有相关记录:

References

  1. https://docs.traefik.io/
  2. https://www.cnblogs.com/xiao987334176/p/12447783.html
  3. https://www.qikqiak.com/post/traefik-2.1-101/
  4. https://github.com/shfshanyue/op-note/blob/master/traefik.md

欢迎支持笔者的作品《深入理解Kafka: 核心设计与实践原理》和《RabbitMQ实战指南》,同时欢迎关注笔者的微信公众号:朱小厮的博客(ID: hiddenkafka)。
本文作者: 朱小厮

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×