Skip to main content

Command Palette

Search for a command to run...

API网关之krakend

Updated
2 min read

这一篇已经拖了好久了,以至于提笔开始写的时候,krakend项目已经改名为lura了,而且这个网关项目还进入到了CNCF中,真的是士别三日,当刮目相看了。不知不觉,我使用的这个开源项目作为团队的业务网关都已经上线了。

image.png

当初我为什么要选择这个网关呢?首先团队跟外部沟通的协议为HTTP,有一些鉴权需求,本身业务量并不大,需要支持自定义插件的,最好是用golang写的,便于维护。从功能上来讲,其实nginx非常符合我的需求,除了技术栈,我只用了几天时间调研试用,就迅速确定了krakend作为API网关的框架,使用简单,性能还很强的样子。当然,从业务量上来讲,性能不是第一优先级,我需要解决的是从无到有的问题。

我所在的团队属于初创,后端这部分有好几个人在写,功能上重复,每个人都跟自己的业务前端对接,部门所做的几个功能都挺分散的,再加上权限控制的需求愈发强烈,网关的必要性就凸显出来了。短短不到百行代码,就能创建一个API网关,这是我选择的主要原因。

package main

    import (
        "flag"
        "log"
        "os"

        "github.com/luraproject/lura/config"
        "github.com/luraproject/lura/logging"
        "github.com/luraproject/lura/proxy"
        "github.com/luraproject/lura/router/gin"
    )

    func main() {
        port := flag.Int("p", 0, "Port of the service")
        logLevel := flag.String("l", "ERROR", "Logging level")
        debug := flag.Bool("d", false, "Enable the debug")
        configFile := flag.String("c", "/etc/lura/lura.json", "Path to the configuration filename")
        flag.Parse()

        parser := config.NewParser()
        serviceConfig, err := parser.Parse(*configFile)
        if err != nil {
            log.Fatal("ERROR:", err.Error())
        }
        serviceConfig.Debug = serviceConfig.Debug || *debug
        if *port != 0 {
            serviceConfig.Port = *port
        }

        logger, _ := logging.NewLogger(*logLevel, os.Stdout, "[LURA]")

        routerFactory := gin.DefaultFactory(proxy.DefaultFactory(logger), logger)

        routerFactory.New().Run(serviceConfig)
    }

不过,看似简洁的背后,其实是一把双刃剑,很快我就遇到了几个问题。

krakend不支持websocket代理

这个其实也不能叫做问题,因为我使用的是开源社区版本,企业版是支持的,我在issues中看到了关于这个问题的回答,老实说,有点心酸:

We are developing and maintaining the project and giving support for free. You can extend and customize it all you want, for free. Do you want us to move to other (payed) projects and let KrakenD die? I'm sure you'll understand that engineers (good or bad) are people and we need to eat and pay bills too

krakend配置文件不支持正则表达式

如果你想使用正则代理接口如^/ping/.*/pong$,抱歉,不支持,你只能按以下格式写

{
  "endpoint": "/myserviceA/{level1}/{level2}/{level3}",
  "backend": [
    {
      "host": [ "http://serverA/" ],
      "url_pattern": "/{level1}/{level2}/{level3}"
    }
  ]
},
{
  "endpoint": "/myserviceB/{level1}/{level2}/{level3}",
  "backend": [
    {
      "host": [ "http://localhost:8060" ],
      "url_pattern": "/{level1}/{level2}/{level3}"
    }
  ]
}

这样写你才能匹配地到/myserviceA/a/b/c,虽然有点难看,但勉强也能接受,只要多码点字而已,具体讨论请查看此处issues

krakend不支持同时配置多个Method

这个意思就是如果/myserviceA/{level1}/{level2}/{level3}这个URI有POSTPUTGET三个方法,你得分别配置三次

{
  "endpoint": "/myserviceA/{level1}/{level2}/{level3}",
  "method": "POST",
  "backend": [
    {
      "host": [ "http://serverA/" ],
      "url_pattern": "/{level1}/{level2}/{level3}"
    }
  ]
},
{
  "endpoint": "/myserviceA/{level1}/{level2}/{level3}",
  "method": "PUT", 
  "backend": [
    {
      "host": [ "http://serverA/" ],
      "url_pattern": "/{level1}/{level2}/{level3}"
    }
  ]
},
{
  "endpoint": "/myserviceA/{level1}/{level2}/{level3}",
  "method": "GET", 
  "backend": [
    {
      "host": [ "http://serverA/" ],
      "url_pattern": "/{level1}/{level2}/{level3}"
    }
  ]
},

是不是感觉心态要爆炸,这得写的多繁琐啊。

krakend配置文件模板难用

如以上示例所见,krakend的配置管理是个大难题,通常我们需要一个模板来简化配置,无奈官方提供的模板功能太弱且难用,我在公司用apollo作为配置中心, key为config,value就是krakend的json配置文件,因为配置较多,超过了value的长度限制,不得已,只能拆,根据host拆成不同的文件,然后用patch的方式再将json文件合并成一个,也不是不能用,至少比官方模板要好一点点吧,不过核心问题还是配置文件不能简化,这真的是很伤脑筋啊。

