API网关Kong学习笔记(二):Kong与Kubernetes集成的方法

作者:李佶澳  更新时间:2019-05-20 14:48:47 +0800

  项目    kong    刷新

目录

说明

经过前面的学习(Nginx、OpenResty和Kong的基本概念与使用方法),对Api网关是什么,以及Kong能够做什么已经有了足够的了解。 现在Kubernetes一统计算资源与应用发布编排的趋势已经形成,我们更关心Kong能否和Kubernetes结合。

Kong是一个Api网关,也是一个特性更丰富的反向代理。既然它有代理流量的功能,那么能不能直接成为Kubernetes的流量入口?使Kubernetes上托管的服务都通过Kong发布。

Kong实现了一个Kubernetes Ingress Controller(后面用kong-ingress-controller指代这个项目)来做这件事。另外把整个Kong部署在Kubernetes中也是可行的,见Kong CE or EE on Kubernetes

相关笔记

2019-05-06 16:28:56:kong 1.1.x有了一个重大变换,实现了db-less模式,可以不使用数据库了,见笔记二十六:查看全部笔记如果是刚开始学习kong,直接从1.x开始,0.x已经不再维护,0.15是0.x的最后一个版本。

前19篇笔记是刚开始接触kong时记录的,使用的版本是0.14.1,当时对kong一知半解,笔记比较杂乱。第二十篇开始是再次折腾时的笔记,使用的版本是1.0.3,笔记相对条理一些。

从0.x到1.x需要关注的变化有:

  1. 插件全部使用pdk
  2. 0.x中不鼓励使用的特性都被移除了;
  3. 全部使用kong.db,以前独立的dao彻底清除,代码简洁清晰了。

先说组成

Kubernetes Ingress Controller for Kong中介绍了在kubernetes中的部署方法,总共有三部分。

第一部分是数据库。kong不支持mysql,使用的数据库只能是9.4及以上版本的postgres,或者Cassandra 3.x.x。

第二部分是ingress-controller.yaml,是一个Deployment,Pod中有三个容器:

第一个容器是InitContainer,负责初始化数据库;

第二个容器是kong-proxy,只开放了admin接口,负责提供Kong的管理API;

第三个容器是kong-ingress-controller,负责Kubernetes资源与Kong的衔接,监测Kubernetes资源的变动,及时调用Kong的管理API,更新Kong的配置。

第三部分是kong.yaml,可以是Deployment,也可以是Daemonset,pod中只有一个kong-proxy容器,禁用了admin接口,只提供代理服务。

控制平面与数据平面

ingress-controller.yaml是控制平面,提供管理接口、下发规则;kong.yaml是数据平面,反向代理对API的请求。

下面是kong-ingress-controller中给出的示意图,红色箭头表示控制信息的流动,绿色箭头表示API请求的流动,dataplane就是属于kong.yaml的多个Pod:

kong kubernetes ingress conroller deployment

CustomResourceDefinitions

Kubernetes支持自定义资源Extend the Kubernetes API with CustomResourceDefinitions,kong-ingress-controller充分利用了这个简称为CRD的特性。

Cluster-types.yml中定义了KongPluginKongConsumerKongCredentialKongIngress四种CRD资源(@2018-09-30 17:19:38)。

Kong ingress controller: custom types对这四种CRD资源做了说明:

KongConsumer:   kong的用户
KongPlugin:     kong的插件的配置项
KongCredential: kong用户的认证凭证
KongIngress:    对用户创建的ingress的补充配置

KongConsumer定义了kong的用户:

apiVersion: configuration.konghq.com/v1
kind: KongConsumer
metadata:
  name: <object name>
  namespace: <object namespace>
username: <user name>
custom_id: <custom ID>

例如:

apiVersion: configuration.konghq.com/v1
kind: KongConsumer
metadata:
  name: consumer-team-x
username: team-X
custom_id: my_team_x # optional and not recommended, please use `username`

KongCredential是用户的认证凭证,它的typekong支持的认证方式一一对应:

apiVersion: configuration.konghq.com/v1
kind: KongCredential
metadata:
  name: credential-team-x
consumerRef: consumer-team-x
type: key-auth
config:
  key: 62eb165c070a41d5c1b58d9d3d725ca1

KongPlugin是可以具体到用户的插件配置,注意它可是全局配置,也可以是针对某个用户的配置(consumerRef关联到特定用户):

apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
  name: <object name>
  namespace: <object namespace>
  labels:
    global: "true" # optional, please note the quotes around true
consumerRef: <optional, name of an existing consumer> # optional
disabled: <boolean>  # optional
config:
    key: value
plugin: <name-of-plugin>

例如:

apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
  name: http-svc-consumer-ratelimiting
consumerRef: consumer-team-x
config:
  hour: 1000
  limit_by: ip
  second: 100
plugin: rate-limiting

KongIngress是对已经存在的ingress的补充。

