# Gloo，充满想象力的 API Gateway

## 缘起

2018 年 11 月，在 Medium 上闲逛时候看到一篇吓人的东西：[Introducing SuperGloo: The Service Mesh Orchestration Platform](https://medium.com/solo-io/announcing-gloo-the-function-gateway-3f0860ef6600)，服务网格编排器——当时感觉挺奇幻的，在群里打趣了一下，并不以为意；直到有一天看到了另外一条消息：

%[https://x.com/christianposta/status/1080483078139572229] 

著名技术网红 Christian Posta 跳槽了，又是这个 [solo.io](https://solo.io)，这就不能不好奇了。在网站上浏览一圈，感觉脑洞大开，不管是否现实，真的有趣，一时手痒，又拿出祖传的 Hello world，有了这篇文章。

## 产品

[Solo.io](https://solo.io) 首页上列出了六个产品：

* [Gloo](https://github.com/solo-io/gloo)：混合应用网关；
    
* [GlooE](https://www.solo.io/glooe)：Gloo 的企业版；
    
* [SuperGloo](https://github.com/solo-io/supergloo)：服务网格编排器；
    
* [Sqoop](https://github.com/solo-io/sqoop)：构建在 Gloo 之上的 GraphQL 引擎，提供跨 API 的查询支持；
    
* [UniK](https://github.com/solo-io/unik)：将代码编译为 unikernels 和 MicroVM；
    
* [Squash](https://github.com/solo-io/squash)：在多云环境下为 IDE 提供微服务调试支持。
    

自然我最感兴趣的就是 SuperGloo 和 Gloo 了。宣发稿中已经做出了很多介绍，根据 CLI Reference 看看其中的亮点。

### SuperGloo

注意，这是一个“网格编排器”，因此其特性都是**跨网格的**。

* 支持 Istio、Consul、Linkerd2 以及 AppMesh 的安装部署；
    
* 路由规则：
    
    * 流量迁移；
        
    * 故障注入；
        
    * 超时控制；
        
    * 重试控制；
        
    * CORS 策略；
        
    * 流量镜像；
        
    * Header 处理。
        
* 安全加固：
    
    * 策略管理；
        
    * mTLS；
        
    * Ingress 加固
        

事实上这部分的特性主要是基于 Istio 的实现，Linkerd2 和 Consul 自身的功能还相当匮乏，具体情况可以参看其[路线快照](https://supergloo.solo.io/#roadmap)

### Gloo

作为一个混合应用网关，其最大特色就是跨云的网关支持：

* 支持 Upstream：
    
    * Kubernetes
        
    * AWS
        
    * Azure
        
    * Consule
        
    * Static
        
* VirtualService：在网关上定义虚拟服务，并在此基础上提供限流。
    
* 路由：在虚拟服务中定义访问的路由规则。
    

## Gloo 初体验

下面我们会使用 Gloo 将一个 Kubernetes 集群上的 HTTPBIN 服务和一个运行在 Azure 上的 Function 粘合起来，合作提供服务，并在最后进行限流测试。

## Gloo 部署

> Gloo 要求 Kubernetes 版本在 1.8 以上

使用脚本安装客户端：

```bash
curl -sL https://run.solo.io/gloo/install | sh
```

按照后续指引完成之后，就安装好了 glooctl 的客户端了，接下来是部署 Gloo：

```shell
$ glooctl install kube

$ kubectl get po -n gloo-system
NAME                            READY   STATUS    RESTARTS   AGE
discovery-78bb6fff4c-86t9c      1/1     Running   0          1m
gateway-6bc69b9cdc-4cgpv        1/1     Running   0          1m
gateway-proxy-bd895c6db-pxk8q   1/1     Running   0          1m
gloo-7588c6d774-25z5f           1/1     Running   0          1m

$ kubectl get svc -n gloo-system
NAME            TYPE           CLUSTER-IP       EXTERNAL-IP      PORT(S)          AGE
gateway-proxy   LoadBalancer   10.245.237.65    203.129.214.16   8080:30859/TCP   1m
gloo            ClusterIP      10.245.194.168   <none>           9977/TCP         1m
```

这样 Gloo 就成功启动并运行了。

### 部署 Kubernetes 应用

首先部署我们的老朋友 httpbin：

```shell

$ kubectl create deployment httpbin --image=citizenstig/httpbin
deployment.apps/httpbin created
$ kubectl expose deploy httpbin --name=httpbin --port 8000 --selector="app=httpbin"
service/httpbin exposed
$ kubectl get svc httpbin
NAME      TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
httpbin   ClusterIP   10.245.47.195   <none>        8000/TCP   1m
```

服务已经成功建立，是缺省的 ClusterIP 类型。

## 通过 Gloo 提供对外服务

我们希望通过 `http://[service-ip]/httpbin/` 的形式，透过 Gloo 的负载均衡服务，对外开放 httpbin 的 API。在 Gloo 中首先通过其发现服务，查找系统中可用的 Upstream：

```shell
$ glooctl get upstreams

+--------------------------------+------------+----------+------------------------------+
|            UPSTREAM            |    TYPE    |  STATUS  |           DETAILS            |
+--------------------------------+------------+----------+------------------------------+
| default-httpbin-8000           | Kubernetes | Accepted | svc name:      httpbin       |
|                                |            |          | svc namespace: default       |
|                                |            |          | port:          8000          |
......
```

可以看到，Gloo 使用 Kubernetes Service 创建了 Upstream；`default-httpbin-8000`。可以使用 `glooctl get upstream default-httpbin-8000 -o yaml` 获取其定义：

```yaml
discoveryMetadata: {}
metadata:
  labels:
    app: httpbin
    discovered_by: kubernetesplugin
  name: default-httpbin-8000
  namespace: gloo-system
  resourceVersion: "13678"
status:
  reportedBy: gloo
  state: Accepted
upstreamSpec:
  kube:
    selector:
      app: httpbin
    serviceName: httpbin
    serviceNamespace: default
    servicePort: 8000
```

接下来为服务创建一个 `httpbin` 路径：

```shell
$ glooctl add route \
  --path-prefix /httpbin \
  --dest-name default-httpbin-8000 \
  --prefix-rewrite /
selected virtualservice default for route
+-----------------+---------+------+----------+---------+--------------------------------+
| VIRTUAL SERVICE | DOMAINS | SSL  |  STATUS  | PLUGINS |             ROUTES             |
+-----------------+---------+------+----------+---------+--------------------------------+
| default         | *       | none | Accepted |         | /httpbin ->                    |
|                 |         |      |          |         | default-httpbin-8000           |
```

可以看到，为了创建这个路由规则，首先创建了缺省的虚拟服务。

## 测试服务

```shell
$ export GATEWAY_URL=$(glooctl gateway url)
$ curl ${GATEWAY_URL}/httpbin/get
{
  "args": {},
  "headers": {
    "Accept": "*/*",
    "Content-Length": "0",
    "Host": "206.189.254.16:8080",
    "User-Agent": "curl/7.54.0",
    "X-Envoy-Expected-Rq-Timeout-Ms": "15000",
    "X-Envoy-Original-Path": "/httpbin/get",
    "X-Request-Id": "1bb19f60-57c9-43aa-b78a-1cd556cc5800"
  },
  "origin": "10.244.93.3",
  "url": "http://206.189.254.16:8080/get"
}
$ curl ${GATEWAY_URL}/httpbin/ip
{
  "origin": "10.244.93.3"
}
```

可以看到，我们成功得到了想要的路径映射。

## 为 Lambda 创建 Upstream

Lambda 是不会被自动发现的，因此我们要手工创建，这里采用交互式的方法：

### 创建 Secret

```shell
glooctl create secret aws -i
? Please choose a namespace gloo-system
? name of secret aws
? Enter AWS Access Key ID (leave empty to read credentials from ~/.aws/credentials):  ...
? Enter AWS Secret Key (leave empty to read credentials from ~/.aws/credentials):  ...
```

### 创建 Upstream

```shell
$ glooctl create upstream -i
? What type of Upstream do you want to create? aws
? What region are the AWS services in for this upstream? us-east-2
? Choose an AWS credentials secret to link to this upstream:  gloo-system.aws
? namespace: gloo-system
? name: hello-lambda
+--------------+------+----------+-------------------------+
|   UPSTREAM   | TYPE |  STATUS  |         DETAILS         |
+--------------+------+----------+-------------------------+
| hello-lambda | AWS  | Accepted | region: us-east-2       |
|              |      |          | secret: gloo-system.aws |
|              |      |          |                         |
+--------------+------+----------+-------------------------+
```

### 为 Lambda 创建 Route

接下来为服务创建一个 `httpbin` 路径：

```shell
$ glooctl add route \
  --path-prefix /lambda \
  --dest-name hello-lambda \
  --function hello-world:1
```

再次成功创建之后，调用新生成的 `/lambda`，**并未成功**。

## 为 Azure function app 创建 Route

**目前并不支持 Azure Secret 的创建。**，所以就连 Upstream 也无法开始了。

## 总结

梦想很丰满。。
