【Traefik二次开发】服务 Service 开发
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 特点
- Service是Traefik流程中最后处理请求的位置(中间件在此之前处理请求)
- Service可以控制请求直接到达源站(中间件做不到)
- Service可以对请求进行修改(中间件也可以)
Traefik 官方自带的 Service
官方自带了三个 Service:
- 流量镜像
- 负载均衡(同时实现了权重)
流量镜像的代码位于:/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 文件中
需要注意的是:
- 自己新定义的配置,需要在 `dynamic.Service` 中新增一条属性。否则 配置不会被加载。
- 定义的配置需要其他模块读取,应注意首字母大写,以保证可访问性
- 需要正确填写tag,包括 json、yaml和toml三种序列化格式的名称,否则可能无法正确加载
- 可以省略的参数,其定义应设置为指针类型,否则即是配置的必选项
举例,定义 白名单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
创建好文件后,在其中添加代码,至少需要:
- 规范包名
- 包内有一个 New 函数,作为 Handler 的初始化函数。(当然可以使用其他名字,但是我们应该按照 Traefik 的规范来)
- 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 开发的更多相关文章
- 仅用移动开发服务:开发native应用
不花一分钱,就可以做native应用开发,这在以前是根本不敢想象的事儿.然而在今天,移动开发工具和服务已经五花八门,聪明的开发者只要随心所欲的抓取几个顺手的,就能完成native开发.今天给大家介绍的 ...
- Delphi 三层框架开发 服务端开发
采用Delphi7+SQL2008 一.创建数据库和表 CREATE TABLE [dbo].[tb_Department]( [FKey] [uniqueidentifier] NOT NULL, ...
- Web Service学习-CXF开发Web Service实例demo(一)
Web Service是什么? Web Service不是框架.更甚至不是一种技术. 而是一种跨平台,跨语言的规范 Web Service解决什么问题: 为了解决不同平台,不同语言所编写的应用之间怎样 ...
- Android系统编程入门系列之加载服务Service
之前几篇文章简单梳理了在Android系统的四大组件之一,最主要的界面Activity中,使应用程序与用户进行交互响应的相关知识点,那对于应用程序中不需要与用户交互的逻辑,又要用到哪些内容呢?本文开始 ...
- 【工业串口和网络软件通讯平台(SuperIO)教程】七.二次开发服务驱动
SuperIO相关资料下载:http://pan.baidu.com/s/1pJ7lZWf 1.1 服务接口的作用 围绕着设备驱动模块采集的数据,根据需求提供多种应用服务,例如:数据上传服务.数 ...
- 免费提供UG、ProE二次开发、定制化开发服务
免费提供UG.ProE二次开发,定制开发服务. 拥有六年UG.ProE二次开发经验,相关项目经验. 从事过智能设计.计算机图形学相关研究. 联系方式: QQ:1787326383 微信号:begtos ...
- ubuntu下安装 gSOAP 用于C/C++开发web service服务端与客户端
昨天在ubuntu下进行安装gSOAP,费了很多时间,没成功,今天又来找了大量教程资料,终于一次成功,这里写下自己的安装步骤和方法,供大家参考. 首先下载gsoap,我下载的是gsoap-2.8.1. ...
- 北京智和信通IT运维管理系统二次开发服务提供商
随着云计算.大数据.物联网.移动互联网.人工智能.5G等高新技术的快速发展,数据中心及网络基础设施呈现出井喷式的增长模式,对设备商来说,多.快.好.省的实现定制化网络管理开发,可极大的扩充设备适用范围 ...
- 使用CXF开发Web Service服务
1.使用CXF开发Web Service服务端 1.1 开发一个Web Service业务接口,该接口要用@WebService修饰 (1)创建一个Java项目MyServer (2)在MyServe ...
随机推荐
- 想知道Vue3与Vue2的区别?五千字教程助你快速上手Vue3!
从Vue3发布以来,我就一直对其非常感兴趣,就一直想着将其投入公司的生产中,但是开始考虑到很多不确定性就暂时对一些很小的功能进行一些尝试:慢慢的发现组合式Api的形式非常适合开发(个人感觉),尤其是V ...
- SAP 定义用户组
SUGR,可进行创建.查看.删除等维护性操作,并可指定本组的用户
- MySql字段增删改语句
新增表字段:alter table 表名 需要添加的字段信息; ALTER TABLE nation add seq VARCHAR(20) COMMENT '顺序' 字段名的修改:alter tab ...
- idea显示 RunDashboard ,多个启动项时列表显示
在.idea(项目所在文件夹中)下的workspace.xml文件中找到 <component name="RunDashboard"> 标签,然后添加如下节点 < ...
- NC20032 [HNOI2003]激光炸弹
NC20032 [HNOI2003]激光炸弹 题目 题目描述 一种新型的激光炸弹,可以摧毁一个边长为R的正方形内的所有的目标. 现在地图上有 \(n\) (\(N ≤ 10000\))个目标,用整数 ...
- 你真的了解JAVA中对象和类、this、super和static关键字吗
作者:小牛呼噜噜 | https://xiaoniuhululu.com 计算机内功.JAVA底层.面试相关资料等更多精彩文章在公众号「小牛呼噜噜 」 目录 Java对象究竟是什么? 创建对象的过程 ...
- 阿里 Maven仓库
<?xml version="1.0" encoding="UTF-8"?> <settings xmlns="http://mav ...
- APISpace 号码实时查询API接口 免费好用
最近公司项目有一个号码实时查询的小功能,想着如果用现成的API就可以大大提高开发效率,所以在网上的API商店搜索了一番,发现了 APISpace,它里面的号码实时查询API非常符合我的开发需求. ...
- 【学习笔记】带你从0开始学习 01Trie
01Trie Section 1:普通 Trie Section 1.1 什么是 Trie Trie 树,即字典树,是一种树形结构.典型应用是用于统计和排序大量的字符串前缀来减少查询时间,最大限度地减 ...
- 图文并茂演示小程序movable-view的可移动范围
前言 开发过小程序的同学可能对这两个内置组件并不陌生,他们配合用来实现在页面中可以拖拽滑动,其中: movable-area表示元素可移动的区域,它决定元素移动的区域范围 movable-view表示 ...