Service 定义

https://doc.traefik.io/traefik/routing/services/

The Services are responsible for configuring how to reach the actual services that will eventually handle the incoming requests.

Service 特点

  1. Service是Traefik流程中最后处理请求的位置(中间件在此之前处理请求)
  2. Service可以控制请求直接到达源站(中间件做不到)
  3. Service可以对请求进行修改(中间件也可以)

Traefik 官方自带的 Service

官方自带了三个 Service:

  1. 流量镜像
  2. 负载均衡(同时实现了权重)

流量镜像的代码位于:/pkg/server/service/loadbalancer/mirror/mirror.go

负载均衡代码位于:/pkg/server/service/loadbalancer/wrr/wrr.go

上述代码可以作为我们开发 Service 的参考。

Service 开发要点

定义 Service 配置

Traefik 的配置解析,是直接映射(或者说反序列化)struct实现的,所有 Service 的配置都 属于 `dynamic.Service` 这个 struct 。这个 struct 位于:/pkg/config/dynamic/http_config.go

其定义如下:

type Service struct {
LoadBalancer *ServersLoadBalancer `json:"loadBalancer,omitempty" toml:"loadBalancer,omitempty" yaml:"loadBalancer,omitempty" export:"true"`
Weighted *WeightedRoundRobin `json:"weighted,omitempty" toml:"weighted,omitempty" yaml:"weighted,omitempty" label:"-" export:"true"`
Mirroring *Mirroring `json:"mirroring,omitempty" toml:"mirroring,omitempty" yaml:"mirroring,omitempty" label:"-" export:"true"`
}

按照 Traefik 已有的 Service 配置来看,我们自定义的 Service 所使用的配置也应该在 http_config.go 文件中

需要注意的是:

  1. 自己新定义的配置,需要在 `dynamic.Service` 中新增一条属性。否则 配置不会被加载。
  2. 定义的配置需要其他模块读取,应注意首字母大写,以保证可访问性
  3. 需要正确填写tag,包括 json、yaml和toml三种序列化格式的名称,否则可能无法正确加载
  4. 可以省略的参数,其定义应设置为指针类型,否则即是配置的必选项

举例,定义 白名单Service:

在 http_config.go 中新增:

type WhiteList struct {
IPList []string `json:"ipList,omitempty" toml:"ipList,omitempty" yaml:"ipList,omitempty"`
Service string `json:"service,omitempty" toml:"service,omitempty" yaml:"service,omitempty" export:"true"`
MaxBodySize *int64 `json:"maxBodySize,omitempty" toml:"maxBodySize,omitempty" yaml:"maxBodySize,omitempty" export:"true"`
}

在 http_config.go 的 `dynamic.Service` 这个 struct 中添加 WhiteList:

type Service struct {
LoadBalancer *ServersLoadBalancer `json:"loadBalancer,omitempty" toml:"loadBalancer,omitempty" yaml:"loadBalancer,omitempty" export:"true"`
Weighted *WeightedRoundRobin `json:"weighted,omitempty" toml:"weighted,omitempty" yaml:"weighted,omitempty" label:"-" export:"true"`
Mirroring *Mirroring `json:"mirroring,omitempty" toml:"mirroring,omitempty" yaml:"mirroring,omitempty" label:"-" export:"true"`
WhiteList *WhiteList `json:"whiteList,omitempty" toml:"whiteList,omitempty" yaml:"whiteList,omitempty" label:"-" export:"true"`
}

这个新增的 WhiteList 对应的配置(其中的maxBodySize可以不填):

http:
services:
my-whitelist:
whiteList:
iplist:
- "127.0.0.1"
- "192.168.0.0/24"
maxBodySize: 2000
service: example # Define how to reach an existing service on our infrastructure
example:
loadBalancer:
servers:
- url: "http://xxx.xxx.xxx.xxx:8888/"

定义 Service 的 Handler

接下来,需要定义 Service 的功能代码。按照 Traefik 已有的 Service 来看,其 Service 应定义在 /pkg/server/service/ 中。每个 Service 单独作为一个包存在。

欲新增 Service 则需要在 /pkg/server/service/ 下新建一个文件夹,并在其中新建文件。还是以 白名单 为例,结构如下(省略的其他无关部分):

├── pkg
│ └── server
│ └── service
│ └── whitelist
│ └── whitelist.go

创建好文件后,在其中添加代码,至少需要:

  1. 规范包名
  2. 包内有一个 New 函数,作为 Handler 的初始化函数。(当然可以使用其他名字,但是我们应该按照 Traefik 的规范来)
  3. New 函数返回一个实现了 http.Handler 接口的对象。

