API網關Kong(二):Kong與Kubernetes集成的方法
作者: 李佶澳 轉載請保留:原文地址 發布時間:2018-09-30 16:07:13 +0800
- 說明
- 先說組成
- 控制平面與數據平面
- CustomResourceDefinitions
- 開始部署
- 使用演示
- 參考
說明
這是API網關Kong的系列教程中的一篇,使用過程中遇到的問題和解決方法記錄在API網關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。
先說組成
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:
CustomResourceDefinitions
Kubernetes支持自定義資源Extend the Kubernetes API with CustomResourceDefinitions,kong-ingress-controller充分利用了這個簡稱為CRD的特性。
Cluster-types.yml中定義了KongPlugin
、KongConsumer
、KongCredential
和KongIngress
四種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是用戶的認證憑證,它的type
與kong支持的認證方式一一對應:
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中創建一個router,為每個被ingress使用的backend在kong中創建一個service。 Ingress是kubernetes定義的(Kubernetes Ingress定義),對於那些與kong相關但是Ingress不支持的配置項,需要在KongIngress
中配置。
下面是一個完成的KongIngress定義,包含upstream
、proxy
和route
三部分:
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-webshell
namespaces中,創建了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>
參考
- Kong CE or EE on Kubernetes
- Kong/kubernetes-ingress-controller
- Nginx、OpenResty和Kong的基本概念與使用方法
- Kubernetes Ingress Controller for Kong
- Deployment: ingress-controller.yaml
- Deployment: Kong
- Extend the Kubernetes API with CustomResourceDefinitions
- Kong ingress controller: custom types
- Kong postgres.yaml
- PostgresSQL數據庫的基本使用
- Kong Custom Resource Definitions
- Nginx、OpenResty和Kong的基本概念與使用方法: Kong的插件
- PGBI/kong-dashboard
- Kubernetes Ingress
- Kong: router
- Kong: service
API網關Kong(二):Kong與Kubernetes集成的方法