Traefik 微服务 API 网关教程(二)

随笔4个月前发布 手机
63 0 0

原文:Traefik API Gateway for Microservices

协议:CC BY-NC-SA 4.0

五、日志、请求跟踪和指标

业务运营执行应用监控。该流程旨在发现并修复应用停机,以免影响正常业务运营。传统上,团队执行简单的检查,如流程启动/关闭或端口打开/关闭。但是这些支票还不够好。随着时间的推移,已经开发了许多工具来改进应用监控过程。该过程包括捕获使用指标和执行分析。但是,仅仅依靠应用监控是一种软弱的做法。应用监控只能提供关于持续应用问题的通知。下一步是确定根本原因

根本原因主要与上下文有关:一个新特性出现故障,或者规范中遗漏了一些控件,或者用户正在执行一个有效的请求,导致“内存不足”,等等。我们无法仅通过查看通知得出结论。我们需要更多的信息来确定根本原因。这就是所谓的失败背景

上下文是通过首先查看应用日志(如果有)来创建的。堆栈跟踪提供了可能的错误的线索,但是错误是由特定的边缘场景引起的。这些边缘场景由用户数据和应用状态定义。如果已经捕获了用户数据,则从请求访问日志中确定用户数据。所有这些说起来容易做起来难。

多年来,企业应用环境变得越来越复杂。以前的实践不足以处理停机。Google 推出了请求追踪的做法。请求跟踪捕获了跨不同分布式系统的用户请求流。这个互补的过程有助于预测失败的场景和涉及的系统。

总之,日志、度量和跟踪是互补的实践(见图 5-1 )用于不同的目的。在大修期间,这些实践中没有一个是单独足够的。因此,应用监控的简单实践已经从单个应用状态转变为整个生态系统的整体视图。这也被称为可观测性。可观察性包括度量、日志和跟踪的收集、可视化和分析,以获得对系统运行的整体理解。

Traefik 微服务 API 网关教程(二)

图 5-1

可观察性数据

像 Twitter、Google、优步等公司,开创了可观察性,定义了基于以下支柱的完整实践。

  • 应用和业务指标

  • 日志

  • 分布式跟踪

  • 警报和通知

  • 形象化

Note

与监控相比,可观察性项目为什么有问题,监控只是告诉什么时候有问题。

作为 API 网关,Traefik 是所有外部发起的用户请求的单一入口点。它必须与企业现有的解决方案集成,以捕获所有的请求流和指标。为了捕获端到端的请求流,Traefik 需要生成请求范围,并将其发送给跟踪后端系统。Traefik 还需要生成访问日志和基于请求的度量,以建立对分布式系统行为的可见性。本章通过一个示例 HTTP 应用来讨论这些特性。

先决条件