大致如下(省略了所有功能,只保留代码结构):

package whitelist

import (
"net"
"net/http" "github.com/traefik/traefik/v2/pkg/config/dynamic"
) // WhiteList is an http.Handler 用于实现白名单功能.
type WhiteList struct {
......
} // New returns a new instance of *WhiteList.
func New(config *dynamic.WhiteList) *WhiteList {
return &WhiteList{}
} func (w *WhiteList) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
w.handler.ServeHTTP(rw, req)
}

注:实现 http.Handler 接口,只需实现 func ServeHTTP(http.ResponseWriter, *http.Request) 即可

编写 Service 初始化代码

有了配置和代码实现,接下来就是在 Service 的初始化代码中,添加我们新增的 Service了。

核心代码位于:/pkg/server/service/service.go

需要关注 func (m *Manager) BuildHTTP() 这个方法,它由 Router 的初始化代码进行调用,用于初始化 Router 定义的 Service 。

我们需要在 func (m *Manager) BuildHTTP() 这个方法中实现对我们自定义 Service 的初始化。

这个方法首先提取了 Service 的配置,然后通过其中的 switch 语句,对配置的存在性进行判断。通过后,开始构建 Service 实例。核心的代码如下:

    switch {
case conf.LoadBalancer != nil:
var err error
lb, err = m.getLoadBalancerServiceHandler(ctx, serviceName, conf.LoadBalancer)
if err != nil {
conf.AddError(err, true)
return nil, err
}
case conf.Weighted != nil:
var err error
lb, err = m.getWRRServiceHandler(ctx, serviceName, conf.Weighted)
if err != nil {
conf.AddError(err, true)
return nil, err
}
case conf.Mirroring != nil:
var err error
lb, err = m.getMirrorServiceHandler(ctx, conf.Mirroring)
if err != nil {
conf.AddError(err, true)
return nil, err
}
default:
sErr := fmt.Errorf("the service %q does not have any type defined", serviceName)
conf.AddError(sErr, true)
return nil, sErr
}

可以看见,三种默认 Service,均定义了 getxxxxxServiceHandler 函数,用于初始化 Service 实例。我们也应该定义类似的方法,以保证上述代码简洁可读。

我们定义的函数如下:

func (m *Manager) getIPWhiteListServiceHandler(ctx context.Context, config *dynamic.WhiteList) (http.Handler, error) {
serviceHandler, err := m.BuildHTTP(config.Service)
if err != nil {
return nil, err
}
handler := whitelist.New(serviceHandler, config)
return handler, nil
}

其中 `m.BuildHTTP(config.Service)` 这里是调用 BuildHTTP 方法,通过配置中传入的其他 Service 名称,创建其 Handler,以供我们的Service 调用。

定义好 `getIPWhiteListServiceHandler` 后,需要在 BuildHTTP 方法中增加配置的判断和调用就行:

// BuildHTTP Creates a http.Handler for a service configuration.
func (m *Manager) BuildHTTP(rootCtx context.Context, serviceName string) (http.Handler, error) {
......(省略了其他代码) var lb http.Handler switch {
......(省略了其他配置)
case conf.WhiteList != nil:
var err error
lb, err = m.getIPWhiteListServiceHandler(ctx, conf.WhiteList)
if err != nil {
conf.AddError(err, true)
return nil, err
}
default:
sErr := fmt.Errorf("the service %q does not have any type defined", serviceName)
conf.AddError(sErr, true)
return nil, sErr
} return lb, nil
}

到此我们的自定义 Service 已经开发完成。可以根据需求,对代码进行测试和修改