Kong-ingress-controller会主动监测kuernetes集群中所有的ingress,为每个配置了host的ingress在kong中创建一个route,为每个被ingress使用的backend在kong中创建一个service

Ingress是kubernetes定义的(Kubernetes Ingress定义),对于那些与kong相关但是Ingress不支持的配置项,需要在KongIngress中配置。Kong-ingress-controller在将kubernetes中Ingress同步到kong的时候,会到同一个namespace中查找Ingress的annotations(configuration.konghq.com)中指定的KongIngress,如果在annotations中指定,则查找同名的Ingress。

// kong/kubernetes-ingress-controller/internal/ingress/controller/kong.go
func (n *NGINXController) getKongIngress(ing *extensions.Ingress) (*configurationv1.KongIngress, error) {
	confName := annotations.ExtractConfigurationName(ing.Annotations)
	if confName != "" {
		return n.store.GetKongIngress(ing.Namespace, confName)
	}

	return n.store.GetKongIngress(ing.Namespace, ing.Name)
}

下面是一个完成的KongIngress定义,包含upstreamproxyroute三部分:

apiVersion: configuration.konghq.com/v1
kind: KongIngress
metadata:
  name: configuration-demo
upstream:
  hash_on: none
  hash_fallback: none
  healthchecks:
    active:
      concurrency: 10
      healthy:
        http_statuses:
        - 200
        - 302
        interval: 0
        successes: 0
      http_path: "/"
      timeout: 1
      unhealthy:
        http_failures: 0
        http_statuses:
        - 429
        interval: 0
        tcp_failures: 0
        timeouts: 0
    passive:
      healthy:
        http_statuses:
        - 200
        successes: 0
      unhealthy:
        http_failures: 0
        http_statuses:
        - 429
        - 503
        tcp_failures: 0
        timeouts: 0
    slots: 10
proxy:
  protocol: http
  path: /
  connect_timeout: 10000
  retries: 10
  read_timeout: 10000
  write_timeout: 10000
route:
  methods:
  - POST
  - GET
  regex_priority: 0
  strip_path: false
  preserve_host: true
  protocols:
  - http
  - https

它们的用法在后面章节演示。

开始部署

这里主要是学习,直接使用了Master分支中提供的yaml文件(commit: 34e9b4165ab64318d00028f42b797e77dac65e24),不是正式的Release版本。

创建custerm-types:

wget https://raw.githubusercontent.com/Kong/kubernetes-ingress-controller/master/deploy/manifests/custom-types.yaml
kubectl create -f custom-types.yaml

创建名为kong的namespace,后面yaml描述的任务部署在这个namespace中:

wget https://raw.githubusercontent.com/Kong/kubernetes-ingress-controller/master/deploy/manifests/namespace.yaml
kubectl create -f namespace.yaml

设置RBAC,为kong namespace中的serivceaccount绑定角色,并赋予权限:

wget https://raw.githubusercontent.com/Kong/kubernetes-ingress-controller/master/deploy/manifests/rbac.yaml
kubectl create -f rbac.yaml

部署postgre,这里为了方便直接在Kubernetes部署了,在操作系统上的部署方法参考:PostgresSQL数据库的基本使用

wget https://raw.githubusercontent.com/Kong/kubernetes-ingress-controller/master/deploy/manifests/postgres.yaml
kubectl create -f postgres.yaml

注意postgres.yaml是一个statfulset,并且要为每个Pod绑定PV,如果你的集群不支持,且纯粹试用可以注释掉(这样postgre的pod重建时,数据会丢失):

...
      volumes:
      - name: datadir
        persistentVolumeClaim:
          claimName: datadir
  volumeClaimTemplates:
  - metadata:
      name: datadir
    spec:
      accessModes:
        - "ReadWriteOnce"
      resources:
        requests:
          storage: 1Gi

部署kube-ingress-controller:

wget https://raw.githubusercontent.com/Kong/kubernetes-ingress-controller/master/deploy/manifests/ingress-controller.yaml
kubectl create -f ingress-controller.yaml

部署kong:

wget https://raw.githubusercontent.com/Kong/kubernetes-ingress-controller/master/deploy/manifests/kong.yaml
kubectl create -f kong.yaml

kong.yaml中少了一个service(commit: 34e9b4165ab64318d00028f42b797e77dac65e24),需要加上:

---
apiVersion: v1
kind: Service
metadata:
  name: kong-proxy
  namespace: kong
spec:
  type: NodePort
  ports:
  - name: kong-proxy
    port: 80
    targetPort: 8000
    protocol: TCP
  - name: kong-proxy-ssl
    port: 443
    targetPort: 8443
    protocol: TCP
  selector:
    app: kong

确保所有的Pod正常运行:

