<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>kong | 伪架构师</title>
    <link>/tags/kong/</link>
      <atom:link href="/tags/kong/index.xml" rel="self" type="application/rss+xml" />
    <description>kong</description>
    <generator>Source Themes Academic (https://sourcethemes.com/academic/)</generator><language>zh</language><lastBuildDate>Fri, 11 May 2018 12:26:22 +0800</lastBuildDate>
    <image>
      <url>/img/logo-wide.png</url>
      <title>kong</title>
      <link>/tags/kong/</link>
    </image>
    
    <item>
      <title>来自骷髅岛的 Ingress Controller：Kong</title>
      <link>/post/intro-kong/</link>
      <pubDate>Fri, 11 May 2018 12:26:22 +0800</pubDate>
      <guid>/post/intro-kong/</guid>
      <description>

&lt;p&gt;&lt;a href=&#34;https://konghq.com/&#34; target=&#34;_blank&#34;&gt;Kong&lt;/a&gt;，是一个在 Nginx 反向代理基础上发展而来的 API 网关产品。我之前一直在推动的 Service Mesh，主要关注的是集群（Mesh）内微服务之间的关系，而 API 网关所管理的则是微服务集群边缘，对外服务的管理。（据我观测，Istio 近期的文档已经出现了 Gateway 等说法，似乎也对这方面的问题颇有兴趣的样子）。&lt;/p&gt;

&lt;p&gt;传统的 API：&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/comp-tra.png&#34; alt=&#34;Traditional api&#34; /&gt;&lt;/p&gt;

&lt;p&gt;API Gateway：&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/comp-kong.png&#34; alt=&#34;API Gateway&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://konghq.com/blog/kubernetes-ingress-controller-for-kong/&#34; target=&#34;_blank&#34;&gt;5 月 8 日，Kong 发布了 Ingress Controller&lt;/a&gt;，对 Kubernetes 和对 Kong 自身来说都是个有意思的事情。&lt;/p&gt;

&lt;p&gt;首先，Ingress Controller 本来应该负责集群的对外通信，有些 Ingress Controller，例如 haproxy 和 Traefik 已经初步具备了这方面的能力。
其次，Kong 之前使用 API 调用的方式来进行管理，在 Ingress Controller 的上下文中，改用 CRD 方式进行管理，对于我等 YAML 程序员来说，无疑是个大大的利好消息。&lt;/p&gt;

&lt;p&gt;Kong 使用&lt;a href=&#34;https://konghq.com/plugins/&#34; target=&#34;_blank&#34;&gt;插件&lt;/a&gt;的方式提供了一些常见功能，这些现在也可以用 CRD 方式进行使用，其中包括日志、限流、认证、鉴权几大类。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/intro-illustration.png&#34; alt=&#34;plugins&#34; /&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Kong 同时提供商业和社区两个版本，目前有部分插件也是商业版独占的。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;今天这一篇，就会对 Kong Ingress Controller 从部署到应用的介绍。&lt;/p&gt;

&lt;h2 id=&#34;安装&#34;&gt;安装&lt;/h2&gt;

&lt;p&gt;官方提供了一个简易的 Kubernetes 环境中的&lt;a href=&#34;https://raw.githubusercontent.com/Kong/kubernetes-ingress-controller/master/deploy/single/all-in-one-postgres.yaml&#34; target=&#34;_blank&#34;&gt;安装文件&lt;/a&gt;；另外在 Ingress Controller 出现之前，Kong 也有一个相对更丰富的 &lt;a href=&#34;https://getkong.org/install/kubernetes/&#34; target=&#34;_blank&#34;&gt;Kubernetes 下的安装文档&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;全部组件都运行在 kong 命名空间。&lt;/p&gt;

&lt;h3 id=&#34;数据库&#34;&gt;数据库&lt;/h3&gt;

&lt;p&gt;安装过程中会创建一个 Postgres 的 StatefulSet，前面提到，这一版本对 Kubernetes 集群的最低版本要求是 1.8，如果是 1.8 版本，需要将这一个 StatefulSet API 版本改为 &lt;code&gt;apps/v1beta2&lt;/code&gt;。另外这一部分需要用 PVC 的形式给数据提供存储空间，所以集群中应该设置缺省 StorageClass。完整的 Kubernetes 安装文档中，还介绍了 Cassandra 的存储方式。&lt;/p&gt;

&lt;h3 id=&#34;crd&#34;&gt;CRD&lt;/h3&gt;

&lt;p&gt;安装过程中创建了如下的自定义资源：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;凭据：用于身份认证。&lt;/li&gt;
&lt;li&gt;服务消费者：给不同的 API 用户提供不同的消费者身份，以便实施不同的治理方式。&lt;/li&gt;
&lt;li&gt;插件：将过去使用 HTTP API 管理的插件系统，以 CRD 的形式在 Kubernetes 环境下统一管理。&lt;/li&gt;
&lt;li&gt;KongIngress：对反向代理行为本身进行定义。&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;服务&#34;&gt;服务&lt;/h3&gt;

&lt;p&gt;其中提供了两组服务：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;kong-ingress-controller：暴露 8001 端口，用于对 Kong 进行管理。这里建议将服务类型改为 ClusterIP，而不是直接暴露于公网。&lt;/li&gt;
&lt;li&gt;kong-proxy：Ingress 服务，对其承载的接口调用都从此经过，可以根据集群情况酌情使用 NodePort 或者 ClusterIP -&amp;gt; Ingress 的方式对外提供服务。&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;提供服务&#34;&gt;提供服务&lt;/h2&gt;

&lt;p&gt;安装结束后，就可以使用网关来对外提供服务了。&lt;/p&gt;

&lt;p&gt;官方提供了一个简单的&lt;a href=&#34;https://raw.githubusercontent.com/Kong/kubernetes-ingress-controller/master/deploy/manifests/dummy-application.yaml&#34; target=&#34;_blank&#34;&gt;例子应用&lt;/a&gt;，我们当然也可以选择别的应用来试用。为他编写一个 Ingress 资源：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: dummy
  annotations:
    kubernetes.io/ingress.class: nginx # 这里仍然是 nginx
spec:
  rules:
  - host: dummy.example.com
    http:
      paths:
      - path: /
        backend:
          serviceName: http-svc
          servicePort: 89
&lt;/code&gt;&lt;/pre&gt;

&lt;blockquote&gt;
&lt;p&gt;如果没有公网 Loadbalancer 条件，可以使用 &lt;code&gt;/etc/hosts&lt;/code&gt;、dnsmasq、或者 curl host 几种方式来模拟。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;ingress 资源创建成功之后，就可以使用域名来访问这一服务了。&lt;/p&gt;

&lt;h3 id=&#34;tls-加密&#34;&gt;TLS 加密&lt;/h3&gt;

&lt;p&gt;作为 Ingress Controller，添加证书提供 https 服务也是基本要求之一。这方面 Kong Ingress Controller 使用的是 tls secret 的方式：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;首先获取证书，可以自行签名，或者使用已有证书文件。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kubectl create secret tls rocks --key privkey.pem --cert fullchain.pem&lt;/code&gt;：创建一个名为 &lt;code&gt;rocks&lt;/code&gt; 的 Secret，其中包含我们的证书和私钥。&lt;/li&gt;

&lt;li&gt;&lt;p&gt;在 Ingress 资源定义中加入下列内容，引用刚才创建的 Secret：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;tls:
- hosts:
- dummy.example.com
secretName: rocks
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;这样就可以使用 https 进行访问了。&lt;/p&gt;

&lt;h2 id=&#34;试用限流插件&#34;&gt;试用限流插件&lt;/h2&gt;

&lt;p&gt;前面提到，Kong Ingress Controller 使用 CRD 方式来实现插件的应用。下面我们创建一个限流插件的 CRD：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
  name: one-per-second-ten-per-hour
config:
  hour: 10
  limit_by: ip
  second: 1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;目前并没有很完善的插件 CRD 规范的文档，因此其中的具体字段需要去该插件的文档页面去查找，例如这里引用的 &lt;a href=&#34;https://getkong.org/plugins/rate-limiting/&#34; target=&#34;_blank&#34;&gt;Ratelimit&lt;/a&gt;。在这一个 YAML 中我们会发现，其中并没有表明具体使用的插件以及对应的服务，通过对 controller 管理端口的 &lt;code&gt;/plugins&lt;/code&gt; 进行查询，也会看到其中并没有定义活动的插件。&lt;/p&gt;

&lt;p&gt;要把它应用到具体服务上，还需要修改我们要控制的 Ingress 资源，在其中加入注解，来引用这一 CRD：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;kubernetes.io/ingress.class: nginx
rate-limiting.plugin.konghq.com: one-per-second-ten-per-hour
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;提交新的 Ingress 之后，再次访问管理端口的 &lt;code&gt;plugins&lt;/code&gt; 路径，会得到以下响应：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-json&#34;&gt;{
    &amp;quot;total&amp;quot;: 1,
    &amp;quot;data&amp;quot;: [
        {
            &amp;quot;created_at&amp;quot;: 1525966801000,
            &amp;quot;config&amp;quot;: {
                &amp;quot;redis_database&amp;quot;: 0,
                &amp;quot;policy&amp;quot;: &amp;quot;cluster&amp;quot;,
                &amp;quot;redis_timeout&amp;quot;: 2000,
                &amp;quot;hide_client_headers&amp;quot;: false,
                &amp;quot;hour&amp;quot;: 20,
                &amp;quot;limit_by&amp;quot;: &amp;quot;ip&amp;quot;,
                &amp;quot;redis_port&amp;quot;: 6379,
                &amp;quot;second&amp;quot;: 10,
                &amp;quot;fault_tolerant&amp;quot;: true
            },
            &amp;quot;id&amp;quot;: &amp;quot;8539eb6f-5467-11e8-a92e-000d3a07d45d&amp;quot;,
            &amp;quot;name&amp;quot;: &amp;quot;rate-limiting&amp;quot;,
            &amp;quot;enabled&amp;quot;: true,
            &amp;quot;route_id&amp;quot;: &amp;quot;f2961715-11fd-410a-a934-dbd6822e5fac&amp;quot;
        }
    ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;可以使用 siege 或者 curl/wrk 等其他工具来访问 API，会发现超过限度之后，服务器返回 429 的状态码：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;HTTP/1.1 200     0.20 secs:     727 bytes ==&amp;gt; GET  /
HTTP/1.1 200     0.22 secs:     729 bytes ==&amp;gt; GET  /
HTTP/1.1 429     0.20 secs:      38 bytes ==&amp;gt; GET  /
HTTP/1.1 429     0.21 secs:      38 bytes ==&amp;gt; GET  /
HTTP/1.1 429     0.20 secs:      38 bytes ==&amp;gt; GET  /
HTTP/1.1 200     0.20 secs:     729 bytes ==&amp;gt; GET  /
HTTP/1.1 200     0.20 secs:     727 bytes ==&amp;gt; GET  /
HTTP/1.1 429     0.20 secs:      38 bytes ==&amp;gt; GET  /
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;证明限流功能已经生效。&lt;/p&gt;

&lt;h3 id=&#34;试用消费者&#34;&gt;试用消费者&lt;/h3&gt;

&lt;p&gt;前面提到，可以使用消费者这一概念，对微服务的用户身份加以甄别，从而提供不同的管控方式。在前面的基础上，我们希望为部分用户修改一下响应内容。&lt;/p&gt;

&lt;p&gt;首先创建一个 KongConsumer 对象：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: configuration.konghq.com/v1
kind: KongConsumer
metadata:
  name: rich
username: boss
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;接下来，为这个用户创建凭据，&lt;strong&gt;凭据是需要认证的，所以还要启用一个插件：key-auth&lt;/strong&gt;，官方文档中并没有提及这一点：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: configuration.konghq.com/v1
kind: KongCredential
metadata:
  name: rich-login
consumerRef: rich # 如果删除这一字段，就代表面向所有消费者。
type: key-auth
config:
  key: 62eb165c070a41d5c1b58d9d3d725ca1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;然后，为这个用户创建一个插件配置&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
  name: rich-response
consumerRef: rich
config:
  hour: 100
  limit_by: ip
  second: 10
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;最后，在 Ingress 资源中启用&lt;strong&gt;两个插件&lt;/strong&gt;，分别是 &lt;code&gt;key-auth&lt;/code&gt; 和 &lt;code&gt;response-transformer&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;response-transformer.plugin.konghq.com: boss
key-auth.plugin.konghq.com: auth
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;重新配置 Ingress 之后，可以使用 curl 进行校验：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;curl --header &amp;quot;apikey: aasome_key_data&amp;quot; -s -i https://dummy.example.com
HTTP/1.1 403 Forbidden
Date: Fri, 11 May 2018 04:17:57 GMT
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Server: kong/0.13.1

{&amp;quot;message&amp;quot;:&amp;quot;Invalid authentication credentials&amp;quot;}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;可以看到上面的认证没能通过。&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;curl --header &amp;quot;apikey: some_key_data&amp;quot; -s -i https://dummy.example.com | grep boss
boss:  true
    x-consumer-username=boss2
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Key Auth 认证插件根据 APIKey 取得了用户名，并且激活了 Response Transformer 插件，在 Header 中加入了我们配置的内容。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Kong 原有的 API 在这里还是可以使用的，例如：
1. &lt;code&gt;curl http://[api-url]/plugins&lt;/code&gt; 查询生效插件
2. &lt;code&gt;curl http://[api-url]&lt;/code&gt; 返回 JSON 中的 &lt;code&gt;/plugins/available_on_server&lt;/code&gt; 列出所有可用插件。
3. &lt;code&gt;curl ttp://[api-url]/consumers&lt;/code&gt; 列出所有消费者。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;相关链接&#34;&gt;相关链接：&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;https://konghq.com/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;https://raw.githubusercontent.com/Kong/kubernetes-ingress-controller/master/deploy/single/all-in-one-postgres.yaml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;https://raw.githubusercontent.com/Kong/kubernetes-ingress-controller/master/deploy/manifests/dummy-application.yaml&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
</description>
    </item>
    
  </channel>
</rss>