在本章中,我们使用一个 HTTP 服务的例子。我们部署和配置 httpbin 服务( https://github.com/postmanlabs/httpbin )来服务我们的目的。这是一个开源应用。服务是用 Python 写的。我们需要一个 Python 运行时来运行应用。部署的服务是使用 Traefik 配置的。

Note

这是一个可选步骤。这是一个用于验证配置更改的示例服务。如果您有正在运行的服务,可以跳过这一步。

首先,检查所需的python, pip,virtualenv命令。

~/Projects$ python3 --version
Python 3.8.0

~/Projects$ pip3 --version
pip 19.2.3 from /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/pip (python 3.8)

~/Projects$ virtualenv --version
16.7.8

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

确保您拥有 Python 和 pip 的 3.x 版本。如果命令失败,您需要安装所需的软件。Python、pip 和 virtualenv 的安装说明超出了本书的范围。

下一步,我们从发布页面 https://github.com/postmanlabs/httpbin/releases 下载一个版本的 httpbin 服务(见图 5-2 )。在撰写本文时,0.6.1 是最新的发布版本。

Traefik 微服务 API 网关教程(二)

图 5-2

httpbin 版本

下载发布的工件,并将它们解压缩到一个目录中。该目录包含源文件、应用许可证、构建文件等等。目的是编译代码并从中获得一个二进制工件。

~/Projects/httpbin-0.6.1$ ls -1
AUTHORS
Dockerfile
LICENSE
MANIFEST.in
Pipfile
Pipfile.lock
Procfile
README.md
app.json
build
dist
httpbin
httpbin.egg-info
setup.cfg
setup.py
test_httpbin.py
tox.ini

Traefik 微服务 API 网关教程(二)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

该服务是使用setuptools构建的。您可以部署和运行服务,如下所述。

  1. 创建一个虚拟环境,然后激活它。

  2. develop模式构建服务。

    (venv) ~/Projects/httpbin-0.6.1$ python setup.py develop
    running develop
    running egg_info
    writing httpbin.egg-info/PKG-INFO
    ####                     ####
    #### removed for brevity ####
    ####                     ####
    /Users/rahulsharma/Projects/httpbin-0.6.1/venv/bin
    Using /Users/rahulsharma/Projects/httpbin-0.6.1/venv/lib/python3.8/site-packages
    Finished processing dependencies for httpbin==0.6.1
    (venv) ~/Projects/httpbin-0.6.1$
    
    

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  3. 在 Gunicorn 中部署应用.

~/Projects/httpbin-0.6.1$ virtualenv venv
Using base prefix '/Library/Frameworks/Python.framework/Versions/3.8'
New python executable in /Users/rahulsharma/Projects/httpbin-0.6.1/venv/bin/python3.8
Also creating executable in /Users/rahulsharma/Projects/httpbin-0.6.1/venv/bin/python
Installing setuptools, pip, wheel...
done.
~/Projects/httpbin-0.6.1$ source venv/bin/activate
(venv) ~/Projects/httpbin-0.6.1$

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
(venv) ~/Projects/httpbin-0.6.1$ gunicorn -b 0.0.0.0 httpbin:app
[2020-06-12 14:35:04 +0530] [67528] [INFO] Starting gunicorn 20.0.4
[2020-06-12 14:35:04 +0530] [67528] [INFO] Listening at: http://0.0.0.0:8000 (67528)
[2020-06-12 14:35:04 +0530] [67528] [INFO] Using worker: sync
[2020-06-12 14:35:04 +0530] [67530] [INFO] Booting worker with pid: 67530

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

httpbin 服务现在正在我们的系统上运行。您可以在http://localhost:8000访问它(参见图 5-3 )。您还可以测试一些可用的端点。

Traefik 微服务 API 网关教程(二)

图 5-3

httpbin 服务

流量配置

在上一节中,我们添加了一个 HTTP 服务。现在让我们配置 Traefik 向它发送用户请求。我们将为 web 应用创建以下带有入口点的treafik.yml

entryPoints :
  web :
    address : ":80"

providers :

    directory : /Users/rahulsharma/Projects/traefik-book/ch05/services
    watch : true
    filename : config
    debugLogGeneratedTemplate : true

api :
  insecure : true
  dashboard : true

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

在之前的配置中,Traefik 正在侦听端口 80。接下来,让我们为部署的 httpbin 应用定义路由和服务。

 http :
  routers :
    guest-router :
      entryPoints :
      - web
      rule : Host(`localhost`)
      service : httpbin-service

  services :
    httpbin-service :
      loadBalancer :
        servers :
        - url  : http://192.168.1.4:8000/

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

此配置向运行在 192.168.1.4 实例上的 httpbin 发送请求。这个配置需要复制到services文件夹作为config.yml.在这之后,你可以查找 http://localhost。浏览器应该加载应用。展开的配置可以在 Traefik 仪表板上看到(参见图 5-4 )。

Traefik 微服务 API 网关教程(二)

图 5-4

httpbin 入口点的仪表板

Traefik 日志

Traefik 报告有关遇到的问题的信息。默认情况下,Traefik 将这些报告给标准输出。这些报告的问题对应于 Traefik 应用中的事件。信息以不同的严重级别报告。您可以通过添加log配置来配置 Traefik 日志。该配置可以设置特定文件的日志记录。它还可以指定消息的最低严重级别。

entryPoints :
  web :
    address : ":80"

providers :
  # removed for Brevity

log:
  level: INFO
  filePath: traefik.json.log
  format: json

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

该代码执行以下操作。

  • 将日志定向到当前工作目录中的tarefik.json.log文件

  • 将默认日志级别更改为 INFO ,,它写入致命、错误、警告和信息级别的消息

  • 以 JSON 格式记录消息

默认情况下,Traefik 以通用日志格式写入所有消息。或者,您可以将其更改为 JSON 格式,如图所示。Traefik 可以报告调试、信息、警告、错误和致命级别的日志消息。配置较低的级别可以报告高于配置级别的所有严重级别。

定义的代码是用于启动 Traefik 的静态配置的一部分。Traefik 不会自动加载这些更改。进行更改后,重新启动服务器。您可以如下所示跟踪日志文件。

ch05 $ tail -f traefik.json.log
{"level":"info","msg":"Traefik version 2.2.0 built on 2020-03-25T17:17:27Z","time":"2020-06-13T20:27:08+05:30"}
{"level":"info","msg":"
Stats collection is disabled.
Help us improve Traefik by turning this feature on :)
More details on: https://docs.traefik.io/contributing/data-collection/
","time":"2020-06-13T20:27:08+05:30"}
{"level":"error","msg":"unsupported access log format: "foobar", defaulting to common format instead.","time":"2020-06-13T20:27:08+05:30"}
{"level":"error","msg":"Failed to create new HTTP code ranges: strconv.Atoi: parsing "foobar": invalid syntax","time":"2020-06-13T20:27:08+05:30"}
{"level":"info","msg":"Starting provider aggregator.ProviderAggregator {}","time":"2020-06-13T20:27:08+05:30"}
{"level":"info","msg":"Starting provider *file.Provider {"directory":"/Users/rahulsharma/Projects/traefik-book/ch05/code","watch":true,"filename":"config","debugLogGeneratedTemplate":true}","time":"2020-06-13T20:27:08+05:30"}
{"level":"info","msg":"Starting provider *traefik.Provider {}","time":"2020-06-13T20:27:08+05:30"}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

访问日志

Traefik 可以报告有关客户端请求的信息。处理完请求后,信息被写入access log。但是access log不是默认创建的。access log配置设置对特定文件的日志记录。但是默认访问日志是以通用日志格式编写的。可以将其配置为以 JSON 格式报告。

# Removed for Brevity

log:
  level: INFO
  filePath: traefik.json.log
  format: json

accessLog:
  filePath: access.json.log
  format: json

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

该代码执行以下操作。

  • 将访问日志定向到当前工作目录中的access.json.log文件

  • 以 JSON 格式记录消息

添加上述配置后,重新启动 Traefik 服务器。当我们访问 http://localhost/时,会生成以下访问日志。

logs $ tail -f access.json.log
{"ClientAddr":"[::1]:63226","ClientHost":"::1","ClientPort":"63226","ClientUsername":"-","DownstreamContentSize":12026,"DownstreamStatus":200,"Duration":28245000,"OriginContentSize":12026,"OriginDuration":28187000,"OriginStatus":200,"Overhead":58000,"RequestAddr":"localhost","RequestContentSize":0,"RequestCount":1,"RequestHost":"localhost","RequestMethod":"GET","RequestPath":"/","RequestPort":"-","RequestProtocol":"HTTP/1.1","RequestScheme":"http","RetryAttempts":0,"RouterName":"httpbin-router@file","ServiceAddr":"192.168.1.4:8000","ServiceName":"httpbin-service@file","ServiceURL":{"Scheme":"http","Opaque":"","User":null,"Host":"192.168.1.4:8000","Path":"/","RawPath":"","ForceQuery":false,"RawQuery":"","Fragment":""}
#### TRUNCATED }

  • 1
  • 2
  • 3
  • 4

访问日志包含各种信息。使用以下报告的属性有助于确定停机和缓慢响应时间。

  • Duration:处理一个请求所花费的总时间

  • OriginDuration:从建立连接到从上游服务器接收到响应体的最后一个字节所花费的时间

  • Overhead:从上游服务器收到的响应和发送回客户端的响应之间的时间差

  • OriginStatus:上游服务器发送的响应码

   "Duration":28245000,
   "OriginContentSize":12026,
   "OriginDuration":28187000,
   "OriginStatus":200,
   "Overhead":58000,

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

因为访问日志是在请求处理之后写入的,所以会增加开销。但是可以通过为日志消息配置缓冲区来优化日志开销。缓冲区支持日志消息的异步写入,而不是请求后写入。缓冲区指定 Traefik 在将日志行写入所选输出之前保留在内存中的日志行数。要启用缓冲区,请配置buffersize属性。

Note

访问日志是仅用于 HTTP 服务的全局配置。这不是入口点或特定于路由的配置。启用后,Traefik 会为所有入口点/用户请求生成日志。

日志过滤器

Traefik 访问日志描述了服务器处理的每个请求。信息很详细。如果服务器正在处理许多用户请求,访问日志会增长得非常快。大量信息很快变得无人管理。或者,您可以根据预配置的标准记录选择性请求。这确保了我们只查看相关的用户请求。它从访问日志中排除无关紧要的日志条目。使用 filters 属性启用选择性日志记录。过滤器属性提供了以下三个选项。

  • statusCodes:仅记录指定的响应代码列表。

  • retryAttempts:有重试尝试时的日志

  • minDuration:当请求花费的时间超过指定时间时记录日志

# Removed for Brevity

accessLog:
  filePath: logs/access.json.log
  format: json
  bufferingSize: 50
  filters:
    statusCodes:
      - 200
      - 300-302
    retryAttempts: true
    minDuration: 5s

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

当下列任一条件为真时,此代码写入访问日志。

  • 响应代码是 200/300/301/302

  • 使用断路来撤回请求

  • 请求时间超过 5 秒

访问http://localhost/应该生成一条日志消息,因为状态代码是 200。现在接入http://localhost/status/418。不应该有任何日志语句。

logs $ tail -f access.json.log
{"ClientAddr":"[::1]:64020","ClientHost":"::1","ClientPort":"64020","ClientUsername":"-","DownstreamContentSize":12026,"DownstreamStatus":200,"Duration":27516000,"OriginContentSize":12026,"OriginDuration":27467000,"OriginStatus":200,"Overhead":49000,"RequestAddr":"localhost","RequestContentSize":0,"RequestCount":1,"RequestHost":"localhost","RequestMethod":"GET","RequestPath":"/","RequestPort":"-","RequestProtocol":"HTTP/1.1","RequestScheme":"http","RetryAttempts":0,"RouterName":"httpbin-router@file","ServiceAddr":"192.168.1.4:8000","ServiceName":"httpbin-service@file"...... TRUNCATED }

  • 1
  • 2
  • 3
日志字段

之前,我们讨论了如何登录响应标准。但是 Traefik 也可以配置为在日志语句中报告选择性信息。您可能需要隐藏用户身份、删除敏感信息或优化日志。Traefik 日志信息由以下两种类型组成。

  • 请求头:用户在请求中传递的头

  • 字段:Traefik 添加的附加信息

这两种信息类型都具有可由以下选项控制的属性。

  • keep在日志中按原样报告信息。

  • drop从日志中删除信息。

  • redact替换和屏蔽日志中的信息。

accessLog:
  filePath: logs/access.json.log
  format: json
  bufferingSize: 50
  fields:
    defaultMode: keep
    names:
      ClientUsername: drop
    headers:
      defaultMode: keep
      names:
          User-Agent: redact
          Authorization: drop
          Content-Type: keep

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

在这段代码中,我们配置了以下内容。

  • defaultmodekeep值允许报告字段和标题。

  • defaultmodekeep值启用报告标题。

  • ClientUsernamedrop值将其从日志中删除。

  • Content-TypeAuthorizationdrop值从日志中删除这些头。

  • User-Agentredact值将该值报告为redacted

添加上述配置后,重新启动 Traefik 服务器。当您访问 http://localhost/时,会生成以下访问日志。

logs $ tail -f access.json.log
{"ClientAddr":"[::1]:49537","ClientHost":"::1","ClientPort":"49537",

 <!-- REMOVED for Brevity -->

,"origin_X-Processed-Time":"0","request_Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9","request_Accept-Encoding":"gzip, deflate, br","request_Accept-Language":"en-US,en;q=0.9","request_Cache-Control":"max-age=0","request_Connection":"keep-alive","request_Sec-Fetch-Dest":"document","request_Sec-Fetch-Mode":"navigate","request_Sec-Fetch-Site":"none","request_Sec-Fetch-User":"?1","request_Upgrade-Insecure-Requests":"1","request_User-Agent":"REDACTED","request_X-Forwarded-Host":"localhost","request_X-Forwarded-Port":"80","request_X-Forwarded-Proto":"http","request_X-Forwarded-Server":"XE-GGN-IT-02498.local","request_X-Real-Ip":"::1","time":"2020-06-14T16:35:18+05:30"}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

Note

Traefik 报告了大约 25 个附加字段。Traefik 文档中提供了字段列表。

原木旋转

生产部署的应用更喜欢日志轮换策略。这有助于在清除历史日志时优化磁盘使用。但是默认情况下 Traefik 日志不会循环。因此,我们需要使用系统程序来执行日志管理。日志管理涉及归档和清除活动。根据操作系统的不同,有不同的程序来完成这项工作。在 FreeBSD 系统上,可以使用newsyslog,而在 Linux 上,可以使用logrotate。它们都依赖于发送 USR1 信号来旋转日志。在下面的讨论中,我们和newsyslog一起工作。概述的步骤对于任何其他程序都是一样的。

FreeBSD 中包含的newsyslog实用程序会循环使用,并在必要时归档日志文件。程序需要输入一个配置文件。该文件标识需要处理哪些日志文件。它提供了一组不同的属性,可以描述文件权限、复制行为、存档数量等。通过使用类似crontab的调度程序,该程序被配置为定期运行。让我们在名为 syslog.conf 的文件中创建以下配置。

/Users/rahulsharma/Projects/traefik-book/ch05/logs/access.json.log    rahulsharma:staff    640  5    500    *     Z

  • 1
  • 2

在这个配置中,我们为acces.json.log配置了日志轮转。

  • 将文件所有者和组设置为rahulsharma:staff。这适用于压缩文件和新的日志文件。

  • 将文件权限设置为 640。

  • 文件只有五次旋转。

  • 当大小增长到 500,000 以上时,会发生旋转。

  • Z 标志配置压缩文件。

您可以使用下面的命令用描述的配置运行newsyslog

code $ sudo newsyslog -vf  syslog.conf
/Users/rahulsharma/Projects/traefik-book/ch05/logs/access.json.log <5Z>: size (Kb): 532 [500] --> trimming log....
Signal all daemon process(es)...
Notified daemon pid 91 = /var/run/syslog.pid
Pause 10 seconds to allow daemon(s) to close log file(s)
Compress all rotated log file(s)...

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

Note

前面的过程不适用于 Windows,因为缺少 USR 信号,所以没有 log rotate 程序。

黑名单

Traefik 通过使用中间件来提供对反向列表的支持。我们在第二章中讨论了中间件。它们被配置为路由器的一部分。中间件在规则匹配之后但在将请求转发给服务之前执行。Traefik 通过配置ipWhiteList中间件支持 IP 反向列表。可以使用以下选项进行配置。

  • sourceRange:以 CIDR 格式描述允许的 IP 集合

  • ipstrategy:描述如何从X-forward-for头识别客户端 IP

http :
  routers :
    httpbin-router :
      entryPoints :
      - web
      rule : HostRegexp(`{name:.*}`)
      middlewares :
      - allowed-sources
      service : httpbin-service

  middlewares:
    allowed-sources:
      ipWhiteList:
        sourceRange:
          - "127.0.0.1/32"

  services :
  # Removed for Brevity

Traefik 微服务 API 网关教程(二)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

在前面的代码中,我们执行了以下操作。

  • 我们将router rule修改为允许所有主机名使用正则表达式。这是使用HostRegexp函数而不是Host操作符来完成的。

  • 我们添加了带有已配置的ipWhiteList中间件名称的中间件部分。

  • 我们用ipWhiteList.的配置配置了中间件部分

  • 我们使用sourceRange选项添加了允许的 IP 列表。

现在让我们运行配置。访问 http://localhost/页面以访问 httpbin 服务。

$ curl -v http://localhost/
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 80 (#0)
> GET / HTTP/1.1
> Host: localhost
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 403 Forbidden
< Date: Sat, 20 Jun 2020 17:41:11 GMT
< Content-Length: 9
< Content-Type: text/plain; charset=utf-8
<
* Connection #0 to host localhost left intact
Forbidden* Closing connection 0

Traefik 微服务 API 网关教程(二)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

我们得到一个被禁止的回应。这是因为我们的本地主机域被解析为 IP6 环回地址(::1)。环回地址不在白名单中。或者,您可以使用 IP4 环回地址(127.0.0.1)来访问。这将按预期加载页面。访问日志中会报告禁止的访问。确保从静态配置中删除基于状态代码的日志过滤器。

{"ClientAddr":"[::1]:64616","ClientHost":"::1","ClientPort":"64616","ClientUsername":"-","DownstreamContentSize":9,"DownstreamStatus":403,"Duration":128000,"OriginContentSize":9,"OriginDuration":79000,"OriginStatus":403,"Overhead":49000,"RequestAddr":"localhost","RequestContentSize":0,"RequestCount":63,"RequestHost":"localhost","RequestMethod":"GET","RequestPath":"/","RequestPort":"-","RequestProtocol":"HTTP/1.1","RequestScheme":"http","RetryAttempts":0,"RouterName":"httpbin-router@file","StartLocal":"2020-06-20T23:11:01.21434+05:30","StartUTC":"2020-06-20T17:41:01.21434Z","entryPointName":"web","level":"info","msg":"","time":"2020-06-20T23:11:01+05:30"}

  • 1
  • 2

请求跟踪

你学到了可观察性是一种多样的实践。请求跟踪或分布式跟踪是分析应用行为的重要支柱。它通常应用于分布式系统,以预测跨不同系统的请求处理是如何发生的。它可以指出导致性能问题或请求处理失败的应用。

简而言之,分布式跟踪映射了系统处理请求的流程。处理流是在一个被称为请求跨度的构建块上创建的。请求跨度表示服务处理所花费的时间。所有处理请求的服务都生成各自的跨度。然后,这些跨度被组合成整个请求的单个分布式跟踪。

作为 API 网关,Traefik 接收不同应用的传入请求。它是所有外部请求的单一入口点。Traefik 必须支持请求跨度的生成。生成的请求跨度作为请求头传播到应用。反过来,应用必须进一步传播这些头。Traefik 生成以下 B3 跟踪头。

  • x-b3-traceid

  • x-b3 西班牙语

  • x-b3 亲西班牙语

  • x-B3-采样

这些跨度被发送到跟踪后端服务。该服务负责存储和处理这些信息。Traefik 支持几个 OpenTracing 后端,如 Zipkin、Datadog 和 Jagger。在本节中,我们将使用 Zipkin。其他后端也需要类似的配置。

安装 Zipkin

Zipkin 是一个用 Java 构建的开源跟踪收集引擎。它不仅支持跟踪收集,还提供了可视化跟踪的仪表板。还有其他允许您分析请求流的特性。由于 Zipkin 是开源的,所以它提供了可以为目标平台编译的代码。或者,我们直接运行一个发布的二进制文件。使用以下命令可以下载 Zipkin 的最新版本。

code $curl -sSL https://zipkin.io/quickstart.sh | bash -s
Thank you for trying Zipkin!
This installer is provided as a quick-start helper, so you can try Zipkin out
without a lengthy installation process.

Fetching version number of latest io.zipkin:zipkin-server release...
Latest release of io.zipkin:zipkin-server seems to be 2.21.4

Downloading io.zipkin:zipkin-server:2.21.4:exec to zipkin.jar...

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

下载完zipkin.jar后,使用下面的命令运行它。

code $ java -jar zipkin.jar
2020-06-20 21:57:31.012  INFO 47685 --- [           main] z.s.ZipkinServer                         : Starting ZipkinServer on XE-GGN-IT-02498.local with PID 47685 (/Users/rahulsharma/Projects/trafik/code/zipkin.jar started by rahulsharma in /Users/rahulsharma/Projects/trafik/code)
2020-06-20 21:57:31.016  INFO 47685 --- [           main] z.s.ZipkinServer                         : The following profiles are active: shared
2020-06-20 21:57:32.040  INFO 47685 --- [           main] c.l.a.c.u.SystemInfo                     : hostname: xe-ggn-it-02498.local (from 'hostname' command)
2020-06-20 21:57:32.537  INFO 47685 --- [oss-http-*:9411] c.l.a.s.Server                           : Serving HTTP at /0:0:0:0:0:0:0:0:9411 - http://127.0.0.1:9411/
2020-06-20 21:57:32.538  INFO 47685 --- [           main] c.l.a.s.ArmeriaAutoConfiguration         : Armeria server started at ports: {/0:0:0:0:0:0:0:0:9411=ServerPort(/0:0:0:0:0:0:0:0:9411, [http])}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

服务器已启动并运行在 9411 端口上。您可以在http://localhost:9411/访问其仪表盘。

Traefik 微服务 API 网关教程(二)

图 5-5

Zipkin 仪表板

集成 Zipkin

Traefik 与 Zipkin 的集成非常简单。我们只需要提供 Zipkin API 的位置。这些参数是 Traefik 静态配置的一部分。Traefik 还提供以下属性来自定义跟踪行为。

  • sameSpan:为 RPC 调用配置一个 span

  • id128Bit:生成 128 位跟踪 id

  • samplerate:被追踪请求的百分比

# Removed for Brevity

tracing:
  zipkin:
    httpEndpoint: http://localhost:9411/api/v2/spans
    id128Bit : true
    sameSpan: true

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在这个配置中,我们提供了 Zipkin API 的位置。我们还为 RPC 客户端和服务器配置了具有相同跨度的 128 位跟踪。现在重新启动服务器。

ch05 $ traefik  --configfile traefik.yml
INFO[0000] Configuration loaded from file: /Users/rahulsharma/Projects/traefik-book/ch05/traefik.yml

  • 1
  • 2
  • 3

您可以在 Traefik 仪表板中验证配置(参见图 5-6 )。它应该报告在应用中配置了哪个跟踪后端。

Traefik 微服务 API 网关教程(二)

图 5-6

跟踪仪表板状态

Note

跟踪是在全局级别启用的。一旦启用,它将为所有请求生成跟踪,包括仪表板 API。

现在,让我们提几个要求。httpbin 应用(见图 5-7 )提供了几种请求类型。尝试加载 IP、状态代码和重定向请求。Traefik 生成请求跟踪,并将其发送给部署的 Zipkin。

Traefik 微服务 API 网关教程(二)

图 5-7

httpbin 应用

你可以跟踪访问日志。Traefik 记录所有传递的请求头,包括生成的 B3 头。

  {
   # Removed for Brevity

   "request_User-Agent":"REDACTED",
   "request_X-B3-Parentspanid":"12f1ca6cf7671169",
   "request_X-B3-Sampled":"1",
   "request_X-B3-Spanid":"1704e2a62f95fa8b",
   "request_X-B3-Traceid":"12f1ca6cf7671169",
  }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

Traefik 集成由以下步骤组成。

  • 基于配置的采样率为请求生成 TraceId 和 Span

  • 将跟踪头转发给服务应用

  • 根据响应代码更新跨度

  • 将生成的跟踪范围发送到跟踪后端

现在,您可以加载 Zipkin 仪表板了。仪表板提供了一个 UI 来可视化请求跟踪。您可以搜索过去 15 分钟内的请求。结果页面应该如下所示。tracer/Zipkin 仪表板(见图 5-8 )用蓝色标记所有带有 2XX 或 3XX 回路的轨迹。但是返回代码 4XX /5XX 显示为红色。

Traefik 微服务 API 网关教程(二)

图 5-8

请求跟踪

Traefik 指标

Traefik 可以生成应用级别的指标。这些指标必须在后台服务中捕获,以便进行监控和警报通知。Traefik 支持使用最广泛的度量解决方案,如 StatsD、Datadog、Prometheus 等。在当前部分,我们与 Prometheus 合作,作为一家有指标支持的商店。Prometheus 是一个使用 Golang 构建的开源解决方案。Prometheus 可以从 Traefik 中暴露的端点获取指标。它还提供了一个可视化指标的仪表板。普罗米修斯的细节超出了本书的范围。

让我们首先通过添加相关配置来启用 Traefik 指标。需要将配置添加到静态配置文件中。Traefik 提供了以下选项。

  • 存储桶:定义响应延迟的存储桶

  • addEntryPointLabels:向请求度量添加入口点名称

  • addServiceLabels:将服务名添加到请求度量中

  • entryPoint:命名配置为发布度量的入口点

  • manualrouting:为 prometheus@internal 服务启用自定义路由器

entryPoints :
  web :
    address : ":80"

# Removed for Brevity

metrics:
  prometheus:
     addEntryPointsLabels: true
     addServicesLabels : true

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

此配置在默认端点上启用指标。这些指标在http://locahost:8080/metrics生成。重新启动服务器并验证 Traefik 仪表板上的配置。

Traefik 微服务 API 网关教程(二)

图 5-9

启用指标

配置普罗米修斯

现在我们需要在 Prometheus 中捕获生成的指标。让我们从使用发布页面( https://prometheus.io/download/ )下载最新版本开始。您可以解压缩该版本。但是在启动 Prometheus 服务器之前,我们需要配置端点,这个端点需要报废。这可以通过更新捆绑的prometheus.yml来完成

# my global config
global:
  scrape_interval:     15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
  evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
  # scrape_timeout is set to the global default (10s).

### REMOVED for BREVITY

    static_configs:
    - targets: ['localhost:8080']

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在此配置中,Traefik 端点(localhost:8080)被添加到目标列表中。Prometheus 使用http:// localhot:8080/metrics查找指标。现在使用下面的命令启动 Prometheus。

prometheus-2.19.1.darwin-amd64 $ ./prometheus
level=info ts=2020-06-21T06:14:37.958Z caller=main.go:302 msg="No time or size retention was set so using the default time retention" duration=15d
level=info ts=2020-06-21T06:14:37.959Z caller=main.go:337 msg="Starting Prometheus" version="(version=2.19.1, branch=HEAD, revision=eba3fdcbf0d378b66600281903e3aab515732b39)"
level=info ts=2020-06-21T06:14:37.959Z caller=main.go:338 build_context="(go=go1.14.4, user=root@62700b3d0ef9, date=20200618-16:45:01)"
level=info ts=2020-06-21T06:14:37.959Z caller=main.go:339 host_details=(darwin)
level=info ts=2020-06-21T06:14:37.959Z caller=main.go:340 fd_limits="(soft=2560, hard=unlimited)"
level=info ts=2020-06-21T06:14:37.959Z caller=main.go:341 vm_limits="(soft=unlimited, hard=unlimited)"
level=info ts=2020-06-21T06:14:37.960Z caller=main.go:678 msg="Starting TSDB ..."
level=info ts=2020-06-21T06:14:37.960Z caller=web.go:524 component=web msg="Start listening for connections" address=0.0.0.0:9090

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

我们可以使用http://locahost:9090/加载普罗米修斯仪表板。指标下拉菜单有不同的选项,前缀为traefik_。我们加载traefik_entrypoint_requests_total度量。它描述了 Traefik 处理的请求总数。此外,您还可以使用以下 bash 脚本向 Traefik 发送几个请求。

$ for ((i=1;i<=10000;i++)); do   curl -v --header "Connection: keep-alive" "localhost"; done

  • 1
  • 2

该脚本向 Traefik 服务器发送大约 10,000 个请求。最后,您可以查看普罗米修斯仪表盘(见图 5-10 ),它捕捉到了流量的增长。

Traefik 微服务 API 网关教程(二)

图 5-10

请求流量度量

摘要

本章讨论了可观测性。我们讨论了它的三个支柱:错误日志、请求跟踪和应用度量。首先,我们配置了错误日志。这些日志捕获关于 Traefik 中发生的任何错误的信息。下一步,我们配置了访问日志。访问日志捕获由 Traefik 处理的传入请求。随着传入请求的增加,访问日志会迅速膨胀。

我们讨论了通过使用过滤器、旋转和标题屏蔽来管理它的方法。我们还配置了IPwhitelist中间件,并捕获了它生成的禁止日志。之后,我们使用 Zipkin 启用了请求跟踪。Traefik 生成用于跟踪的 B3 标头。这些标题可以在访问日志中看到。

您查看了流程流,并在 Zipkin 仪表板中生成了跟踪。最后,我们启用了 Traefik 指标,并在 Prometheus 中捕获了它们。Traefik 支持许多用于跟踪和度量的后端存储。以齐普金和普罗米修斯为例来说明其集成。这些工具在像微服务这样的分布式架构中很有帮助。

在下一章中,您将使用微服务的 Traefik 支持。

六、用于微服务的 Traefik

在第一章中,我们讨论了微服务架构。企业越来越多地从整体架构转向利用微服务架构。但是微服务系统是一个分布式系统。为了有效地使用它,我们需要采用额外的基础设施组件。这些附加组件规定了每个微服务必须遵循的一套新准则。

微服务架构提倡粒度服务来满足不断发展的业务需求。根据不断变化的业务需求,开发团队可以创建或组合服务。此外,在生产环境中,每个服务都是独立部署和扩展的。基于云的自动伸缩通常基于服务负载复制实例。因此,架构处于不断的演进中,并且没有微服务的最终状态列表。

动态生态系统需要最新运行的微服务的目录。这也被称为服务注册中心。简而言之,注册中心是一个包含服务实例和相应位置细节的服务数据库。为了有效地工作,服务必须在启动时注册,在关闭时删除。有许多方法可以实现这一点,但是服务自注册的过程是推荐的机制。

服务在注册中心注册后,客户机需要查找相同的服务。这个客户端过程被称为服务发现(见图 6-1 )。客户端首先查询服务注册中心来查找服务的可用实例。获得活动服务实例列表后,客户端可以向所需的服务发送请求。

Traefik 微服务 API 网关教程(二)

图 6-1

服务注册和服务发现

服务注册中心通常是信息的键值存储。很多时候,您必须注册关于服务的附加信息。这些信息可能与多租户系统中的客户端类型有关,也可能与所提供的视图有关,比如 web 或 mobile,或者其他任何信息。每个服务负责将这些数据添加到存储中。在本章中,我们使用服务自注册机制来集成 Traefik 和微服务。

微服务架构推荐服务协作。这意味着一个服务可以调用其他服务来获取用户请求所需的数据。但是这个机制有它自己的一系列问题。当一个服务同步调用另一个服务时,总有可能另一个服务不可用,或者表现出很高的延迟,以至于基本上不可用。

在等待其他服务响应时,调用方可能会消耗线程等宝贵的资源。这可能会导致资源耗尽,从而使调用服务无法处理其他请求。

一个服务的失败可能会影响整个应用中的其他服务。这个问题可以通过在应用设计中采用断路器来解决(见图 6-2 )。当连续失败的次数超过阈值时,断路器跳闸,并且在超时期间,所有调用远程服务的尝试都会立即失败。

Traefik 微服务 API 网关教程(二)

图 6-2

断路器模式

超时后,断路器允许有限数量的测试请求通过。如果这些请求成功,断路器恢复正常运行。否则,如果出现故障,超时周期将重新开始。在本章中,我们在调用 Traefik 的不同微服务时集成断路器。

API 网关是任何基于微服务的架构的重要组成部分。诸如身份验证、负载平衡、依赖关系解析、数据转换和动态请求调度等跨领域的问题可以方便而通用地处理。然后,微服务可以专注于特定的任务,而无需重复代码。这使得每个微服务的开发更加容易和快速。

实现一个 API 网关,它是所有客户端的单一入口点。API 网关以两种方式之一处理请求。一些请求被代理/路由到适当的服务。它通过分散到多个服务来处理其他请求。在前面的章节中,我们为单一服务的需求配置了 Traefik。在本章中,我们将 Traefik 配置为微服务网关。

pet-临床应用

在本章中,我们需要一个基于微服务的应用。应用必须至少有两个或更多与 Traefik 集成的微服务。我们使用 PetClinic 应用。PetClinic 是一个基于 Java 的应用,它与 Spring 框架打包在一起,用于学习目的。Spring 社区维护这个应用。它详细解释了基于 Spring 框架的技术。因此,该应用是企业技术的良好测试平台。

PetClinic 应用是为兽医诊所的需要而设计的。该应用使其用户能够查看和管理兽医、客户和他们的宠物。该应用支持以下用例。

  • 查看兽医及其专业的列表

  • 查看宠物主人的信息

  • 更新宠物主人的信息

  • 在系统中添加一个新的宠物主人

  • 查看宠物的信息

  • 更新宠物的信息

  • 向系统中添加新宠物

  • 查看宠物的访问历史信息

  • 向宠物的访问历史记录中添加有关访问的信息

该解决方案需要使用微服务架构来构建。让我们从 https://github.com/rahul0208/spring-petclinic-microservices 下载 PetClinic 应用。

Spring PetClinic 微服务是围绕小型独立服务(几百行代码)构建的,运行在自己的 JVM 中,通过 REST API 在 HTTP 上通信。这些微服务都是用 Java 写的。三个客户、vet 和访问业务微服务中的每一个都是 Spring Boot 意义上的应用。为了在分布式环境中工作,这些微服务依赖于 Spring Cloud 提供的一组工具:集中配置管理、自动发现其他微服务和负载平衡(见图 6-3 )。应用 UI 用 Angular 开发,部署在 Nginx。Traefik 将执行请求路由。在本章中,我们将构建和部署一个应用。书中涵盖了一些重要的方面,但是完整的应用技术细节超出了本书的范围。

Traefik 微服务 API 网关教程(二)

图 6-3

宠物诊所服务

应用配置

PetClinic 应用配置位于 https://github.com/rahul0208/spring-petclinic-microservices-config 。使用 spring-cloud-config 服务器提供配置。配置服务器在以下 REST URLs 上提供配置。

  • /{应用}/{个人资料}[/{标签}]

  • /{应用}-{个人资料}。阳明海运股份有限公司

  • /{标签}/{应用}-{个人资料}。阳明海运股份有限公司

  • /{应用}-{个人资料}。性能

  • /{标签}/{应用}-{个人资料}。性能

配置服务器还消除了在配置改变的情况下重新打包应用的需求。由于所有最新的配置在列出的 REST 端点上都是可用的,所以我们只需要重启服务。还可以通过使用@RefreshScope注释或EnvironmentChangeEvent事件监听器来配置热重载服务。

Spring 遵循从application.properties.加载应用配置的惯例,但是如前所述,当使用 spring-cloud-config 服务器时,application.properties不再是应用的一部分。相反,spring-cloud-context 被配置为从外部源加载配置属性。它也可以配置为解密外部配置文件中的属性。Spring Cloud 应用启动一个 bootstrap 上下文,从 bootstrap.yml 文件中加载它的配置。bootstrap.yml 文件非常简洁。它包含微服务的名称和配置服务器的 URL。以下是来自 vets-service 微服务的一个例子。

spring:
  cloud:
    config:
      uri: http://localhost:8888
  application:
    name: vets-service

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

我们在配置中指定了 spring-config-server 在 localhost:8888 的位置。vets-service 微服务要求服务器位于上述位置。它查询服务器以确定配置值,然后完成服务器启动。值得注意的是,可以使用 SPRING_CLOUD_CONFIG 这样的环境变量来注入配置服务器的位置。但是不能使用服务注册表来发现它。

咨询服务登记处

之前,我们讨论了微服务架构的演进本质。当服务部署在云中时,您很难预测相同微服务的实例数量(取决于负载)或它们部署在哪里(以及它们可以在哪个 IP 和端口上访问)。因此,需要一个服务注册中心。在 PetClinic 应用中,我们使用了咨询服务注册中心。启动时,每个微服务都向服务注册表注册自己。注册后,每个服务定期向注册中心提供心跳。这本书并不打算涵盖咨询服务注册的细节。有关更多信息,请参考文档。

现在让我们从 www.consul.io/ 下载领事。下载后,提取压缩文件并启动服务。

$ ./consul agent -dev
==> Starting Consul agent...
           Version: 'v1.8.0'
           Node ID: '935fccd6-74ca-e62e-c53f-c838de3c3681'
         Node name: 'XE-GGN-IT-02498.local'
        Datacenter: 'dc1' (Segment: '<all>')
            Server: true (Bootstrap: false)
       Client Addr: [127.0.0.1] (HTTP: 8500, HTTPS: -1, gRPC: 8502, DNS: 8600)
      Cluster Addr: 127.0.0.1 (LAN: 8301, WAN: 8302)
           Encrypt: Gossip: false, TLS-Outgoing: false, TLS-Incoming: false, Auto-Encrypt-TLS: false

==> Log data will now stream in as it occurs:

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

我们可以在http://localhost:8500/ui/dc1/services加载 Consul UI。(见图 6-4 )

Traefik 微服务 API 网关教程(二)

图 6-4

领事服务

部署宠物诊所

现在我们可以以任何顺序运行 PetClinic 微服务。该应用由以下三个微服务组成。

  • 兽医服务

  • 探访服务

  • 客户服务

所有的服务都基于 Spring Boot。它们被打包成可执行的 JAR 文件。执行特定于服务的 jar 启动带有嵌入式 servlet 引擎的服务。因为服务获取是来自 spring-config 服务器的配置,所以让我们确保我们是 bootstrap.yml 中配置服务器的正确位置。

接下来,确保 config-server 指向正确的 git 位置。在本例中, https://github.com/rahul0208/spring-petclinic-microservices-config 是应用配置源。我们建议您克隆此配置,并根据环境进行更新。

前面的 URL 是在 config-server 的 bootstrap.yml 中配置的。

server.port: 8888
spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/spring-petclinic/spring-petclinic-microservices-config
        native:
          searchLocations: file:///${GIT_REPO}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

配置的细节超出了本书的范围。我们建议您用自己的克隆更新 URI。现在,我们需要使用包 maven 包装器来构建服务。

$ ./mvnw clean install
[INFO] Scanning for projects...
[INFO] --------------------------------------------------------
[INFO] Reactor Build Order:
[INFO]
[INFO] spring-petclinic-microservices                                 [pom]
[INFO] spring-petclinic-customers-service                                 [jar]
[INFO] spring-petclinic-vets-service                                   [jar]
[INFO] spring-petclinic-visits-service                                   [jar]
[INFO] spring-petclinic-config-server                                   [jar]
...
..... Truncated for Brevity

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

该命令在目标文件夹下为每个服务创建一个可执行文件。

$ find  . -type f  -name "*jar"
./spring-petclinic-config-server/target/spring-petclinic-config-server-2.3.1.jar
./spring-petclinic-ui/target/spring-petclinic-ui-2.3.1.jar
./spring-petclinic-vets-service/target/spring-petclinic-vets-service-2.3.1.jar
./.mvn/wrapper/maven-wrapper.jar
./spring-petclinic-customers-service/target/spring-petclinic-customers-service-2.3.1.jar
./spring-petclinic-visits-service/target/spring-petclinic-visits-service-2.3.1.jar

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在当前设置中,我们将所有服务部署在同一个盒子中。因此,在配置中使用本地主机地址。通过在 git 配置中进行适当的更新,您可以在任何主机上自由部署服务。作为第一步,您需要用下面的命令启动配置服务器。

target $ java -jar spring-petclinic-config-server-2.3.1.jar
2020-07-26 21:56:26.401  INFO 7442 --- [           main] o.s.s.p.config.ConfigServerApplication   : No active profile set, falling back to default profiles: default
2020-07-26 21:56:27.221  INFO 7442 --- [           main] o.s.cloud.context.scope.GenericScope     : BeanFactory id=15cd0375-3bcf-3529-9d02-67397a0dc277
2020-07-26 21:56:27.609  INFO 7442 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8888 (http)
2020-07-26 21:56:27.621  INFO 7442 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2020-07-26 21:56:27.621  INFO 7442 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.36]
2020-07-26 21:56:27.690  INFO 7442 --- [           main]

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

下一步是运行每个微服务。但是首先让我们确保我们在application.yml.中有正确的咨询服务注册地址

spring:
  cloud:
    consul:
      host: localhost
      port: 8500

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

现在让我们用下面的命令启动 vets 服务。

target $ java -jar spring-petclinic-vets-service-2.3.1.jar
2020-07-21 15:34:11.693  INFO [vets-service,,,] 26509 --- [           main] c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at : http://localhost:8888
2020-07-21 15:34:15.525  INFO [vets-service,,,] 26509 --- [           main] c.c.c.ConfigServicePropertySourceLocator : Located environment: name=vets-service, profiles=[default], label=null, version=062fb94b71dc6b99e6518fe7088a0bff3a9431d1, state=null
2020-07-21 15:34:15.527  INFO [vets-service,,,] 26509 --- [           main] b.c.PropertySourceBootstrapConfiguration : Located property source: [BootstrapPropertySource {name='bootstrapProperties-configClient'}, BootstrapPropertySource {name='bootstrapProperties-https://github.com/spring-petclinic/spring-petclinic-microservices-config/vets-service.yml (document #1)'}, BootstrapPropertySource {name='bootstrapProperties-https://github.com/spring-petclinic/spring-petclinic-microservices-config/vets-service.yml (document #0)'}, BootstrapPropertySource {name='bootstrapProperties-https://github.com/spring-petclinic/spring-petclinic-microservices-config/application.yml (document #0)'}]
- Start completed.

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

同样,我们需要启动客户服务和访问服务。每个服务都在 Consul 服务注册表中注册自己。您可以在咨询仪表板中验证服务详情(参见图 6-5 )。此外,这些服务中的每一个都可能报告基于 Zipkin 的请求跟踪失败。请求跟踪提供了各种好处。在第五章中,我们介绍了这些工具与 Traefik 的集成。我们在本章中不讨论这些集成。

Traefik 微服务 API 网关教程(二)

图 6-5

仪表板 UI

宠物诊所用户界面

应用 UI 是在 AngularJS 上使用 1.7 版本构建的。这些 HTML 页面被部署为 Spring web 应用的静态资源。或者,我们可以将它们打包并部署在像 Apache Tomcat 或 HTTPD 这样的服务器上。UI 也被打包成一个可执行的 JAR。现在让我们用下面的命令启动 UI。

target $ java -jar spring-petclinic-ui-2.3.1.jar
2020-07-27 22:15:21.996  INFO [petclinic-ui,,,] 17732 --- [  restartedMain] c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at : http://localhost:8888
2020-07-27 22:15:22.870  INFO [petclinic-ui,,,] 17732 --- [  restartedMain] c.c.c.ConfigServicePropertySourceLocator : Located environment: name=petclinic-ui, profiles=[default], label=null, version=8adeb754f96df6e7308344e7bb2ceddcca09b93f, state=null
2020-07-27 22:15:22.871  INFO [petclinic-ui,,,] 17732 --- [  restartedMain] b.c.PropertySourceBootstrapConfiguration : Located property source: [BootstrapPropertySource {name='bootstrapProperties-configClient'}, BootstrapPropertySource {name='bootstrapProperties-https://github.com/rahul0208/spring-petclinic-microservices-config/petclinic-ui.yml (document #0)'}, BootstrapPropertySource {name='bootstrapProperties-https://github.com/rahul0208/spring-petclinic-microservices-config/application.yml (document #0)'}]
...... TRUNCATED FOR BREVITY

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

UI 部署在 9000 端口上。我们可以用http://localhost:9000/#!/welcome来访问它。(见图 6-6

Traefik 微服务 API 网关教程(二)

图 6-6

PetClinic UI(小诊所 UI)

UI 也在更新咨询服务注册中心。这样,注册表就是正在运行的服务的综合目录。

配置网关

在前面的设置中,我们部署了应用的所有微服务。现在我们需要配置 Traefik 来呈现 UI,并将调用路由到每个服务。我们可以像前面几章一样,把这个配置写在一个文件中。它配置 Traefik,但是这种方法不能处理微服务架构的动态特性。随着新的服务加入到生态系统中,我们需要不断更新配置。此外,很难保持更新服务的所有实例的 IP 地址。

或者,Traefik 可以作为配置提供者与 Consul 键值存储一起使用。所有 Traefik 配置都作为键和值分层添加到已配置的根节点下。默认根节点名为“traefik”。表 6-1 突出显示了一些 Traefik 键。

表 6-1

交通钥匙

|

钥匙

|

价值

|
| — | — |
| traefik/http/routers//entry points/0 | 指定各自的入口点名称 |
| traefik/http/routers//middleware/0 | 指定中间件名称 |
| traefik/http/routers/ /rule | 指定了匹配规则 |
| traefik/http/routers//service | 指定各自的服务名称 |
| traefik/http/service//load balancers/0/URL | 指定了实例 url 位置 |
| RAE fik/http/middleware//strip prefix/prefix/0 | 指定了中间件配置 |

Traefik 文档提供了用于配置它的密钥的更新列表。作为第一步,让我们将配置添加到 Consul。您可以使用 Consul GUI 创建它。或者,您可以从 JSON 文件中导入键。每个键的值都以 Base64 格式编码。

$ consul kv import "$(cat config.json)"
Imported: traefik/http/middlewares/petclinic-customers-stripprefix/stripPrefix/prefixes/0
Imported: traefik/http/middlewares/petclinic-visits-stripprefix/stripPrefix/prefixes/0
Imported: traefik/http/routers/petclinic-customers-route/entryPoints/0
Imported: traefik/http/routers/petclinic-customers-route/middlewares/0
Imported: traefik/http/routers/petclinic-customers-route/rule
Imported: traefik/http/routers/petclinic-customers-route/service
Imported: traefik/http/routers/petclinic-route/entryPoints/0
Imported: traefik/http/routers/petclinic-route/rule
Imported: traefik/http/routers/petclinic-route/service
Imported: traefik/http/routers/petclinic-vets-route/entryPoints/0
Imported: traefik/http/routers/petclinic-vets-route/rule
Imported: traefik/http/routers/petclinic-vets-route/service
Imported: traefik/http/routers/petclinic-visits-route/entryPoints/0
Imported: traefik/http/routers/petclinic-visits-route/middlewares/0
Imported: traefik/http/routers/petclinic-visits-route/rule
Imported: traefik/http/routers/petclinic-visits-route/service

Traefik 微服务 API 网关教程(二)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

一旦配置被导入,我们应该在 Consul 存储中看到所有的键值。现在我们需要更新 Traefik 静态配置来使用 Consul provider。

entryPoints :
  web :
    address : ":80"

providers:
  consul:
    endpoints:
      - "127.0.0.1:8500"
    rootKey : "traefik"

api :
  insecure : true
  dashboard : true

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

我们在配置中指定了 Consul provider 而不是 FileProvider。我们还指定了位置和根密钥。还有其他选项来配置身份验证和 TLS 信息。让我们启动 Traefik 服务器并查看仪表板。

仪表板显示来自 Consul 键值存储的配置。Traefik 已经创建了四条新路由,每条路由对应一个已部署的服务。如果服务没有运行,那么配置添加的路由是错误的,如图 6-7 所示。如果您单击某个路径,您会看到一条关于相应服务缺失详细信息的错误消息。

Traefik 微服务 API 网关教程(二)

图 6-7

来自 consul 的流量配置

服务详情

Traefik 需要每个服务的服务器详细信息。在微服务架构中,服务注册是将所有细节添加到注册表中的过程。在我们看来,自注册是支持所有可能场景的最简单的机制。我们扩展了自助注册,为所需的咨询密钥添加了 Traefik 特定的详细信息。ServiceRegistry类完成了这一职责。

@Configuration
public class ServiceRegistry implements ApplicationListener<ServletWebServerInitializedEvent> {

    final String serviceKey = "/traefik/http/services/{0}/loadBalancer/servers/";
    final String serverKey = "/traefik/http/services/{0}/loadBalancer/servers/{1}/";
    final String urlKey = "/traefik/http/services/{0}/loadBalancer/servers/{1}/url";

    @PreDestroy
    void removerServerMapping() {
        if(index > -1) {
            consulClient.deleteKVValues(format(serverKey, applicationName, index));
        }
    }

    void addServerMapping(int port)  {
        Response<List<String>> keys = consulClient.getKVKeysOnly(format(serviceKey, applicationName));
        index = keys.getValue()!=null ? keys.getValue().size() : 0;
        consulClient.setKVValue(format(urlKey, applicationName,index), format("http://{0}:{1,number,#}/","127.0.0.1",port));
    }

 // REMOVED for Brevity
}

Traefik 微服务 API 网关教程(二)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

前面的代码执行以下操作。

  • 已确定启动应用的端口

  • 使用 ConsulClient 将主机和端口信息添加到 Consul KV 存储中

  • 将值添加到 Traefik keys/Traefik/http/services/{ 0 }/load balancer/servers/{ 1 }/URL 中

  • 服务关闭时删除密钥

类是每个服务的一部分。如果您启动所有服务并重新加载仪表板,您会看到所有错误都已修复。(见图 6-8

Traefik 微服务 API 网关教程(二)

图 6-8

PetClinic 配置

Note

Traefik 继续关注 KVS 商店的价值。当配置在 Consul 中更新时,它会自动重新加载配置。

现在让我们在 http://localhost/上加载 PetClinic 应用。应用按预期执行。我们可以跨三种不同的微服务加载和保存数据。(参见图 6-9 )

Traefik 微服务 API 网关教程(二)

图 6-9

宠物诊所

断路器

我们说过,微服务经常协作来交付一个完整的用户功能。一个服务调用其他服务来获取相关数据。但是在像微服务这样的分布式系统中,远程服务调用在失败之前可能会挂起一段时间。无响应的服务调用会阻塞调用服务的资源。如果有许多这样的调用,系统可能会耗尽关键资源,导致跨多个系统的级联故障。

断路器经常被用来解决这个故障快速行为的问题。断路器跟踪远程呼叫。在不正常的响应中,断路器会立即返回,而不会将呼叫发送到目标服务。这本书没有详细介绍这种模式。

Traefik 提供了可以配置断路器的中间件。因为断路器被配置为中间件链的一部分,所以断路器仅在其执行后改变行为。值得注意的是,尽管断路器在配置中声明了一次,但它配置为每个路由的单独实例。Traefik 可以通过以下指标检测服务错误率。

  • 延迟 : Traefik 可以测量服务分位数延迟时间。如果测量的时间超过一个配置值(如LatencyAtQuantileMS(50.0) > 100 ) .该参数指定分位数,则断路器可被触发。

  • 网络错误:测量网络错误率(如NetworkErrorRatio() > 0.30)。

  • 响应代码 : Traefik 可以测量服务响应状态代码(如ResponseCodeRatio(500, 600, 0, 600) > 0.25 ) .这里的四个参数是 HTTP 状态代码。

    • 错误状态代码来自

    • 错误状态代码至

    • 申请状态代码自

    • 申请状态代码至

这些度量值中的每一个都可以通过使用以下操作符来检查。

  • 大于(>)

  • 大于或等于(> =)

  • 小于(

  • 小于或等于(< =)

  • 等于(==)和

  • 不等于(!=)运算符

您还可以使用 AND (&&)和 OR (||)运算符组合两个或多个指标。当 Traefik 确定触发了断路器时,它不会将呼叫转发到目标服务;相反,它返回 503 响应。(参见图 6-10 )

Traefik 微服务 API 网关教程(二)

图 6-10

交通断路器

现在让我们将以下响应状态断路器添加到 over services 中。

$ consul kv import "$(cat circuitbreaker.json)"
Imported: traefik/http/middlewares/response-check/circuitbreaker/expression
Imported: traefik/http/routers/petclinic-customers-route/middlewares/1

  • 1
  • 2
  • 3
  • 4

我们为配置中的客户服务路径添加了断路器中间件。当客户服务返回 500 错误代码时,断路器被触发。Traefik 还在仪表板上显示断路器中间件配置。(见图 6-11 )

Traefik 微服务 API 网关教程(二)

图 6-11

带断路器的路线

重试次数

在动态生态系统中,服务实例可以处于开始状态。可能会出现间歇性网络连接错误。这些瞬时误差通常是自校正的。如果您重试服务呼叫,很可能会成功。重试是使应用容错的另一种机制。

重试模式规定您可以重试失败的请求。重要的是要确定这种方法可能导致的故障。如果应用报告一个无效的数据错误,那么它很可能在重试时不起作用。此外,在整个系统中传播的失败请求会产生不必要的瓶颈。另一方面,如果请求由于连接或响应超时而失败,则重试成功的可能性很高。

Traefik 通过使用重试中间件来支持重试模式,如果出现超时错误,重试中间件会向服务重新发出指定次数的请求。一旦有来自服务的响应,中间件就停止重新发布。中间件 done 验证收到的响应是否是错误的。我们可以添加重试中间件配置,并按照以下方式为路由启用它。

$ consul kv import "$(cat retry.json)"
Imported: traefik/http/middlewares/retry-check/retry/attempts
Imported: traefik/http/routers/petclinic-vets-route/middlewares/1

  • 1
  • 2
  • 3
  • 4

我们将重试中间件配置为四次重试。中间件应用于配置中的 vets-service 路由。很难测试这样的配置。该配置适用于服务响应缓慢的情况。只有在连接超时的情况下,才会复制该错误。这些是实际的网络错误。请求超时时,重试机制不起作用。在这些情况下,请求由服务处理,但是处理可能非常慢。如果重试这样的请求,可能会导致意想不到的问题,如帐户借记请求中的双重借记。

只有在 Traefik 中配置了超时,重试才能正常工作。这是全局级别的配置。Traefik 提供 serverstransport . forwarding time out 静态配置属性,可以控制服务器的超时。

  • idleConnTimeout:指定空闲连接在关闭前保持空闲的最长时间

  • responseHeaderTimeout:指定等待服务器响应头的时间

  • dialTimeout:指定建立连接所花费的时间

serversTransport:
  forwardingTimeouts:
    responseHeaderTimeout: 1s
    dialTimeout: 1s
    idleConnTimeout: 1s

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

我们在配置中为服务响应和空闲连接配置了一秒超时。让我们重新启动 Traefik,并在仪表板上验证重试中间件配置。

Traefik 微服务 API 网关教程(二)

图 6-12

重试路由

该配置显示,对于失败的请求,将执行三次重试。

节流

在微服务架构中,不同的服务协作提供用户价值。这包括将企业集成技术应用到应用中,以解决各种问题。应用集成中的一个常见问题是控制资源消耗。有些资源的创建成本很高,因此它们的访问必须通过服务级别协议来控制。节流是一种通过发送比服务级别协议更多的请求来控制不当行为或欺诈服务的方法。如果临界区服务失败,将此应用于临界区服务作为整个生态系统停止是必要的。这有助于改进应用容量规划。

节流通常通过拒绝溢出请求来实现。Traefik 通过使用限速中间件支持节流。它可以测量特定来源在规定时间内的平均调用次数。如果中间件调用的调用超过了配置的限制,它会向源服务发送 HTTP 状态 429(调用太多)。中间件提供了以下三个属性来配置 API 比率。

  • 平均值:统计配置周期内的请求数

  • 周期:指定时间(费率定义为平均调用次数/周期)

  • Burst :指定如何在短时间内处理最大请求

有控制信号源识别的选项。我们可以为 vets 服务启用限速中间件。

$ consul kv import "$(cat ratelimit.json)"
Imported: traefik/http/middlewares/ratelimit-check/ratelimit/average
Imported: traefik/http/middlewares/ratelimit-check/ratelimit/period
Imported: traefik/http/routers/petclinic-vets-route/middlewares/2

  • 1
  • 2
  • 3
  • 4
  • 5

Traefik 更新配置并显示在仪表板中,如图 6-13 所示。

我们将速率定义为 1 个请求/30 秒。如果我们尝试对/ api/vets/vets发出几个请求,您会看到下面的响应。

Request URL: http://localhost/api/vet/vets
Request Method: GET
Status Code: 429 Too Many Requests
Remote Address: [::1]:80
Referrer Policy: no-referrer-when-downgrade

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Traefik 微服务 API 网关教程(二)

图 6-13

节气门仪表板

中间件链

Traefik 提供了一个链式中间件,可用于简化跨不同服务应用的配置。链式中间件可以用来按顺序对中间件进行分组。整个组可以应用于一个路由,消除了单独应用每个中间件的需要。通过向链中间件属性提供一个逗号分隔的列表来指定完整的链。在这个场景中,我们可以将链配置为由断路器和速率限制中间件组成。

$ consul kv import "$(cat chain-list.json)"
Imported: traefik/http/middlewares/chain-list/chain/middlewares
Imported: traefik/http/routers/petclinic-customers-route/middlewares/0

  • 1
  • 2
  • 3
  • 4

Traefik 更新配置并显示在仪表板中,如图 6-14 所示。

Traefik 微服务 API 网关教程(二)

图 6-14

链式中间件

金丝雀部署

Traefik 使用加权循环法支持 Canary 部署。在上一节中,我们添加了ServiceRegistry类来添加实例细节。这些实例以循环方式使用。在第三章中,我们讨论了加权循环法,权重被添加到服务器实例中。Traefik 按照提供权重的比率划分收到的请求。当我们开始新的实例时,你会在咨询服务注册中心看到新的服务(见图 6-15 )。可以从 UI 为每个实例添加权重。

Traefik 微服务 API 网关教程(二)

图 6-15

多个实例

将请求子集重定向到新服务是 canary 部署的基础之一。该机制可以通过使用 Consul 客户端来实现自动化。但是完整的端到端流程需要额外的组件来提供和部署新发布的版本。

Note

本章将 Traefik 与 Consul KV store 集成在一起。Traefik 还提供了与 Zookeeper 和 etcd 的集成。与他人的配置类似于基于 Consul 的集成,但是有些特性不能像预期的那样工作。

摘要

在本章中,我们部署了一个基于微服务的解决方案,并将 Traefik 配置为它的网关。我们使用了微服务的咨询服务注册。启用 Traefik 从 Consul KV 存储中读取配置。Traefik 可以检测 KV 存储中的更新并执行热重装。这使得配置在像微服务这样的动态生态系统中保持更新。

服务可以在它们启动/关闭时注册/注销它们。这些更新由 Traefik 挑选,它提供了可以在微服务架构中配置的中间件。本章介绍了断路器、重试、速率限制和链式中间件。它还研究了基于加权轮询的部署,这种部署可以拆分 canary 部署的请求。在下一章中,我们将在编排引擎上部署微服务解决方案并配置 Traefik。

七、作为 Kubernetes 入口的 Traefik

在最后一章中,您将尝试 Traefik 与 Kubernetes 容器编排平台的本机集成。Kubernetes 无疑是最受欢迎的容器微服务平台。Traefik 与 Kubernetes 紧密结合,可以充当 Kubernetes 生态系统中的一等公民。您已经尝试了 Traefik 的许多网关功能。本章探讨了这些功能如何轻松地映射到 Kubernetes 入口概念。您还可以看到 Traefik 与 Jaeger 的简单集成,Jaeger 是一个特定于 Kubernetes 的分布式跟踪解决方案。

Note

与前几章一样,重点仍然是 Traefik 如何与 Kubernetes 生态系统集成,而不是它的高级特性。我们假设您对 Kubernetes 原语有基本的了解,因此我们只解释 Traefik 如何映射到它们。

trafik 作为 kubernetes 入口控制器

Kubernetes 主要是一个 orchestrator/scheduler 和一个支持所需状态配置的 API 服务器。通常,客户端向 Kubernetes API 服务器提交声明性的 YAML 资源请求,Kubernetes 相应地提供所请求的资源。对于 Kubernetes API 服务器支持的每一种资源类型,比如部署或服务,默认的 Kubernetes 控制器会处理和提供提交的资源请求。一个例外是入口资源类型。

入口对象在单个资源中定义流量路由规则(例如,负载平衡、SSL 终止、基于路径的路由),以在集群外部公开多个服务。根据 Kubernetes 官方文档:

Ingress 是允许入站连接到达后端定义的端点的规则集合。入口可以被配置为向服务提供外部可达的 URL、负载平衡流量、终止 SSL ,提供基于名称的虚拟主机等。

这与 Traefik 充当 API 网关的方式没有太大区别。入口控制器是负责提供提交的入口请求的组件。Kubernetes 不附带默认入口控制器。第三方供应商提供实现。有一个参考(也是广泛使用的)基于 nginx 的 nginx-ingress-controller(它有三个不同的版本),但是最终用户可以自由部署他们喜欢的任何其他 ingress 控制器。在本章中,我们将 Traefik 作为入口控制器的选择。

Traefik 在早期版本中支持 Ingress API。但是在 Traefik v2 中,他们对配置方法做了一些更改。这是由于入口 API 中的限制,这些限制困扰着规范。

Ingress API 规范花了很长时间进行测试。自 Kubernetes 版本 1.2 以来,它一直处于 v1beta1 状态。该规范仅在 2019 年正式定稿,并在 Kubernetes 版本中获得 GA 地位。基本规范相当简单,但是在各种各样的实现中制定一致的标准是一个挑战。没有好的方法来传递特定于供应商的配置,以针对特定的实现进行微调。实现者开始在 YAML 定义中的许多自定义注释中定义特定于供应商的配置,导致了空间的碎片化。Traefik 的旧版本遵循相同的方法。还有一些歧义,比如结尾的“/”处理得不一致(也有问题)。最终,规范是不精确的,既不是可移植的,也不是功能丰富的,所以拥有一个标准 API 的初衷从未实现。许多第三方供应商没有采用 ingress 规范,而是将 LoadBalancer 服务类型与他们自己的定制配置一起使用——同样是通过注释。一旦规范最终确定,大使 API Gateway 将在 2019 年建立入口支持。

大多数 Kubernetes 社区现在已经脱离了定制注释(对于其他用例也是如此)和入口规范,而转向定制资源定义 (CRDs)。CRD 在集群中定义了一个新的对象种类,并让 Kubernetes API 服务器处理它的生命周期。Kubernetes 是一个对扩展开放的系统,允许外部实现者定义他们的自定义资源 API 定义,并运行自定义控制器来处理这些自定义 API 资源。

第三方的 ingress 实现被重组为他们定义的 CRD 的 Kubernetes 控制器。Contour 是首批引入 CRD 进行配置的入口 API 网关之一。甚至 Ambassador Gateway 现在也推荐使用自己的 CRDs,而不是新的 ingress 支持。Traefik 紧随其后,Traefik v2 引入了 IngressRoute(和其他)CRD,为在 Kubernetes 中配置 Traefik 路由提供了一种更好的方式。

Traefik 现在有两个独立的 Kubernetes 提供商。一个是传统的 Kubernetes ingress 提供程序,其中 Traefik 的行为与任何其他 Kubernetes ingress 控制器完全一样,并使用许多自定义注释。另一个是 Kubernetes CRD 提供商,这是我们本章的重点。Traefik 的所有入口配置都使用 Traefik 的 IngressRoute 和其他 CRD 提交给 Kubernetes。这为在 Kubernetes 上配置 Traefik 提供了更好的体验,是目前推荐的方法。

Note

在这一章中,服务这个词是重载的。服务的常见含义是公开 API 的应用,这是我们通常使用的术语。在 Traefik 配置的上下文中还有一个服务,它指向一个实际的后端服务。在这一章中,还有一个 Kubernetes 服务,这就是 Kubernetes 如何将流量路由到 pods。为了避免混淆,我们明确地说明了所有事件的含义。

在 kubernetes 安装 trafik

在本章中,我们将在一台笔记本电脑上运行一个本地 Kubernetes 集群来进行 Traefik 安装和配置。本地 Kubernetes 的安装不在本书讨论范围之内,但是从官网设置应该不会太复杂。我们在不同的场景下使用 microk8s ( https://microk8s.io/ )(在 macOS 上运行多次)或 minikube ( https://minikube.sigs.k8s.io/docs/ )。

Microk8s 使得一些高级 Kubernetes 应用的设置变得非常简单,而 minikube 是运行 Kubernetes 本地版本的事实上的标准。您可能更喜欢使用您喜欢的任何其他 Kubernetes 风格,例如启用了 Kubernetes 的 Docker Desktop。您也可以使用基于云的托管产品。此外,我们针对后面的几种情况转向托管云产品。

我们预计本地和云 Kubernetes 之间的 Traefik 配置和安装不需要任何更改。使用云产品的原因是为了再次使用公共 TLS 证书(类似于第四章)。对于使用 Let’s Encrypt 的 TLS 终止,我们在 DigitalOcean (DOKS)上提供了一个云 Kubernetes 集群。如果你愿意的话,你可以选择使用其他品牌,如 GKE、AKS 或 EKS。我们概述的大多数步骤应该可以在任何 Kubernetes 发行版上按原样工作。

我们已经运行了本地的 Kubernetes 集群。所有对 Kubernetes API 服务器的请求都是通过 kubectl CLI 进行的,它通常与本地 Kubernetes 发行版一起安装。Kubectl 需要一个 kube 上下文配置来指向我们的目标 Kubernetes 集群。我们首先在集群上手动安装 Traefik。然后,我们将在后面的小节中探索一种更简单的安装机制。为了在 Kubernetes 上启动和运行 Traefik,我们需要三部分配置。

  • Kubernetes RBAC 配置给 Traefik 足够的权限与 API 服务器对话。

  • 我遇到了 CRD

  • 实际的交通部署

Note

这些是标准的 Traefik 部署文件。我们鼓励您在 https://docs.traefik.io/providers/kubernetes-crdhttps://docs.traefik.io/routing/providers/kubernetes-crd 从 Traefik 文档中获取所有这些的更新版本。

# First install the RBAC security configuration
% kubectl apply -f traefik-rbac.yml
clusterrole.rbac.authorization.k8s.io/traefik-ingress-controller created
clusterrolebinding.rbac.authorization.k8s.io/traefik-ingress-controller created

# RBAC configuration details, full configuration omitted for brevity
rules:
  - apiGroups:
      - ""
    resources:
      - services
      - endpoints
      - secrets
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - extensions
    resources:
      - ingresses
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - extensions
    resources:
      - ingresses/status
    verbs:
      - update
  - apiGroups:
      - traefik.containo.us
    resources:
      - middlewares
      - ingressroutes
      - traefikservices
      - ingressroutetcps
      - ingressrouteudps
      - tlsoptions
      - tlsstores
    verbs:
      - get
      - list
      - watch

Listing 7-1Installing Traefik RBAC via kubectl

Traefik 微服务 API 网关教程(二)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

同样,Kubernetes 提供了一个声明性的 API 服务器,所以清单 7-1 中的 RBAC 配置向 Kubernetes 服务授予 Traefik 读取权限,并在它的自定义资源上使用traefik.containo.us API 组(尽管我们还没有安装 CRDs)。Traefik 可以观察这些类型的对象的变化,并相应地重新配置自己。接下来,我们安装清单 7-2 中的 Traefik CRDs。

% kubectl apply -f traefik-crd.yml
customresourcedefinition.apiextensions.k8s.io/ingressroutes.traefik.containo.us created
customresourcedefinition.apiextensions.k8s.io/middlewares.traefik.containo.us created
customresourcedefinition.apiextensions.k8s.io/ingressroutetcps.traefik.containo.us created
customresourcedefinition.apiextensions.k8s.io/ingressrouteudps.traefik.containo.us created
customresourcedefinition.apiextensions.k8s.io/tlsoptions.traefik.containo.us created
customresourcedefinition.apiextensions.k8s.io/tlsstores.traefik.containo.us created
customresourcedefinition.apiextensions.k8s.io/traefikservices.traefik.containo.us created

# IngressRoute CRD

apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: ingressroutes.traefik.containo.us

spec:
  group: traefik.containo.us
  version: v1alpha1
  names:
    kind: IngressRoute
    plural: ingressroutes
    singular: ingressroute
  scope: Namespaced

# Rest omitted for brevity

Listing 7-2Installing Traefik CRDs via kubectl

Traefik 微服务 API 网关教程(二)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

我们安装了清单 7-2 中列出的 7 个 CRD。这些都是为不同类型的自定义配置提供的 CRDs Traefik。这个数字将来可能会增加。我们没有挑挑拣拣,而是把它们全都安装了。我们列出了 Ingres route CRD,它在接下来的部分中被大量使用。具体细节不是很有意思。需要安装 CRDs,以便 Traefik 可以监视对 API 服务器的任何这类定制资源请求,并对其进行操作。Traefik 充当 Kubernetes 控制器,对这些自定义资源类型进行操作。根据清单,每种不同类型的 Traefik 特定配置都有不同的 CRD。这是新 CRD 方法带给我们的一大优势。早些时候,很多这样的内容会被定义为标准入口资源上的自定义注释。

接下来,我们安装 Traefik(参见清单 7-3 )。我们将 Traefik 安装为带有一个 pod 的 Kubernetes 部署。Kubernetes 始终保持至少一个 Traefik 实例运行。由于 Traefik 是一个无状态服务,所有配置都来自 Kubernetes,因此即使 pod 重新启动,Traefik 也会保留配置。

% kubectl apply -f traefik.yml
serviceaccount/traefik-ingress-controller created
deployment.apps/traefik created
service/traefik created

Listing 7-3Traefik Installation via kubectl

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

至此,Traefik 已经安装并运行在我们的集群上。在 Kubernetes 的上下文中,安装应用和运行应用没有区别。它会在容器中自动启动。让我们看看清单 7-4 中的一些部署配置。

# Many fields omitted for brevity
kind: Deployment
metadata:
  name: traefik
spec:
  replicas: 1
  template:
    spec:
      containers:
        - name: traefik
          image: traefik:v2.2 #the Traefik Docker image used
          args:
            - --log.level=DEBUG
            - --api.insecure
            - --api.dashboard
            - --entrypoints.web.address=:80
            - --entrypoints.traefik.address=:8080
            - --providers.kubernetescrd
          ports:
            - name: web
              containerPort: 80
            - name: traefik
              containerPort: 8080
kind: Service
metadata:
  name: traefik

spec:
  type: NodePort
  ports:
    - protocol: TCP
      port: 80
      name: web
      targetPort: 80
    - protocol: TCP
      port: 8080
      name: traefik
      targetPort: 8080

Listing 7-4Traefik Deployment Configuration

Traefik 微服务 API 网关教程(二)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

我们在清单 7-4 中列出了 Traefik 部署和服务的部分配置。您可以看到要部署的映像版本和副本的数量。Traefik 作为一个无状态服务运行,其状态由 Kubernetes 管理,因此根据需要运行多个副本进行扩展是没有问题的(因为它不必形成有状态的集群)。

有趣的部分是静态配置。动态 Traefik 配置全部由 Kubernetes 提供者在运行时提供,包括 Traefik 路由和 Traefik 服务。然而,静态配置——比如入口点和提供者——仍然需要在启动时提供。为此,Traefik 利用了常用的 CLI 参数方法。这是为 Docker 和 Kubernetes 传递 Traefik 静态配置的常用方式。我们从两个入口点开始:一个用于 HTTP 流量,另一个用于仪表板。我们还在不安全模式下公开仪表板,因为我们在本地运行,并将日志设置为所需的级别。这都是典型的东西。

新标志是--providers.kubernetescrd值。这确保了 Traefik 可以根据 Kubernetes CRDs 配置自己。微妙的是,它只选择新的基于 Traefik 的 CRD。如果您还希望 Traefik 充当标准的 Kubernetes 入口控制器,您必须传递--providers.kubernetesingress标志。您可以启用一个或两个提供程序。您还公开了 Traefik 端口本身,因此 Kubernetes 可以注册它们。不要忘记 Traefik 是作为 NodePort 类型的 Kubernetes 服务在集群外部公开的。服务如清单 7-5 所示。

% kubectl get svc traefik
NAME    TYPE       CLUSTER-IP     PORT(S)
traefik NodePort   10.110.30.69   80:31624/TCP,8080:32529/TCP

Listing 7-5Traefik Kubernetes Service

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

不管 Traefik 运行在哪个 Kubernetes worker 节点上(本地只有一个), Kubernetes 都会将任何 worker 节点上公开的节点端口上的任何传入流量转发给正在运行的 Traefik 实例。如果有多个 Traefik pods,Kubernetes 会自动在它们之间对请求进行负载平衡。这是节点端口服务类型的常见 Kubernetes 行为。在云场景中,我们将使用 Traefik 服务的负载平衡器类型,它启动云负载平衡器来公开 Traefik 服务,所有对 Traefik 的请求都通过负载平衡器 IP。云平台运行负载均衡器。在本地,我们通常使用节点端口,尽管一些本地 Kubernetes 发行版现在也通过特殊机制支持负载平衡器。

现在让我们看看 Kubernetes 公开的端口 31624 上的默认 Traefik 后端(见图 7-1 )。此端口由 Kubernetes 随机分配,可能会有所不同。这会将请求转发到 HTTP 端口 80 上的 Traefik web 入口点。由于没有为这个入口点配置默认路由,我们照常得到 404。请注意,IP 地址是 minikube 虚拟机的本地 IP,可以使用minikube ip命令.访问

Traefik 微服务 API 网关教程(二)

图 7-1

节点端口入口点上的默认后端

我们还暴露了另一个端口上的 Traefik 仪表板,以检查配置(参见图 7-2 )。配置了两个入口点:traefikwebtraefik入口点服务于仪表板路由,而web用于所有其他 HTTP 流量。请注意,Traefik 文档建议不要在实际生产使用中以不安全的模式公开仪表板。第四章讲述了如何通过 TLS 安全地暴露仪表板。对于本地使用,现在可以这样访问它。

Traefik 微服务 API 网关教程(二)

图 7-2

使用仪表板入口点的流量部署

如果您向下滚动到 Providers 部分,您会看到 Kubernetes CRD 提供商已启用(参见图 7-3 )。在前面的章节中,我们使用了 FileProvider 和 Consul provider。旧的 Kubernetes 入口提供程序未启用,因此 Traefik 不作用于标准入口资源。

Traefik 微服务 API 网关教程(二)

图 7-3

使用 kubernetes crd 提供程序进行 trafik 部署

接下来,我们在集群上部署一个 Kubernetes 服务,并尝试通过traefik入口点访问它。

安装 bookinfo 应用

现在 Traefik 已经启动并运行,让我们将一个微服务风格的应用部署到我们的集群中,它可以通过 Traefik 公开。为此,我们使用 Istio 文档中的 BookInfo 示例应用( https://istio.io/latest/docs/examples/bookinfo/ )。这个应用由几个不同的容器化微服务组成,虽然它主要是 Istio 服务网格的一个展示窗口,但我们可以将其用于 Traefik。

请注意,我们也可以使用上一章中的 Spring PetClinic 应用。然而,在撰写本文时,这个应用还不完全是 Kubernetes 的原生程序。我们必须做一些调整才能在 Kubernetes 上运行它。BookInfo 构建为运行在 Kubernetes 之上,因此我们可以直接关注部署后的部分。我们对它的实际代码不感兴趣。部署后,通过 Traefik 公开的唯一服务是主 web 应用,名为productpage

web 应用在内部调用其余的服务。BookInfo 有许多不同的部署配置。我们只对基本部署感兴趣。这个文件在 https://github.com/istio/istio/blob/master/samples/bookinfo/platform/kube/bookinfo.yaml 。你可以下载它或者直接用原始网址应用它(参见清单 7-6 )。

% kubectl apply -f bookinfo.yml
service/details created
serviceaccount/bookinfo-details created
deployment.apps/details-v1 created
service/ratings created
serviceaccount/bookinfo-ratings created
deployment.apps/ratings-v1 created
service/reviews created
serviceaccount/bookinfo-reviews created
deployment.apps/reviews-v1 created
deployment.apps/reviews-v2 created
deployment.apps/reviews-v3 created
service/productpage created
serviceaccount/bookinfo-productpage created
deployment.apps/productpage-v1 created

Listing 7-6Install bookinfo Services

Traefik 微服务 API 网关教程(二)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

部署和服务启动后,我们可以继续应用 IngressRoute。这很标准。它只是公开了 web 应用需要从浏览器调用的所有路径。我们必须创建自己的来与 Traefik 合作。然后,我们可以在 HTTP web 节点端口上访问 BookInfo 应用。首先,让我们看看 BookInfo 的 Kubernetes 服务中有哪些是可用的(参见清单 7-7 )。

% kubectl get svc
NAME          TYPE        CLUSTER-IP        PORT(S)
details       ClusterIP   10.111.105.145    9080/TCP
productpage   ClusterIP   10.101.6.99       9080/TCP
ratings       ClusterIP   10.102.103.167    9080/TCP
reviews       ClusterIP   10.103.10.20      9080/TCP

% kubectl get deploy
NAME             READY   UP-TO-DATE   AVAILABLE
# 3 separate reviews deployments, rest omitted for brevity
reviews-v1       1/1     1            1
reviews-v2       1/1     1            1
reviews-v3       1/1     1            1

Listing 7-7BookInfo Services

Traefik 微服务 API 网关教程(二)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

清单 7-7 是一组创建的 ClusterIP 类型的服务。这意味着它们可以相互通信,但在群集之外无法访问。我们必须使用 IngressRoute 公开的唯一服务是productpage服务。这是 BookInfo 的主要 web 应用,服务于端口 9080 上的请求。

我们可以为此服务应用一个 IngressRoute 自定义资源,以通过 Traefik 公开它。让我们首先来看看清单 7-8 中这个资源的一些配置。您可以看到它大体上匹配我们通常通过 FileProvider 定义的动态配置。定义了一个入口点,并使用通常的匹配规则进行路由。有趣的部分是后端服务配置通常所在的部分。在这里,您可以看到我们直接引用了一个 Kubernetes 服务并通过 Traefik 路由找到了它。因此,IngressRoute 或多或少定义了从入口点到后端 Kubernetes 服务的 Traefik 路由。如果需要,我们也可以在这里参考 Traefik 中间件。

spec:
  entryPoints:
    - web
  routes:
  - match: PathPrefix(`/productpage`) || PathPrefix(`/static`) || Path(`/login`) || Path(`/logout`) || PathPrefix(`/api/v1/products`)
    kind: Rule
    services:
    - name: productpage
      port: 9080

% kubectl apply -f bookinfo-product-ingress.yml
ingressroute.traefik.containo.us/bookinfo-productpage-ingress created

% kubectl get IngressRoute
NAME                           AGE
bookinfo-productpage-ingress   29s

Listing 7-8BookInfo IngressRoute

Traefik 微服务 API 网关教程(二)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

一旦服务在入口公开,我们就可以很容易地查看网页(见图 7-4 )。这在内部调用其他 BookInfo 服务来填充页面每个部分的数据。由于点评服务由三个不同的点评部署支持(如清单 7-7 所示),该网页在每个请求上看起来可能略有不同。

Traefik 微服务 API 网关教程(二)

图 7-4

BookInfo 产品页面 UI

我们现在可以在 Traefik 仪表板中检查配置。您会看到路由器和服务配置显示出来。IngressRoute 已经自动创建了一个路由器和一个服务(Traefik 抽象,而不是 Kubernetes 抽象,尽管在本例中它们是相同的)。Kubernetes 服务由 Traefik 自动发现,并被视为 Traefik 中的服务抽象。您可以在如图 7-5 和 7-6 所示的仪表盘中看到路由器和服务信息。

Traefik 微服务 API 网关教程(二)

图 7-6

产品页面入口服务

Traefik 微服务 API 网关教程(二)

图 7-5

产品页面路由器

如果您浏览服务配置中的服务器(我们通常在这里定义后端服务的负载平衡器 IP),您会看到相应 Kubernetes 服务的 pod IPs(参见图 7-6 )。Traefik 可以自动检查来自 Kubernetes 的这些细节,并处理内部的 Kubernetes 网络(它需要这样做)。当 pod 发生任何变化时(例如,放大或缩小、pod 重新启动等。)时,Traefik 会自动选择它。这与上一章形成了有趣的对比。在那里,我们必须使用 Consul 提供者来跟踪服务,从而将 Traefik 与 Consul 服务注册中心集成起来。然而,Kubernetes 提供开箱即用的服务发现,Traefik 可以直接与 Kubernetes 对话以获取服务细节。

Note

此上下文中的 LoadBalancer 是指用于指定多个后端服务 IP 的 Traefik 配置,而不是 Kubernetes LoadBalancer。

如果还不清楚的话,这个例子说明了 IngressRoute 是如何以 CRD 风格实现 Traefik HTTP 路由器的。这是使用 CRD 方法优于普通入口的优势,它允许您更接近 Traefik 风格的配置。

安装带舵的 trafik

在上一节中,我们成功地在 Kubernetes 上部署了 Traefik,并使用它来公开服务。基本配置涉及一些不同的手动步骤。使用更高级的 Traefik 配置,所需的手动步骤可能会很快变得难以操作,特别是当我们希望随着时间的推移调整静态配置或定期升级 Traefik 时。对于生产安装,我们使用一个名为 Helm ( https://helm.sh/ )的包和发布管理器在 Kubernetes 上安装 Traefik。在 Helm 中,一个可部署的工件被捆绑到一个图表中,该图表封装了随着时间的推移安装和升级该软件所需的所有资源,包括配置和依赖关系。有一个 Traefik 舵图,我们从现在开始使用它来安装/升级 Traefik。Helm 重用由 kubectl 设置的当前 kubeconfig。我们已经安装了 Helm v3 的最新版本,并且我们的 kubeconfig 设置指向我们的本地 Kubernetes 集群。

中央 Helm 资源库(类似于 Maven central、PyPi 或 Debian apt 资源库)中可用的 Traefik 版本是较旧的 Traefik v1.7 版本。因此,在通过 Helm 安装 Traefik v2 之前,我们需要运行几个高级步骤(参见清单 7-9 )。这些注册了 Traefik v2 Helm 存储库,因此我们可以使用 Helm 安装 Traefik v2。确保您不会意外安装旧版本;它不支持 IngressRoute CRDs,并且工作方式有些不同。

% helm repo add traefik https://containous.github.io/traefik-helm-chart
"traefik" has been added to your repositories

% helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "traefik" chart repository
Update Complete. ☼ Happy Helming!☼

Listing 7-9Adding Traefik’s Helm repository

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

一旦完成,我们就可以使用 Traefik v2 的官方导航图安装它了。因为我们已经手动安装了 Traefik,所以我们需要重置整个集群(在 minikube 上很容易完成),或者删除到目前为止安装的所有东西。现在让我们进行全新安装。

探索 trafik 掌舵图

Traefik Helm chart 安装了将 Traefik 作为入口控制器运行所需的所有先决条件,包括 Kubernetes RBAC 配置和用于配置路由规则的 CRDs。除了一个例外,安装在本地或云 Kubernetes 上的方式是一样的。在托管云服务中,Traefik ingress 通过使用类型为 LoadBalancer *的 Kubernetes 服务向外界公开。*这会在所有 Kubernetes 节点前自动启动托管云负载平衡器,并将所有传入流量路由至 Traefik 入口控制器。对于外部世界,单一入口点是云负载平衡器的 IP 或 DNS 名称。

裸机或本地虚拟机上不提供负载平衡器。Minikube 和 microk8s 可以通过一种特殊的机制来处理这个问题,尽管使用节点端口通常更简单。您需要确保您选择的 Kubernetes 发行版支持 LoadBalancer 类型的服务。否则,您必须将 Traefik 入口公开为 NodePort 类型的 Kubernetes 服务。这必须在舵安装期间通过定制舵图表值来解决。这可以通过在命令行中将它们传递给 Helm 来实现,或者更好的方法是为自定义值定义一个文件,该文件可以在安装过程中覆盖默认值。

让我们来看看舵图上的一些默认值( https://github.com/containous/traefik-helm-chart/blob/master/traefik/values.yaml )以及一些我们想要定制的值(参见清单 7-10 )。

# Configure the deployment with number of pods
deployment:
  replicas: 1

# IngressRoute for the dashboard will be installed
ingressRoute:
  dashboard:
    enabled: true

# Configure both types of dynamic Traefik providers
providers:
  kubernetesCRD:
    enabled: true
  kubernetesIngress:
    enabled: true

# Configure ports
ports:
  traefik:
    port: 9000
            # As recommended, the dashboard is not exposed by default in production
    expose: false
# The HTTP and HTTPS ports are opened by default
  web:
    port: 8000
    expose: true
  websecure:
    port: 8443
    expose: true

service:
  enabled: true
  type: LoadBalancer

rbac:
  # False value indicates Traefik can be used cluster-wide across all namespaces.
  namespaced: false

Listing 7-10Some of the Default Values in Traefik Helm Chart values.yaml

Traefik 微服务 API 网关教程(二)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

这不是任何一种标准的库本内特人清单。这些只是应用于 Helm 图表中 Kubernetes YAMLs 的 YAML 格式的配置值。默认情况下,它具有以下配置。

  • trafik 的一个实例在 kubernetes pod 中运行

  • Traefik 服务通过负载平衡器公开。这可能不适用于非云集群。

  • 旧的和新的动态配置 Kubernetes 提供者都被启用。因此 Traefik 监视标准入口和 Traefik 的自定义入口路由资源。

  • 打开了三个入口点:一个名为 9000 上的traefik,另外两个用于 HTTP 和 HTTPS 流量。稍后我们将进一步探讨这个额外的入口点。

  • 将自动创建仪表板的 IngressRoute 自定义资源。但是,仪表板入口点不会向 Traefik Kubernetes 服务公开。这有点不一致和混乱,因为 Traefik 建议在生产中为仪表板创建您自己的安全入口。但是,我们可以在本地利用这个 IngressRoute。这种行为在我们能找到的任何地方都没有记录,所以将来可能会改变。

掌舵图的 default values.yaml 里有很多这样的条目。我们鼓励您自行探索进一步的配置。大部分都与在 Kubernetes 上可靠地运行 Traefik 有关。例如,未启用 Traefik pods 在负载下的自动缩放;如果需要,可以打开它。请注意,在写这本书的时候,这些观察是为了舵图的当前状态。图表继续发展。

在我们定制这些值之前,我们可以使用helm template命令来查看默认生成的部署清单。这些非常类似于我们在前面几节中用来手动安装 Traefik 的内容。让我们运行命令,看看最终的配置是什么样的。由于产量很多,我们只关注其中的几块。鼓励您自己运行该命令来查看完整的输出(参见清单 7-11 )。

% helm template traefik traefik/traefik

# Partial values in the output
# Deployment configuration
       #Kubernetes liveness probe
        readinessProbe:
          httpGet:
            path: /ping
            port: 9000

       #Kubernetes liveness probe
        livenessProbe:
          httpGet:
            path: /ping
            port: 9000

       # Traefik CLI arguments
        args:
          - "--entryPoints.traefik.address=:9000/tcp"
          - "--entryPoints.web.address=:8000/tcp"
          - "--entryPoints.websecure.address=:8443/tcp"
          - "--api.dashboard=true"
          - "--ping=true"
          - "--providers.kubernetescrd"
          - "--providers.kubernetesingress"

# Service configuration
  type: LoadBalancer
  ports:
  - port: 80
    name: web
    targetPort: "web"
    protocol: "TCP"
  - port: 443
    name: websecure
    targetPort: "websecure"
    protocol: "TCP"

# IngressRoute
kind: IngressRoute
metadata:
  name: traefik-dashboard
spec:
  entryPoints:
    - traefik
  routes:
  - match: PathPrefix(`/dashboard`) || PathPrefix(`/api`)
    kind: Rule
    services:
    - name: api@internal
      kind: TraefikService

Listing 7-11Generated Helm Template with Default Values

Traefik 微服务 API 网关教程(二)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54

让我们来分析一下清单 7-11 中我们捕捉到了什么。静态配置通常通过 CLI 参数提供。我们已经提到了三个入口点和两个提供者。您还可以看到仪表板启用标志。您还会看到ping Traefik 服务已启用。我们稍后在仪表板中查看它;它暴露于/ping路径下的traefik端口。它为 Kubernetes 定期检查 Traefik pods 的健康状况提供了一种标准方法。如果健康探测失败,Kubernetes 会自动重启 Traefik pods。这提供了一种在 Kubernetes 上运行 Traefik 的弹性方法。

您会看到创建了一个 Ingres routetraefik-dashboard来公开集群外部的仪表板。这在默认安装中不起作用。原因是 Traefik 的服务配置中不包括traefik入口点端口 9000。虽然可以在集群内部访问它以进行运行状况检查,但是不能通过节点端口访问它,并且无法到达该入口点来访问控制面板。

要在安装/升级时自定义一些默认值,我们可以在文件中覆盖它们,并将其提供给 Helm CLI。让我们看看清单 7-12 中我们想要定制的值。虽然仪表板在生产中没有公开,但我们在这里覆盖了traefik入口点的配置,使仪表板在本地可用。我们将 Traefik 服务更改为 NodePort 类型,并将日志级别设置为INFO。如您所见,Traefik 静态配置仍然提供了 CLI 参数。舵轮图显示了一个additionalArguments特殊键来传递额外的参数。

additionalArguments:
  - "--log.level=INFO"
ports:
  traefik:
    expose: true
service:
  type: NodePort

Listing 7-12custom-values.yml for Traefik Helm Chart

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

让我们再次运行 Helm template 命令,查看生成的带有自定义值的部署清单。我们仅在清单 7-13 中列出新的/修改的值。这使用了我们在清单 7-12 中详述的同一个custom-values.yml文件。

% helm template --values=custom-values.yml traefik traefik/traefik

# Partial changed values in the output
# Deployment configuration
       # Traefik CLI arguments
        args:
          - "--log.level=INFO"

# Service configuration
  type: NodePort
  ports:
  - port: 9000
    name: traefik
    targetPort: "traefik"

Listing 7-13Generated Helm Template with Custom Values

Traefik 微服务 API 网关教程(二)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

现在,我们可以使用此配置访问集群外部的 Traefik 控制面板。让我们继续安装 Traefik。

本地安装

在安装 Traefik 之前,还有一个问题是我们希望将 Traefik 安装在哪个 Kubernetes 名称空间中。在生产中,如果 Traefik 负责集群范围的入口问题,那么 kube-system 名称空间是一个很好的选择。它与其他集群管理/操作服务一起存在。另一种方法是将 Traefik 限制在特定的名称空间,并为集群的其余部分使用不同的入口控制器(或不同的 Traefik 部署)。舵轮图支持开箱即用的rbac.namespaced配置。对于我们的例子,我们坚持使用默认的名称空间。

现在让我们用 Helm 命令安装 Traefik(参见清单 7-14 )。我们重用我们在清单 7-12 中详述的同一个 custom-values.yml 文件。然后,我们运行几个命令来观察它是否被正确部署。由于仪表板端口 9000 现在暴露在节点端口上,您也可以打开仪表板(参见图 7-7 )。

Traefik 微服务 API 网关教程(二)

图 7-7

安装舵的入口点

% helm install --values=custom-values.yml traefik traefik/traefik
NAME: traefik
LAST DEPLOYED: Wed Apr 22 00:26:27 2020
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None

% helm ls
NAME     NAMESPACE  REVISION  STATUS    CHART          APP VERSION
traefik  default      1       deployed  traefik-8.9.1  2.2.5

% kubectl get pods
NAME                     READY   STATUS    RESTARTS   AGE
traefik-5bcf58d556-vfhlv 1/1     Running       0      63s

% kubectl get svc traefik
NAME    TYPE    CLUSTER-IP    PORT(S)
traefik NodePort 10.99.103.150 9000:31342/TCP,80:30085/TCP,443:30615/TCP

% kubectl get svc traefik -o yaml
spec:
  clusterIP: 10.99.103.150
  externalTrafficPolicy: Cluster

  ports:
  - name: traefik
    nodePort: 31342
    port: 9000
    protocol: TCP
    targetPort: traefik
  - name: web
    nodePort: 30085
    port: 80
    protocol: TCP
    targetPort: web
  - name: websecure
    nodePort: 30615
    port: 443
    protocol: TCP
    targetPort: websecure
  selector:
    app.kubernetes.io/instance: traefik
    app.kubernetes.io/name: traefik
  sessionAffinity: None
  type: NodePort

% kubectl get IngressRoute traefik-dashboard -o yaml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute

spec:
  entryPoints:
  - traefik
  routes:
  - kind: Rule
    match: PathPrefix(`/dashboard`) || PathPrefix(`/api`)
    services:
    - kind: TraefikService
      name: api@internal

Listing 7-14Install Traefik Using Helm

Traefik 微服务 API 网关教程(二)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63

在图 7-7 中,你可以在仪表板上看到我们的三个入口点。您还可以深入到路由器,查看到 Traefik 内部仪表板和 ping 服务的路由映射。您可能会对路由器的名称感兴趣。对于ping@internal服务,一切如常。然而,指向api@internal的仪表板 IngressRoute 有一个生成的名称(见图 7-8 和 7-9 )。这是因为它有一个单独定义的 IngressRoute。所有定义的 IngressRoute 对象都使用类似的命名约定。

Traefik 微服务 API 网关教程(二)

图 7-9

仪表板路线

Traefik 微服务 API 网关教程(二)

图 7-8

安装头盔的路线

Helm chart 还安装了所有必需的 Traefik CRDs。Traefik 依靠标准的 Kubernetes 声明性配置机制,通过这些 CRD 来配置自己。每种动态路由器配置都有不同的 CRD。让我们看看清单 7-15 中安装了什么。

% kubectl get crd
NAME
ingressroutes.traefik.containo.us
ingressroutetcps.traefik.containo.us
ingressrouteudps.traefik.containo.us
middlewares.traefik.containo.us
tlsoptions.traefik.containo.us
tlsstores.traefik.containo.us
traefikservices.traefik.containo.us

Listing 7-15Traefik CRDs

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

公开 bookinfo 评论服务

在前面的小节中,我们观察了 Traefik 如何直接与 Kubernetes 服务对话,以在不同的 pods 或服务实例之间实现负载平衡。虽然很容易,但这不允许您利用我们在第三章中观察到的一些特殊流量路由功能,例如加权循环或镜像。这是通过使用另一个名为 TraefikService 的 CRD 在 Kubernetes 上实现的。既然 Traefik 已经启动并运行了 Helm,那么让我们使用 BookInfo over Traefik 来尝试一个稍微复杂一点的用例。继续使用上一节中详述的相同步骤将 BookInfo 再次部署到集群中(参见清单 7-6 )。一旦我们这样做了,我们应该在集群中再次拥有 BookInfo 资源。

我们现在在 Traefik ingress 上公开的服务是 reviews 服务。productpage后端内部调用它。这是一个单一的 Kubernetes 服务,由三个独立的部署提供支持。评论服务将流量路由到三个 pod,它们的行为略有不同。

  • reviews-v1返回样品评论。

  • reviews-v2调用评级服务并返回黑色样本评级。

  • reviews-v3调用评级服务并返回红色样本评级。

我们在使用 Traefikservice 的同时使用 IngressRoute 来公开此服务。这允许您尝试使用 Kubernetes 提供者的加权循环策略。服务启动后,我们可以继续应用 IngressRoute。首先,我们为三个单独的部署创建三个额外的 Kubernetes 服务(参见清单 7-16 )。Traefikservice 必须指向现有的 Kubernetes 服务。

apiVersion: v1
kind: Service
metadata:
  name: reviews-noratings
  labels:
    app: reviews
    version: v1
    service: reviews
spec:
  ports:
  - port: 9080
    name: http
  selector:
    app: reviews
    version: v1
---
apiVersion: v1
kind: Service
metadata:
  name: reviews-black
  labels:
    app: reviews
    version: v2
    service: reviews
spec:
  ports:
  - port: 9080
    name: http
  selector:
    app: reviews
    version: v2
---
apiVersion: v1
kind: Service
metadata:
  name: reviews-red
  labels:
    app: reviews
    version: v3
    service: reviews

spec:
  ports:
  - port: 9080
    name: http
  selector:
    app: reviews
    version: v3

% kubectl apply -f bookinfo-reviews-extsvcs.yml
service/reviews-noratings created
service/reviews-black created
service/reviews-red created

# We now have 4 reviews services, one from the original deployment
% kubectl get svc
NAME                TYPE        CLUSTER-IP      PORT(S)
reviews             ClusterIP   10.110.252.89   9080/TCP
reviews-black       ClusterIP   10.97.126.88    9080/TCP
reviews-noratings   ClusterIP   10.111.136.174  9080/TCP
reviews-red         ClusterIP   10.105.94.3     9080/TCP

Listing 7-16Three Separate Reviews Services

Traefik 微服务 API 网关教程(二)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64

一旦这些服务就位,让我们定义一个 Traefikservice 来对其中两个应用加权循环策略(参见清单 7-17 )。我们以 3:1 的权重将reviews-blackreviews-noratings服务组合在一起。

apiVersion: traefik.containo.us/v1alpha1
kind: TraefikService
metadata:
  name: reviews-v1v2
spec:
  weighted:
    services:
      - name: reviews-black
        port: 9080
        weight: 3
      - name: reviews-noratings
        port: 9080
        weight: 1

% kubectl apply -f bookinfo-reviews-traefikservice.yml
traefikservice.traefik.containo.us/reviews-v1v2 created

Listing 7-173 TraefikService Resources

Traefik 微服务 API 网关教程(二)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

我们现在应用一个 IngressRoute 来对外公开这些服务(参见清单 7-18 )。

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: bookinfo-reviews-ingress
spec:
  entryPoints:
    - web
  routes:
  - match: PathPrefix(`/reviews`)
    kind: Rule
    services:
# We can define multiple services here for simple Round robin load balancing
    - name: reviews-v1v2
      kind: TraefikService
    - name: reviews-red
      port: 9080

% kubectl apply -f bookinfo-review-ingress.yml
ingressroute.traefik.containo.us/bookinfo-reviw-ingress created

% kubectl get IngressRoute
NAME                      AGE
bookinfo-review-ingress   29s

# Call reviews ingress on loop
% for ((i=1;i<=20;i++)); do curl http://192.168.64.5:30680/reviews/1 | jq ; done

Listing 7-18Reviews IngressRoute

Traefik 微服务 API 网关教程(二)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

如果您在一个循环中调用服务入口(参见清单 7-18 ,您会看到负载根据提供的权重分布在三个独立的实例中。我们得到的红色和黑色评论比没有评论的评论多。您可以在图 7-10 、 7-11 、 7-12 和 7-13 的仪表盘中查看这些服务和路由器。

Traefik 微服务 API 网关教程(二)

图 7-13

用于入口服务的路由器

Traefik 微服务 API 网关教程(二)

图 7-12

加权 Traefikservice

Traefik 微服务 API 网关教程(二)

图 7-11

trafik 中的所有评论服务

Traefik 微服务 API 网关教程(二)

图 7-10

生成的入口服务

用 Jaeger 配置请求跟踪

第五章展示了如何用 Zipkin 将 Traefik 集成到分布式跟踪设置中。虽然 Zipkin 几年来一直是 Spring Cloud 生态系统分布式追踪的默认选择,但在 Kubernetes 世界中,人们更喜欢使用 Jaeger ( www.jaegertracing.io )。Jaeger 是由优步发布的 CNCF 分布式追踪系统,它为运行在 Kubernetes 上的服务分发追踪。Jaeger 适用于大规模部署,支持 OpenTracing 和其他标准。其背后的基本概念与 Zipkin 非常相似。它将跟踪头传播到下游服务,并根据发送到收集器的所有数据聚合跨度。Jaeger 是 Traefik 的默认跟踪后端。如果我们启用请求跟踪,并且不指定任何其他内容,Traefik 会自动采用 Jaeger 跟踪。

在 Traefik 中进行 Jaeger 配置之前,我们需要一个正在运行的 Jaeger 实例。耶格的完整设置是广泛的,超出了本书的范围。(数字海洋云上的最小设置需要至少四个 Kubernetes 工作节点。)出于演示目的,Jaeger 提供了一个 AllInOne 映像,它将所有组件打包在一个可执行文件中,并使用内存存储来部署在一个单独的 pod 中。这需要部署一个耶格操作员和相关的 CRD。类似于 Traefik 的 CRD,当我们向 Kubernetes 提交一个类型为Jaeger的资源时,它会启动 AllInOne Jaeger pod。如果你想更深入地了解 minikube 上的 Jaeger 设置,我们鼓励你采用这种方法。

在我们的例子中,我们采用了一种更简单的方法来设置 Jaeger,这避免了前面提到的所有复杂性。我们从 minikube 切换到另一个本地 Kubernetes 发行版 microk8s。我们使用现有的头盔图在上面安装 Traefik,然后在 microk8s 上启用 Jaeger(参见清单 7-19 )。这将自动部署 jaeger-operator 并启动一个简单的 jaeger 一体化部署,无需我们进行任何手动操作。然后,我们可以确定在启动配置中配置哪个服务端点。我们只对特定服务的几个端口感兴趣:一个 TCP 和一个 UDP(参见清单 7-19 )。

% microk8s enable jaeger

% microk8s kubectl get pod
NAME                               READY   STATUS
jaeger-operator-7b58b969cf-vh8pp   1/1     Running
simplest-658764ffff-xktbp          1/1     Running

% microk8s kubectl get svc simplest-agent
NAME            TYPE      PORT(S)
simplest-agent  ClusterIP 5775/UDP,5778/TCP,6831/UDP,6832/UDP

Listing 7-19Enable Jaeger on microk8s

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

必须在启动时指定 Jaeger 特定配置以及请求跟踪配置。因为我们已经在集群上运行了 Traefik,所以我们可以调整配置并运行一个helm upgrade命令。这将启动一个启用跟踪的新 Traefik pod,并删除现有的一个。我们在 custom-values.yml 文件中添加了以下内容(参见清单 7-20 )。

additionalArguments:
# New values in Helm configuration
  - "--tracing=true"
  - "--tracing.serviceName=traefik" # default value, can be omitted
  - "--tracing.jaeger=true" # default value, can be omitted
  - "--tracing.jaeger.samplingServerURL=http://simplest-agent:5778/sampling"
  - "--tracing.jaeger.localAgentHostPort=simplest-agent:6831"

% helm upgrade --values=custom-values.yml traefik traefik/traefik

Listing 7-20Additions in custom-values.yml and Helm Upgrade

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

您可以查看我们的仪表板,并在图 7-14 中看到 Jaeger tracing 已启用。

Traefik 微服务 API 网关教程(二)

图 7-14

耶格追踪已启用

以下是默认设置的 Jaeger 配置参数。

  • tracing . jaeger . sampling type = const

  • tracing . jaeger . sampling param = 1.0

默认情况下,这会将所有轨迹发送给 Jaeger。这可以通过调整来控制采样轨迹的数量。

  • tracing.jaeger.propagation = jaeger 耶格

这个可以改成发送 Zipkin 式的痕迹,耶格可以解读。

文档中还有一些其他配置参数。我们需要设置的两个必需参数已经在清单 7-20 中的 Helm 配置中。

由于跟踪是全局启用的,Traefik 现在开始向 Jaeger 收集器发送所有传入请求的跟踪。我们可以提出几个请求,然后检查 Jaeger UI(见图 7-15 )。

Traefik 微服务 API 网关教程(二)

图 7-15

界面上的耶格痕迹

我们可以通过传入的serviceName配置来过滤跟踪,以隔离 Traefik 特定的跟踪,并进一步通过 Traefik 入口点来过滤。我们可以深入到特定的跟踪。图 7-16 中的是对 Traefik 仪表板的请求。

Traefik 微服务 API 网关教程(二)

图 7-16

耶格追踪向下钻

这里还有一个有趣的地方。由于 Jaeger 实例运行在我们的集群中,我们如何访问 Jaeger UI 呢?它需要在节点端口上或通过 Traefik 入口(或另一个入口控制器)公开。由 microk8s 设置的 Jaeger 服务将其 UI 公开为集群中的默认入口规则。集群中有一个入口(不是 IngressRoute)资源,它是由 Jaeger 操作员自动创建的(参见清单 7-21 )。

% microk8s kubectl get ingress simplest-query -o yaml
kind: Ingress
spec:
  backend:
    serviceName: simplest-query
    servicePort: 16686

Listing 7-21Jaeger UI Ingress on microk8s

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

您在本章的其他地方没有遇到过这种格式,因为您没有处理过纯 Kubernetes 入口资源。这为默认入口控制器定义了一个默认后端,所以如果我们点击根路径(/)上 Traefik 的 web/websecure 入口点,它会打开 Jaeger UI。您可以在 Traefik 仪表板中查看这一点,它已经为一个default-backend配置了一个default-router(参见图 7-17 )。这种行为有两个原因。

Traefik 微服务 API 网关教程(二)

图 7-17

Jaeger 默认入口后端

  • Traefik Helm 图表设置了 Kubernetes CRD 供应商和普通 Kubernetes 供应商(如图 7-14 所示)。如果我们禁用了旧的提供程序,Traefik 不会注册它。

  • 我们在此群集中没有其他入口控制器。默认的是 nginx-ingress-controller,但是我们没有启用它。Traefik 正在处理这次入侵。

虽然这不是我们想要的行为(这只是由于不可预见的变量,看起来不可定制,甚至没有记录),但这只是为了我们的示例。它允许您说明 Traefik 对 Kubernetes ingress 的支持,我们跳过了这一步。在任何真实的用例中,都不是这样设置的。正确的做法是通过 IngressRoute 对象来公开 Jaeger UI。

数字海洋立方体云上的设置交通

现在让我们在 DigitalOcean Kubernetes (DOKS)上设置 Traefik。任何希望使用不同云提供商的人都可以这样做(AKS、EKA、GKE 等)。这是一个由 DigitalOcean 管理的云 Kubernetes 集群。集群的实际配置超出了本书的范围。

DigitalOcean 通过点击操作使其变得非常简单。一旦启动,您将获得下载 kubeconfig 的说明,这样您就可以使用本地 Kubernetes CLI (kubectl)连接到您的集群。对于云,在 DOKS 上将 Traefik 服务公开为默认类型的负载平衡器会自动为我们提供一个云负载平衡器。我们现在只在清单 7-22 中定制 Helm 安装期间的日志级别。

从这里开始,kubeconfig 必须改为指向我们的云集群来执行所有命令。

# kubeconfig has to be changed to point to cloud cluster for following commands
% helm install --set="additionalArguments={--log.level=INFO}" traefik traefik/traefik

% kubectl get svc traefik
NAME     TYPE         EXTERNAL-IP     PORT(S)
traefik  LoadBalancer  139.59.53.243    80:30415/TCP,443:32494/TCP

Listing 7-22Install Traefik Using Helm on Cloud LB

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

DigitalOcean 提供云负载平衡器。这个过程需要一点时间,之后我们获得公共外部 IP 来访问我们的入口点(参见清单 7-22 )。与 NodePort 不同,这里我们可以在默认端口上路由请求。回想一下,Traefik 会自动为 HTTPS 入口点生成一个自签名证书,因此您会看到如图 7-18 所示的端口 443。

Traefik 微服务 API 网关教程(二)

图 7-18

云负载平衡器上具有自签名证书的 HTTPS 入口点

当我们继续时,我们得到 Traefik 的默认后端(见图 7-19 )。

Traefik 微服务 API 网关教程(二)

图 7-19

云负载平衡器上的默认后端

我们没有公开这个部署的traefik端点,所以我们不能公开访问仪表板。Traefik 文档中建议这样做。现在有两种查看仪表板的方式。你可以做任何一个。

  • 直接对仪表板端口执行kubectl port-forward命令。这将控制面板的访问权限限制为只有那些拥有 kubeconfig 的用户(如果集群内的服务直接连接到 pod,则可能还有集群内的服务)。

  • 按照 Traefik 的建议,使用安全的 IngressRoute 暴露仪表板(类似于我们在第四章中所做的)。

Kubernetes 上的 TLS 终止通过让我们加密证书

现在您已经看到了在 Kubernetes 上运行 Traefik 所需的部分。唯一没有讨论的是 TLS 支持,这对于任何严肃的生产使用都是必要的。第四章介绍了一个公开的 Traefik 实例如何轻松地为 TLS 流量提供服务,以及如何对自动证书分发进行加密。

在第四章中,我们展示了在单个云虚拟机(或 droplet)上运行的 Traefik 上的安全路由,通过 TLS 连接(即websecure入口点)启用了基本身份验证。在本章中,我们尝试在 cloud Kubernetes 上使用 Traefik 做同样的事情。我们部署 BookInfo 服务,在websecure入口点上为它定义一个 IngressRoute,并从 Let’s Encrypt 为该域请求一个有效的 TLS 证书。请记住,Let’s Encrypt 只为可公开访问的域颁发有效证书。已颁发证书的域必须与您为有效 TLS 连接而访问的域的 URL 相匹配。为了用 Let’s Encrypt 支持重新配置 Traefik,我们提供了一个新的 values 配置文件并升级了我们的 Helm 版本。我们还将日志级别更改为 DEBUG(参见清单 7-23 )。

additionalArguments:
  - "--certificatesresolvers.letsencrypt.acme.email=<valid email>"
  - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
  - "--certificatesresolvers.letsencrypt.acme.storage=/data/acme.json"
  - "--certificatesresolvers.letsencrypt.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
  - "--log.level=DEBUG"

persistence:
  enabled: true
  size: 1Gi   #min. volume size allowed on DigitalOcean
  storageClass: "do-block-storage"

Listing 7-23New cloud-values.yml file

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

我们在这里使用类似的让我们加密配置(见清单 7-23 ),我们上次在第四章中使用过,除了现在我们使用 CLI 参数而不是静态 YAML 配置。为了混淆,我们使用 HTTP-01 挑战,而不是 TLS-ALPN-01 挑战。这是一种更标准、更广泛使用的挑战类型。它要求 web 入口点(端口 80)是公共可达的(让我们加密)。

我们使用 Let’s Encrypt 暂存 URL,因为我们不需要获得有效的生产证书。获取的证书的存储位置需要一些额外的配置。Traefik 的舵图提供了这一点。pod 通常是暂时的,如果没有 Kubernetes 持久卷的支持,就不能将数据持久化到 pod 文件系统中。

Kubernetes 存储抽象的详细讨论超出了我们的范围。Traefik Helm 图表为向文件系统写入数据提供了一个存储位置,该位置在 pod 重新启动后仍然存在。存储安装在位于/data位置的运行 Traefik pod 中,我们获得的证书保存在该文件夹中。否则,证书会在 pod 重新启动时丢失。作为参考,Helm 图表生成的存储配置如清单 7-24 所示。这可以像往常一样通过 Helm template 命令生成。它可以在舵图中进一步定制。存储类别do-block-storage属性是特定于供应商的。它需要在 DigitalOcean 中配置存储,在其他任何地方都没有用。

kind: PersistentVolumeClaim
metadata:
  name: traefik
spec:
  accessModes:
    - "ReadWriteOnce"
  resources:
    requests:
      storage: "1Gi"
  storageClassName: "do-block-storage"
# Additional Deployment configuration
spec:
  template:
    spec:
        volumeMounts:
          - name: data
            mountPath: /data
      volumes:
        - name: data
          persistentVolumeClaim:
            claimName: traefik

Listing 7-24Generated Storage Value Snippets

Traefik 微服务 API 网关教程(二)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

我们现在可以使用清单 7-25 中的文件来升级头盔以应用这个配置。

% helm upgrade --values=cloud-values.yml  traefik traefik/traefik
Release "traefik" has been upgraded. Happy Helming!
NAME: traefik
LAST DEPLOYED: Sun Aug 16 20:34:16 2020
NAMESPACE: default
STATUS: deployed
REVISION: 2
TEST SUITE: None

Listing 7-25Helm Upgrade with certresolver

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

此时,我们可以使用与清单 7-6 中完全相同的配置来部署 BookInfo 服务。然后,我们定义一个新的 IngressRoute 来到达该服务。首先,我们打开另一个终端,并在清单 7-26 中跟踪 Traefik pod 日志。回想一下,我们将 Traefik 日志级别更改为 DEBUG。我们可以检查证书获取过程。

# In a separate terminal
% kubectl get pod
NAME                      READY  STATUS
traefik-6cb8d56bf8-sghpj  1/1    Running

% kubectl logs -f traefik-6cb8d56bf8-sghpj
time="2020-08-16T15:07:37Z" level=info msg="Configuration loaded from flags."
time="2020-08-16T15:07:37Z" level=info msg="Traefik version 2.2.8 built on 2020-07-28T15:46:03Z"
time="2020-08-16T15:07:37Z" level=debug msg="Static configuration loaded...
...

Listing 7-26Secure Dashboard IngressRoute

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

让我们让它继续运行,然后回到我们的主终端来应用 IngressRoute(参见清单 7-27 )。

# whoami-doks-ingress.yml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: productpage-ingresstls
spec:
  entryPoints:
    - websecure
  routes:
  - match: Host(`k8straefik.rahulsharma.page`) && (PathPrefix(`/productpage`) || PathPrefix(`/static`) || Path(`/login`) || Path(`/logout`) || PathPrefix(`/api/v1/products`))
    kind: Rule
    services:
    - name: productpage
      port: 9080
  tls:
    certResolver: letsencrypt

#Apply the IngressRoute
% kubectl apply -f bookinfo-doks-ingress.yml

Listing 7-27TLS IngressRoute for bookinfo productpage

Traefik 微服务 API 网关教程(二)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

在清单 7-16 的 log tail 终端中,您会看到日志中关于应用 YAML 和打开浏览器的消息(参见清单 7-28 )。为了简洁起见,我们省略了许多信息。我们已经在公共域提供者中添加了一个子域条目,指向我们的负载平衡器的 IP 地址。您会看到 Traefik 首先尝试使用 TLS-ALPN-01 质询类型,然后退回到 HTTP-01 质询。这个挑战是一个多步骤的过程,它提供了对我们的公共可达域上的默认 HTTP 端口进行加密的自动响应,这就是为什么端口 80 需要为这个挑战开放的原因。

level=debug msg="Try to challenge certificate for domain [k8straefik.rahulsharma.page] found in HostSNI rule"
level=debug msg="Domains ["k8straefik.rahulsharma.page"] need ACME certificates generation for domains "k8straefik.rahulsharma.page"." providerName=letsencrypt.acme
level=debug msg="legolog: [INFO] [k8straefik.rahulsharma.page] acme: Could not find solver for: tls-alpn-01"
level=debug msg="legolog: [INFO] [k8straefik.rahulsharma.page] acme: use http-01 solver"
level=debug msg="legolog: [INFO] [k8straefik.rahulsharma.page] The server validated our request"
level=debug msg="legolog: [INFO] [k8straefik.rahulsharma.page] acme: Validations succeeded; requesting certificates"
level=debug msg="Certificates obtained for domains [k8straefik.rahulsharma.page]"

Listing 7-28Lets Encrypt HTTP-01 Certificate Negotiation Log Snippets

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

当您在浏览器中访问 BookInfo productpage URL 时,您会得到通常的响应,并且可以检查暂存证书(参见图 7-20 )。

Traefik 微服务 API 网关教程(二)

图 7-20

具有 LE 证书的云负载平衡器上的 BookInfo 产品页面 UI

多个 trafik 实例的 tls 证书限制

你可能会觉得我们现在已经准备好推出 Traefik 来在 Kubernetes 上运行了;然而,有一个问题。我们还没有谈到的一点是高可用性(HA)。Kubernetes 的一个优点是,它通过在同一服务的多个单元之间负载平衡流量来自动提供 HA 支持。如果启用了自动伸缩,Kubernetes 将进一步横向扩展 pod 以处理请求的增加。

这也适用于 Traefik,因为它是作为部署支持的 Kubernetes 服务运行的。这个 HA 为 Traefik ACME 协议与 Let’s Encrypt 的集成带来了问题。如您之前所见,自动化的“让我们加密 TLS”挑战需要多步互动。没有办法保证 Traefik 的同一个实例接收所有的质询请求。还记得 Traefik 将动态获取的证书存储在共享持久性卷中的 acme.json 文件中。

Traefik 文档警告您,该文件不应用于多个实例的并发访问。因此,当您水平扩展 Traefik 时,让我们加密集成会崩溃。Traefik 不允许这样的部署配置继续进行;它在舵安装期间抛出一个错误。

traefike 的商业版本 traefike 支持这种分布式加密配置。然而,如果我们想坚持使用免费社区版,这种方法是行不通的。我们可以将手动获取的证书配置为 Kubernetes 机密,然后在 IngressRoute 配置中引用它,如清单 7-29 所示。

# whoami-doks-ingress.yml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: productpage-ingresstls
spec:
  entryPoints:
    - websecure
  routes:
  - match: Host(`k8straefik.rahulsharma.page`) && PathPrefix(`/productpage`) || #etc..
    kind: Rule
    services:
    - name: productpage
      port: 9080
  tls:
    secretName: k8straefik-tls # TLS certificate already added as Kubernetes Secret

Listing 7-29TLS IngressRoute for Whoami

Traefik 微服务 API 网关教程(二)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

如果我们仍然希望使用 Let’s Encrypt 来自动获取和更新证书,Traefik 建议使用 jet stack cert-manager(https://cert-manager.io)。Cert-manager 是 Kubernetes 上管理证书的实际解决方案。它使用与 Traefik 相同的 ACME 协议为不同的用例提供证书,尽管它不支持像 Traefik 那样的 TLS-ALPN-01 挑战。Cert-manager 拥有与 Kubernetes Ingress 的本机集成。如果我们创建一个普通的 Kubernetes 入口资源并添加正确的自定义注释,cert-manager 会自动为该域提供一个 TLS 证书。

问题是,在撰写本文时,它还不能与 Traefik 的 Ingres route CRD 一起使用。Traefik 团队正在进行这种整合。作为一种变通方法,现在,我们可以为 cert-manager 创建一个证书定制资源,它获取一个证书并将其保存为 Kubernetes 机密,然后管理其上的证书。这可以在 IngressRoute 资源中使用,如清单 7-29 所示。因为这是一个可能很快解决的限制的变通方法,所以我们不详细说明它。

摘要

本章使用其 Helm 图表在 Kubernetes 上部署和配置了 Traefik。Traefik 与 Kubernetes 紧密集成,其 API 网关功能可以轻松映射到 Kubernetes 入口。这使得它成为用作入口控制器的非常有吸引力的提议。

您以 CRDs 的形式尝试了 Traefik 与 Kubernetes 的本机集成。您看到了 Traefik 如何检测 Kubernetes API 服务器中的动态更新,并在没有任何人工干预的情况下保持其配置更新。服务在 Kubernetes 集群中更新时,会在 Traefik 中注册和注销。

虽然这一章在压缩的时间内涵盖了许多复杂的领域,但这种复杂性是 Kubernetes 生态系统所固有的。在我们看来,Traefik 简化了在 Kubernetes 上部署和管理 API 网关的工作。

就这样,我们来到了本章和本书的结尾。Traefik 每天都在快速发展,我们鼓励您阅读 Traefik 官方文档,继续您的 Traefik 探索之旅。

© 版权声明

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...