$ kubectl -n kong get pod -o wide
NAME                                     READY     STATUS    RESTARTS   AGE       IP             NODE
kong-54875c6bd7-8ttgf                    1/1       Running   0          15s       192.168.78.8   10.10.173.203
kong-ingress-controller-cfc7dc7d-vnp64   2/2       Running   7          15m       192.168.78.6   10.10.173.203
postgres-0                               1/1       Running   0          17m       192.168.78.5   10.10.173.203

相关Service的状态:

$ kubectl -n kong get svc
NAME                      TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
kong-ingress-controller   NodePort    10.254.147.53   <none>        8001:31627/TCP               27m
kong-proxy                NodePort    10.254.237.61   <none>        80:32057/TCP,443:31552/TCP   52s
postgres                  ClusterIP   10.254.77.113   <none>        5432/TCP                     47m

然后可以部署一个第三方提供的Dashboard:PGBI/kong-dashboard

---
apiVersion: v1
kind: Service
metadata:
  name: kong-dashboard
  namespace: kong
spec:
  type: NodePort
  ports:
  - name: kong-dashboard
    port: 80
    targetPort: 8080
    protocol: TCP
  selector:
    app: dashboard
---

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: dashboard
  namespace: kong
spec:
  template:
    metadata:
      labels:
        name: dashboard
        app: dashboard
    spec:
      containers:
      - name: kong-dashboard
        args:
        - start
        - --kong-url http://kong-ingress-controller:8001
        - --basic-auth admin=admin
        image: pgbi/kong-dashboard:latest
        ports:
        - name: http
          containerPort: 8080
          protocol: TCP

使用演示

在另一个namespaces中创建一个完整应用:webshell-all-in-one.yaml

$ kubectl create -f https://raw.githubusercontent.com/introclass/kubernetes-yamls/master/all-in-one/webshell-all-in-one.yaml
namespace "demo-webshell" created
ingress "webshell-ingress" created
service "webshell" created
deployment "webshell" created

上面的yaml文件,在demo-webshellnamespaces中,创建了deployment、serivce和ingress。

创建成功之后,在kong的dashboard中,可以看到自动创建了为demo-webshell.webshell.80 的Route:

Service                     Methods    Protocols    Hosts          Paths    Priority    
demo-webshell.webshell.80   (none)     http         webshell.com   /        0

和一个同名的service:

Name                        Protocol    Host                         Port    PATH
demo-webshell.webshell.80   http        demo-webshell.webshell.80    80      /

之后可以通过kong-proxy服务访问webshell:

// kong-proxy的采用NodePort方式,端口是32057
kong-proxy                NodePort    10.254.237.61   <none>        80:32057/TCP,443:31552/TCP   52s

访问效果如下,10.10.173.203是kubernetes一个node的IP:

$ curl -v -H "Host: webshell.com" 10.10.173.203:32057
* About to connect() to 10.10.173.203 port 32057 (#0)
*   Trying 10.10.173.203...
* Connected to 10.10.173.203 (10.10.173.203) port 32057 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Accept: */*
> Host: webshell.com
>
< HTTP/1.1 200 OK
< Content-Type: text/html; charset=utf-8
< Content-Length: 382
< Connection: keep-alive
< Date: Mon, 08 Oct 2018 10:59:08 GMT
< X-Kong-Upstream-Latency: 3
< X-Kong-Proxy-Latency: 9
< Via: kong/0.14.1
<
<html>
<head>
<meta content="text/html; charset=utf-8">
<title>WebShell</title>
</head>

<body>

<form method="post" accept-charset="utf-8">
	Command: <input type="text" name="command" width="40%" value="hostname">
	Params : <input type="text" name="params" width="80%" value="">
	<input type="submit" value="submit">
</form>
<pre>

webshell-cc785f4f8-2vp6c

</pre>
</body>
</html>

参考

  1. Kong CE or EE on Kubernetes
  2. Kong/kubernetes-ingress-controller
  3. Nginx、OpenResty和Kong的基本概念与使用方法
  4. Kubernetes Ingress Controller for Kong
  5. Deployment: ingress-controller.yaml
  6. Deployment: Kong
  7. Extend the Kubernetes API with CustomResourceDefinitions
  8. Kong ingress controller: custom types
  9. Kong postgres.yaml
  10. PostgresSQL数据库的基本使用
  11. Kong Custom Resource Definitions
  12. Nginx、OpenResty和Kong的基本概念与使用方法: Kong的插件
  13. PGBI/kong-dashboard
  14. Kubernetes Ingress
  15. Kong: route
  16. Kong: service

站长微信(朋友圈有精华,一般不闲聊)

推荐阅读

Copyright @2011-2019 All rights reserved. 转载请添加原文连接,合作请加微信lijiaocn或者发送邮件: [email protected],备注网站合作

友情链接:  李佶澳的博客  小鸟笔记  软件手册  编程手册  运营手册  爱马影视  网络课程  奇技淫巧  课程文档  精选文章  发现知识星球  百度搜索 谷歌搜索