【Traefik二次开发】服务 Service 开发的更多相关文章

  1. 仅用移动开发服务:开发native应用

    不花一分钱,就可以做native应用开发,这在以前是根本不敢想象的事儿.然而在今天,移动开发工具和服务已经五花八门,聪明的开发者只要随心所欲的抓取几个顺手的,就能完成native开发.今天给大家介绍的 ...

  2. Delphi 三层框架开发 服务端开发

    采用Delphi7+SQL2008 一.创建数据库和表 CREATE TABLE [dbo].[tb_Department]( [FKey] [uniqueidentifier] NOT NULL, ...

  3. Web Service学习-CXF开发Web Service实例demo(一)

    Web Service是什么? Web Service不是框架.更甚至不是一种技术. 而是一种跨平台,跨语言的规范 Web Service解决什么问题: 为了解决不同平台,不同语言所编写的应用之间怎样 ...

  4. Android系统编程入门系列之加载服务Service

    之前几篇文章简单梳理了在Android系统的四大组件之一,最主要的界面Activity中,使应用程序与用户进行交互响应的相关知识点,那对于应用程序中不需要与用户交互的逻辑,又要用到哪些内容呢?本文开始 ...

  5. 【工业串口和网络软件通讯平台(SuperIO)教程】七.二次开发服务驱动

    SuperIO相关资料下载:http://pan.baidu.com/s/1pJ7lZWf 1.1    服务接口的作用 围绕着设备驱动模块采集的数据,根据需求提供多种应用服务,例如:数据上传服务.数 ...

  6. 免费提供UG、ProE二次开发、定制化开发服务

    免费提供UG.ProE二次开发,定制开发服务. 拥有六年UG.ProE二次开发经验,相关项目经验. 从事过智能设计.计算机图形学相关研究. 联系方式: QQ:1787326383 微信号:begtos ...

  7. ubuntu下安装 gSOAP 用于C/C++开发web service服务端与客户端

    昨天在ubuntu下进行安装gSOAP,费了很多时间,没成功,今天又来找了大量教程资料,终于一次成功,这里写下自己的安装步骤和方法,供大家参考. 首先下载gsoap,我下载的是gsoap-2.8.1. ...

  8. 北京智和信通IT运维管理系统二次开发服务提供商

    随着云计算.大数据.物联网.移动互联网.人工智能.5G等高新技术的快速发展,数据中心及网络基础设施呈现出井喷式的增长模式,对设备商来说,多.快.好.省的实现定制化网络管理开发,可极大的扩充设备适用范围 ...

  9. 使用CXF开发Web Service服务

    1.使用CXF开发Web Service服务端 1.1 开发一个Web Service业务接口,该接口要用@WebService修饰 (1)创建一个Java项目MyServer (2)在MyServe ...

随机推荐

  1. SpringBoot的浅浅配置和小整合

    SpringBoot的浅浅配置和小整合 本文如题,就是浅浅记录一下学习的过程中一些过程,比较简单,并没有多少深度.谢谢! SpringBoot创建 从IDEA中新建项目或者模块.注意jdk版本,一般不 ...

  2. SpringBoot 集成缓存性能之王 Caffeine

    使用缓存的目的就是提高性能,今天码哥带大家实践运用 spring-boot-starter-cache 抽象的缓存组件去集成本地缓存性能之王 Caffeine. 大家需要注意的是:in-memeory ...

  3. ShardingSphere-proxy-5.0.0容量范围分片的实现(五)

    一.修改配置文件config-sharding.yaml,并重启服务 # # Licensed to the Apache Software Foundation (ASF) under one or ...

  4. bat-使用bat安装jdk和配置环境变量

    文件路径 @echo off Setlocal enabledelayedexpansion @REM vscode中自动开启延迟环境变量扩展, %~d0 cd %~dp0 @REM dir echo ...

  5. VScode运行总是显示running状态

    一.每次点击运行都显示code is already running,而且键盘也没有办法输入 二.解决办法 注意:记得重新启动VScode

  6. C语言输出九九乘法表

    C语言学了有一阵子了,趁着假期没事练练手,没想到挺简单 基本思路是这样的 先写一个主函数,然后定义两个变量i1和i2;使用for语句循环嵌套,外层循环负责写循环9次,内循环里面写从1开始递增去和外层循 ...

  7. do-while循环和三种循环的区别

    循环语句3--do...while do...while循环格式 初始化表达式① do{ 循环体③ 步进表达式④ }while(布尔表达式②); 执行流程 执行顺序:①③④>②③④>②③④ ...

  8. .NET GC工作流程

    前言 在上文[如何获取GC的STW时间]一文中,我们聊到了如何通过监听GC发出的诊断事件来计算STW时间.里面只简单的介绍了几种GC事件和它的流程. 群里就有小伙伴在问,那么GC事件是什么时候产生的? ...

  9. 攻防世界MISC进阶区---41-45

    41.Get-the-key.txt 得到无类型文件,扔进kali中,strings一下,得到了一堆像flag的内容 扔进010 Editor中,搜索关键字,发现一堆文件,改后缀为zip 打开,直接得 ...

  10. loguru备忘

    loguru是个非常好用的三方日志管理包,简单易用,奈何老是记不住,在这记录一下吧 #coding:utf-8 ''' @version: python3.8 @author: 'eric' @lic ...