你所不了解的 Traefik


picture.image

 在之前的文章中,我们简单介绍了关于 Traefik 的相关概念及组件原理机制,具体可参考:[为什么选择 Traefik Ingress ?](http://mp.weixin.qq.com/s?__biz=MzA4MjM3NzE5MQ==&mid=2649662798&idx=1&sn=d31bd14e3038eb4f42397457db4a2f28&chksm=879ca5c6b0eb2cd089aaa18b0b29ddceb8a6b4af70147169561e8f0d1bfbcfa1ccf7ea4ddbad&scene=21#wechat_redirect)






 作为一款革新的边缘路由器 ,意味着 Traefik 是所构建的整个应用平台的守卫者,拦截并路由每一个接入的请求:基于所设定的逻辑和规则,以确定哪些服务处理对应的请求。关于 Traefik 的模型画像,具体可参考如下所示:

picture.image

 当然,除了所具备的服务代理特征之外, Traefik 同时也拥有“服务发现”功能机制,其

动态检测后端服务状态信息并实时更新路由规则,从而达到服务治理之功效。

 我们以 

Docker Provider 场景作为参考模型对 Traefik 生态进行简要的剖析,以使得大家能够深入了解 Traefik 相关特性。

 如下场景中,我们基于最新版的 Traefik v2.5.2 镜像为例,进行相关相关实例的部署及运行,具体如下所示:

          
[administrator@JavaLangOutOfMemory ~] % vi docker-compose.yaml 
          
version: '3'
          
services:
          
  reverse-proxy:
          
    image: traefik:latest
          
    # 开启 web UI 并且 Traefik 监听 Docker
          
    command: --api.insecure=true --providers.docker
          
    ports:
          
      # HTTP 端口
          
      - "80:80"
          
      # Web UI 端口(通过 --api.insecure=true 启用)
          
      - "8080:8080"
          
    volumes:
          
      # Traefik 监听 Docker 事件
          
      - /var/run/docker.sock:/var/run/docker.sock
      
 然后,我们运行此实例,具体如下:

        
            

          [administrator@JavaLangOutOfMemory ~] % docker-compose up -d reverse-proxy
        
      

          
[administrator@JavaLangOutOfMemory ~] %  curl -i http://192.168.56.114:8080/api/rawdata?json
          
HTTP/1.1 200 OK
          
Content-Type: application/json
          
Date: Thu, 09 Sep 2021 02:05:08 GMT
          
Content-Length: 1361
          

          
{"routers":{"api@internal":{"entryPoints":["traefik"],"service":"api@internal","rule":"PathPrefix(`/api`)","priority":2147483646,"status":"enabled","using":["traefik"]},"dashboard@internal":{"entryPoints":["traefik"],"middlewares":["dashboard_redirect@internal","dashboard_stripprefix@internal"],"service":"dashboard@internal","rule":"PathPrefix(`/`)","priority":2147483645,"status":"enabled","using":["traefik"]},"reverse-proxy-traefik@docker":{"entryPoints":["http"],"service":"reverse-proxy-traefik","rule":"Host(`reverse-proxy-traefik`)","status":"enabled","using":["http"]}},"middlewares":{"dashboard_redirect@internal":{"redirectRegex":{"regex":"^(http:\\/\\/(\\[[\\w:.]+\\]|[\\w\\._-]+)(:\\d+)?)\\/$","replacement":"${1}/dashboard/","permanent":true},"status":"enabled","usedBy":["dashboard@internal"]},"dashboard_stripprefix@internal":{"stripPrefix":{"prefixes":["/dashboard/","/dashboard"]},"status":"enabled","usedBy":["dashboard@internal"]}},"services":{"api@internal":{"status":"enabled","usedBy":["api@internal"]},"dashboard@internal":{"status":"enabled","usedBy":["dashboard@internal"]},"noop@internal":{"status":"enabled"},"reverse-proxy-traefik@docker":{"loadBalancer":{"servers":[{"url":"http://172.20.0.2:80"}],"passHostHeader":true},"status":"enabled","usedBy":["reverse-proxy-traefik@docker"],"serverStatus":{"http://172.20.0.2:80":"UP"}}}}
      
 此时,我们也可以通过浏览器访问 

http://192.168.56.114:8080/api/rawdata 接口来查看 Traefik 的 API 原始数据。

 接下来,我们部署一个 Demo 服务,基于 Traefik 进行路由创建,具体如下所示:  

          
version: '3'
          

          
services:
          
  reverse-proxy:
          
    # 官方的 Traefik 2.0 Docker 镜像
          
    image: traefik:latest
          
    # 开启 web UI 并且告诉 Traefik 监听 Docker
          
    command: --api.insecure=true --providers.docker
          
    ports:
          
      # HTTP 端口
          
      - "80:80"
          
      # Web UI 端口(通过 --api.insecure=true 启用)
          
      - "8080:8080"
          
    volumes:
          
      # 这样 Traefik 可以监听 Docker 事件
          
      - /var/run/docker.sock:/var/run/docker.sock
          

          
  whoami:
          
    # 一个通过 API 暴露其 IP 地址的容器
          
    image: containous/whoami
          
    labels:
          
      - "traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)"
      
 基于上面的 Yaml文件中,我们定义了 一个名称为 whoami 简单的 web 服务,此服务会打印部署的机器的相关信息(IP 地址、主机等等)。然后我们使用以下命令启动 whoami 服务,具体:

        
            

          [administrator@JavaLangOutOfMemory ~] % docker-compose up -d whoami
        
      
 此时,我们再次进行请求 Api 接口,结果如下所示:

          
[administrator@JavaLangOutOfMemory ~] % curl -i http://192.168.56.114:8080/api/rawdata?json
          
HTTP/1.1 200 OK
          
Content-Type: application/json
          
Date: Thu, 09 Sep 2021 02:09:25 GMT
          
Content-Length: 1705
          

          
{"routers":{"api@internal":{"entryPoints":["traefik"],"service":"api@internal","rule":"PathPrefix(`/api`)","priority":2147483646,"status":"enabled","using":["traefik"]},"dashboard@internal":{"entryPoints":["traefik"],"middlewares":["dashboard_redirect@internal","dashboard_stripprefix@internal"],"service":"dashboard@internal","rule":"PathPrefix(`/`)","priority":2147483645,"status":"enabled","using":["traefik"]},"reverse-proxy-traefik@docker":{"entryPoints":["http"],"service":"reverse-proxy-traefik","rule":"Host(`reverse-proxy-traefik`)","status":"enabled","using":["http"]},"whoami@docker":{"entryPoints":["http"],"service":"whoami-traefik","rule":"Host(`whoami.docker.localhost`)","status":"enabled","using":["http"]}},"middlewares":{"dashboard_redirect@internal":{"redirectRegex":{"regex":"^(http:\\/\\/(\\[[\\w:.]+\\]|[\\w\\._-]+)(:\\d+)?)\\/$","replacement":"${1}/dashboard/","permanent":true},"status":"enabled","usedBy":["dashboard@internal"]},"dashboard_stripprefix@internal":{"stripPrefix":{"prefixes":["/dashboard/","/dashboard"]},"status":"enabled","usedBy":["dashboard@internal"]}},"services":{"api@internal":{"status":"enabled","usedBy":["api@internal"]},"dashboard@internal":{"status":"enabled","usedBy":["dashboard@internal"]},"noop@internal":{"status":"enabled"},"reverse-proxy-traefik@docker":{"loadBalancer":{"servers":[{"url":"http://172.20.0.2:80"}],"passHostHeader":true},"status":"enabled","usedBy":["reverse-proxy-traefik@docker"],"serverStatus":{"http://172.20.0.2:80":"UP"}},"whoami-traefik@docker":{"loadBalancer":{"servers":[{"url":"http://172.20.0.3:80"}],"passHostHeader":true},"status":"enabled","usedBy":["whoami@docker"],"serverStatus":{"http://172.20.0.3:80":"UP"}}}}
      
 通过查看 

/api/rawdata 接口返回的数据,我们发现 Traefik 已自动检测到新的容器并更新了相应的配置。前面在介绍 Traefik 的时候, 我们说过,当 Traefik 检测到新服务时,它会自动创建相应的路由,然后我们可以访问相应的路由。此时,我们借助 Curl 工具进行验证,具体如下所示:


          
[administrator@JavaLangOutOfMemory ~] % curl -H Host:whoami.docker.localhost http://127.0.0.1
          
Hostname: d1078dbb0332
          
IP: 127.0.0.1
          
IP: 172.20.0.3
          
RemoteAddr: 172.20.0.2:37580
          
GET / HTTP/1.1
          
Host: whoami.docker.localhost
          
User-Agent: curl/7.29.0
          
Accept: */*
          
Accept-Encoding: gzip
          
X-Forwarded-For: 172.20.0.1
          
X-Forwarded-Host: whoami.docker.localhost
          
X-Forwarded-Port: 80
          
X-Forwarded-Proto: http
          
X-Forwarded-Server: 814dfa472b98
          
X-Real-Ip: 172.20.0.1
      
 接下来,我们对  whoami 服务进行扩容,以验证 Traefik 的负载均衡功能,具体操作如下所示:

          
[administrator@JavaLangOutOfMemory ~] % docker-compose up -d --scale whoami=4
          
traefik_reverse-proxy_1 is up-to-date
          
Creating traefik_whoami_2 ... done
          
Creating traefik_whoami_3 ... done
          
Creating traefik_whoami_4 ... done
      
 此时,我们看一下扩容完成后当前我们的服务运行的容器状况,如下所示:

          
[administrator@JavaLangOutOfMemory ~] % docker-compose ps
          
         Name                        Command               State                                     Ports                                   
          
---------------------------------------------------------------------------------------------------------------------------------------------
          
traefik_reverse-proxy_1   /entrypoint.sh --api.insec ...   Up      0.0.0.0:80->80/tcp,:::80->80/tcp, 0.0.0.0:8080->8080/tcp,:::8080->8080/tcp
          
traefik_whoami_1          /whoami                          Up      80/tcp                                                                    
          
traefik_whoami_2          /whoami                          Up      80/tcp                                                                    
          
traefik_whoami_3          /whoami                          Up      80/tcp                                                                    
          
traefik_whoami_4          /whoami                          Up      80/tc
      

          
[administrator@JavaLangOutOfMemory ~] % curl -i http://192.168.56.114:8080/api/rawdata?json  
          
HTTP/1.1 200 OK
          
Content-Type: application/json
          
Date: Thu, 09 Sep 2021 02:28:35 GMT
          
Content-Length: 1882
          

          
{"routers":{"api@internal":{"entryPoints":["traefik"],"service":"api@internal","rule":"PathPrefix(`/api`)","priority":2147483646,"status":"enabled","using":["traefik"]},"dashboard@internal":{"entryPoints":["traefik"],"middlewares":["dashboard_redirect@internal","dashboard_stripprefix@internal"],"service":"dashboard@internal","rule":"PathPrefix(`/`)","priority":2147483645,"status":"enabled","using":["traefik"]},"reverse-proxy-traefik@docker":{"entryPoints":["http"],"service":"reverse-proxy-traefik","rule":"Host(`reverse-proxy-traefik`)","status":"enabled","using":["http"]},"whoami@docker":{"entryPoints":["http"],"service":"whoami-traefik","rule":"Host(`whoami.docker.localhost`)","status":"enabled","using":["http"]}},"middlewares":{"dashboard_redirect@internal":{"redirectRegex":{"regex":"^(http:\\/\\/(\\[[\\w:.]+\\]|[\\w\\._-]+)(:\\d+)?)\\/$","replacement":"${1}/dashboard/","permanent":true},"status":"enabled","usedBy":["dashboard@internal"]},"dashboard_stripprefix@internal":{"stripPrefix":{"prefixes":["/dashboard/","/dashboard"]},"status":"enabled","usedBy":["dashboard@internal"]}},"services":{"api@internal":{"status":"enabled","usedBy":["api@internal"]},"dashboard@internal":{"status":"enabled","usedBy":["dashboard@internal"]},"noop@internal":{"status":"enabled"},"reverse-proxy-traefik@docker":{"loadBalancer":{"servers":[{"url":"http://172.20.0.2:80"}],"passHostHeader":true},"status":"enabled","usedBy":["reverse-proxy-traefik@docker"],"serverStatus":{"http://172.20.0.2:80":"UP"}},"whoami-traefik@docker":{"loadBalancer":{"servers":[{"url":"http://172.20.0.4:80"},{"url":"http://172.20.0.5:80"},{"url":"http://172.20.0.3:80"},{"url":"http://172.20.0.6:80"}],"passHostHeader":true},"status":"enabled","usedBy":["whoami@docker"],"serverStatus":{"http://172.20.0.3:80":"UP","http://172.20.0.4:80":"UP","http://172.20.0.5:80":"UP","http://172.20.0.6:80":"UP"}}}}
      
 此时,我们请求4次,以查看 Traefik 在四个实例之间的负载均衡,具体命令如下所示:

          
[administrator@JavaLangOutOfMemory ~] % curl -H Host:whoami.docker.localhost http://127.0.0.1
          
# 第一次
          
Hostname: 50f70b1ccace
          
IP: 127.0.0.1
          
IP: 172.20.0.4
          
RemoteAddr: 172.20.0.2:40000
          
...
          
# 第二次
          
Hostname: 8c2204231f98
          
IP: 127.0.0.1
          
IP: 172.20.0.5
          
RemoteAddr: 172.20.0.2:39660
          
...
          
# 第三次
          
Hostname: d1078dbb0332
          
IP: 127.0.0.1
          
IP: 172.20.0.3
          
RemoteAddr: 172.20.0.2:37600
          
...
          
# 第四次
          
Hostname: f1cf5b632fde
          
IP: 127.0.0.1
          
IP: 172.20.0.6
          
RemoteAddr: 172.20.0.2:50384
          
...
      
 基于此,我们通过 http://192.168.56.114:8080/dashboard/#/ 访问 Traefik Web  UI 以观测不同路由请求、服务、中间件以及其他相关联信息。具体如下所示:

picture.image

 在整个首页,我们可以看到 Traefik 所支持的不同协议的请求、服务类型,涉及 HTTP、TCP 以及 UDP 等。同时,显示不同类型的 Providers 信息,涉及 Docker、K8S 及其他相关信息等。基于 HTTP 协议,可以看到所建立的 4个路由规则,5个服务以及2个自定义中间件。以 Middlewares 为例,我们点击基于 HTTP 协议的 “Middlewares ” 版块的“Explore” 链接,可以清新地看到当前所部署应用所形成的链路拓扑调用链,具体如下所示:

picture.image

 针对 Traefik Middlewares 的自定义开发相关实践,大家若感兴趣的话,可参考之前文章:[Traefik Middleware 插件实践](http://mp.weixin.qq.com/s?__biz=MzA4MjM3NzE5MQ==&mid=2649662818&idx=1&sn=01d01e4cdf8706e31a014a4aa260a8d1&chksm=879ca5eab0eb2cfc823bcb5dee5b3fc278a49961404351cd0b3c0910aefb15e7e4c9721386d1&scene=21#wechat_redirect),以便使的大家能够了解 Traefik 的功能之丰富。





 针对证书的自定续订功能,也是 Traefik 组件的强大功能之一,基于此,我们将分别基于 HTTP 和 DNS 两方面进行简要阐述。

picture.image

 基于上述场景,其简要的活动流程解析为:






 Traefik 使用 ACME(一种协议(精确约定的通信方式),用于协商来自 LE 的证书。它是 Traefik 的一部分) 向 LE(Let's Encrypt,一种提供免费证书的服务)请求特定域的证书,如,example.com。LE 使用一些随机生成的文本进行回答,Traefik 将这些文本放在服务器上的特定位置。LE 然后询问DNS Internet 服务器,例如 .com,该服务器指向某个 IP 地址。LE 通过端口 80/443 查看包含该随机文本的文件的 IP 地址。






 如果存在,那么这证明了请求证书的人同时控制服务器和域,因为它显示了对 DNS 记录的控制。证书已颁发,有效期为3个月,剩余不足30天时,Traefik将自动尝试续订。





 基于 HttpChallenge 的优势在于能够获得通配符证书。这些是验证所有子域 *.example.com 的证书

此外,不需要打开任何端口。 其相关文件配置如下所示:


          
## STATIC CONFIGURATION
          
log:
          
  level: INFO
          

          
api:
          
  insecure: true
          
  dashboard: true
          

          
entryPoints:
          
  web:
          
    address: ":80"
          
  websecure:
          
    address: ":443"
          

          
providers:
          
  docker:
          
    endpoint: "unix:///var/run/docker.sock"
          
    exposedByDefault: false
          

          
certificatesResolvers:
          
  lets-encr:
          
    acme:
          
      #caServer: https://acme-staging-v02.api.letsencrypt.org/directory
          
      storage: acme.json
          
      email: whatever@gmail.com
          
      httpChallenge:
          
        entryPoint: web
          

      

picture.image

 基于此场景,Traefik 使用 ACME 向 LE 请求特定域的证书,如 example.com。LE 回答一些随机生成的文本,Traefik 将其作为新的 DNS TXT 记录。然后,LE 检查 example.com DNS 记录以查看文本是否存在。




 如果它存在,那么这证明了请求证书的人控制了域,证书有效期为3个月。Traefik将在剩余时间不足30天时自动尝试续订。




 相比基于 HttpChallenge ,Traefik 需要能够对 DNS 记录进行自动更新,因此需要任何管理 DNS 站点的人对此提供支持。这就是为什么要使用 Cloudflare。其相关文件配置如下所示:

          
## STATIC CONFIGURATION
          
log:
          
  level: INFO
          

          
api:
          
  insecure: true
          
  dashboard: true
          

          
entryPoints:
          
  web:
          
    address: ":80"
          
  websecure:
          
    address: ":443"
          

          
providers:
          
  docker:
          
    endpoint: "unix:///var/run/docker.sock"
          
    exposedByDefault: false
          

          
certificatesResolvers:
          
  lets-encr:
          
    acme:
          
      #caServer: https://acme-staging-v02.api.letsencrypt.org/directory
          
      email: whatever@gmail.com
          
      storage: acme.json
          
      dnsChallenge:
          
        provider: cloudflare
          
        resolvers:
          
          - "1.1.1.1:53"
          
          - "8.8.8.8:53"
          

      
 除上述特性外,在 Traefik V2.3.x 及后续的版本中,引入了一系列最新功能,包括 Traefik 插件系统、与 Traefik Pilot 的集成、对 Amazon ECS 的支持等,使的 Traefik 生态组件功能越来越丰富,应用场景越来越广泛。

picture.image

 除了上述所展现的实例、告警、监控信息功能之外,Traefik Pilot 也支持自定义“插件”开发功能,其提供了丰富的插件类型,可结合实际的业务场景进行适应性装配,具体如下所示:

picture.image

 综上所述,作为一款云原生边缘路由器,Traefik 功能已经能够满足绝大部分的业务场景,同时,也落地不少的行业及应用。或许,在下一个版本中,我们将迎来更为强大的 Traefik 生态,包括对谷歌团队最新推出的 Kubernetes Service API 的支持,以及用于在 Traefik Mesh 中支持 mTLS 的功能。除上述外,其他可能潜在的功能特性也会随着市场的不断变化而应运而生,最后,让我们拭目以待~
参考资料
  • EOF -

如果您喜欢本文,欢迎 点赞 、 在看 、 留言 ,或者点击 右上角 ,把文章分享到朋友圈~~~

0
0
0
0
评论
未登录
暂无评论