HTTP响应配置

一开始想当然地觉着使用krakend代理的http请求响应是透传的,但偏偏不是这样的,默认情况是只要是返回的http code大于400,krakend返回的就是500,要想做到透传,需要增加两次no-op配置,如下所示:

{
    "endpoint": "/auth/login",
    "output_encoding": "no-op",
    "backend": [
        {
            "encoding": "no-op",
            "host": [ "localhost:8080" ],
            "url_pattern": "/__debug/login"
        }
    ]
}

点此查看文档 正如你所看到的那样,配置文件在不知不觉中越变越长……


说了那么多槽点,总得说点优点吧,毕竟我也是给这个项目做出过贡献的人,优点我总结了两点

  1. 简单,这个在开篇也说了
  2. 无状态,不需要数据库,貌似还不支持动态更新配置

客观来说,因为简单,所以接入门槛自然很低,熟悉gin框架的情况下,自定义插件也非常容易,适合轻量型网关场景,确实解决了团队网关从无到有这个问题,根据使用情况来看,目前最大的问题在于配置文件过于冗长,这个是先天劣势,不好弥补;再就是不支持websocket。但是瑕不掩瑜,krakend自有其适用的场景和其存在的价值。哦,不过呢,随着团队业务的发展,后期大概率是要换掉krakend了。

731 views

More from this blog

2025: 祛魅 灰度 念头通达

今天是2025年的最后一天,当大家都在准备下班的时候,好巧不巧的,我刚好发现了一个不大不小的问题,大胆猜想,小心求证,向上反馈,暴露风险,作为2025年工作注解,实在是再有趣不过了。 今年的工作,从结果上看,还算平稳,至于过程,有太多不可言说的部分。厂里打镙丝的牛马,有工资可拿,理应知足了,至于其它的,与己无关,也没那么重要了。 祛魅 近距离观察大厂,才发现一些违背常识/直觉的事实:路人以为的高大

Feb 28, 20261 min read21

大厂祛魅:破碎的专注力

毁掉一个人最直接的方法,就是毁掉ta的专注力。 这句话的出处已然模糊,但放在大厂环境中,却显得格外深刻。 围城 大厂宛如一座围城。城外的人满怀憧憬,目之所及皆是光鲜;城内的人却如困笼之鸟,翅膀日渐退化,每日挣扎求生。 高大上 不可否认,大厂的硬件设施确实令人艳羡:宽敞的独立园区内,来往穿梭的人群中,几乎人人手握智能设备。这看似现代化的景象背后,却藏着一个无奈的事实:在工作时段,每台电脑都被严密监控,连听音乐都成奢望。于是,工作之余玩手机,成了许多人难得的解压方式。 大厂的品牌效应确实强大。外界对...

Jul 29, 20251 min read138

Black Swan

黑天鹅理论 是指极不可能发生,实际上却又发生的事件 来到大厂打工已经满一个月了,从一开始的手足无措,到逐渐度过不适期,也算是适应了吧。 不适应 刚入职时,不适应的地方还是挺多的。 第一次只使用台式机工作,这就限制了我一天中的绝大部分时间,都必须呆在自己的工位上,好在工位足够大。只是人与人的沟通少了很多,有问题只能在工位上通过 IM 呼对方,有种魔幻又现实的感觉 第一次只能用 Windows,也不能 WSL,这给我的工作效率带来了很大影响,不能用熟悉的软件,就连写代码用的 VSCode 的...

Jan 24, 20251 min read74

2024年: 逐渐平静

这个世界是一面镜子,会把你的感受反射给你 2024 开端: 相由心生 那时,还带着一着愤懑,因为拿到了低绩效,虽然内心知道这是公司经营困难,想让我离开的一种策略,但仍然感受到自己那可笑的自尊受到了践踏。自那之后,非必要不加班,只做份内事,尽可能地不去涉及份外之事。 2024 年中: 与人为善 组里的项目眼见不行了,我被迫去支援 AI 项目,久违地写起了 python,项目接近完成时,意外收到通知:我拿到大礼包了。在这之前,架构师因故裸辞。在我离开之后不到两周,我的 TL 也裸辞了,直到同事告诉...

Jan 9, 20251 min read92

企业软件之殇

殇 动词 未成年而死。 名词 战死者。 笔者经历了两家打着云原生旗号的企业软件/解决方案公司,都是中途加入,项目都以解(失)散(败)告终。 云原生解决方案 NB 公司:一个传统的 IDC 小厂,想着借云原生的热度,进军企业软件市场。 在加入这个项目之前,笔者考取了 CKAD 认证,彼时对 K8s 相当着迷。先简要介绍一下这个项目背景: 基于 Rancher (换皮肤)的二次开发项目,名字叫:HCaaS ,在笔者加入这个团队之前,项目已经开发近两年了,除了 TL 之外,其它人之前都...

Jul 1, 20241 min read103

just for fun

57 posts

I'm a Software Engineer