Reference
- https://github.com/Kong/kubernetes-ingress-controller/blob/master/docs/design.md
- https://konghq.com/blog/kubernetes-ingress-controller-for-kong/
- https://blog.getambassador.io/kubernetes-ingress-nodeport-load-balancers-and-ingress-controllers-6e29f1c44f2d
之前设想kong和k8s结合使用https://docs.konghq.com/install/kubernetes/?_ga=2.265164879.1330610937.1543828237-1627235705.1540276193 中的Kong via Manifest Files方案,对应仓库https://github.com/Kong/kong-dist-kubernetes,即
- kubectl create -f postgres.yaml
- kubectl create -f kong_migration_postgres.yaml
- kubectl delete -f kong_migration_postgres.yaml
- kubectl create -f kong_postgres.yaml
但是公司大牛调研后推荐Kubernetes Ingress Controller for Kong的方案,那么我们来看下。
本文涉及的技术:
- helm: https://docs.helm.sh/
- kubernetes ingress: https://kubernetes.io/docs/concepts/services-networking/ingress/
- kong: https://docs.konghq.com/
- kong kubernetes ingress: https://github.com/Kong/kubernetes-ingress-controller
实践
helm 安装kong
(helm 是kubernetes的包管理器,这里不再赘述。)
$ helm search kong
$ helm fetch stable/kong
这时已下载kong的charts文件到本地,因为我们只会更改它的values.yml文件,所以拷贝一份出来,目录结构类似:对于kubernetes ingress来说,ingress controller是核心,这里我们配置ingressController的enabled为true。
kong会暴露两组端口至外部,一个是admin api(这里为admin), 另一个是resource api(这里为proxy)。因为我们需要使用oauth插件, kong的oauth endpoint必须为https,所以proxy需要使用https,admin可以改为http方便使用。
# helm启动
$ helm install --name my-kong kong --namespace kong --values values.yaml
# helm更新(较慢,需要等kong ns下的kong-upgrade-migrations执行完毕)
$ helm upgrade my-kong kong -f values.yaml
# 永久删除
$ helm delete my-kong --purge
配置resource 服务
这里给一个简单示例
kind: Service
apiVersion: v1
metadata:
name: python-service
# annotations:
# plugins.konghq.com: rl-by-ip
spec:
# type: NodePort
selector:
app: python
ports:
- protocol: TCP
port: 5000
# targetPort: 80
# nodePort: 31203
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: python-deployment
spec:
replicas: 1
selector:
matchLabels:
app: python
template:
metadata:
labels:
app: python
spec:
containers:
- name: python-controller
image: godbaby/kong-python:1.0
ports:
- containerPort: 5000
#volumeMounts:
# - mountPath: /code/app.py
#name: python-volume
#volumes:
#- name: python-volume
#hostPath:
#path: /Users/goddy/test/kong/docker/resource.py
# readinessProbe:
# httpGet:
# path: /debug/version
# port: 80
# initialDelaySeconds: 5
# periodSeconds: 10
# successThreshold: 5
# resources:
# requests:
# memory: "400Mi"
# cpu: "100m"
# limits:
# memory: "800Mi"
# cpu: "200m"
---
这里注释的为了方便调试和记住这些配置项,可以忽略。
注意这里未使用nodePort的方式暴露端口,而是使用clusterIP的方式,来达到kong作为唯一集群外的访问终端。
配置KongIngress
Ingress是kubernetes已定义好的资源。
KongIngress是helm已经帮我们定义好的kubernetes 自定义资源,作为Ingress的额外配置,而且它必须创建于Ingress上(即metadata一致)。
apiVersion: configuration.konghq.com/v1
kind: KongIngress
metadata:
name: tls-example-ingress
proxy:
path: /
route:
strip_path: true
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: tls-example-ingress
# annotations:
# plugins.konghq.com: rl-by-ip
# plugins.konghq.com: oauth
# ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: test
http:
paths:
- path: /te
backend:
serviceName: python-service
servicePort: 5000
# - path: /2
# backend:
# serviceName: python-service
# servicePort: 5000
# - host: dashboard
# http:
# paths:
# - path: /
# backend:
# serviceName: kong-dashboard
# servicePort: 8080
示例中的strip path就是一种常见的需求。
- 设置成false时(或不设置):资源服务内部分接口生效,Ingress的path类似一个正则过滤器,不符合的则访问不到。
- true时:比如有两个资源服务,同时想占用同一个域名,如 前端使用www.test.com,而后端使用 www.test.com/api(这样前端直接用`location.origin/api`访问即可),此时就需要开启strip_path.
kong dashboard
因为kong-kubernetes ingress的方案提倡声明式的资源,所以GUI其实没啥用。而且目前版本的kong是不可以使用admin api创建数据的。
---
apiVersion: v1
kind: Service
metadata:
name: kong-dashboard
namespace: kong
spec:
# type: NodePort
selector:
app: dashboard
ports:
- port: 8080
protocol: TCP
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: kong-dashboard
namespace: kong
spec:
template:
metadata:
labels:
name: dashboard
app: dashboard
spec:
containers:
- name: kong-dashboard
args:
- start
- --kong-url http://bot-gateway-kong-admin:8444
# - --basic-auth admin=admin
image: pgbi/kong-dashboard:latest
ports:
- containerPort: 8080
对于oauth插件来说,还需要创建以下资源
开启插件
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: oauth
config:
scopes: read,write
mandatory_scope: true
enable_password_grant: true
global_credentials: true
provision_key: frh1REQndMbcEVuO1DV4EpWtR7Wnmfac
plugin: oauth2
config的选项和kong官网的一致,这里不赘述。
多个Ingress可以声明同一个KongPlugin,理论上kong不支持单服务使用同一个插件,这里kubernetes的方案会自动帮我们创建多个一致的插件到不同服务,只是我们看起来它们同时使用一个kong的oauth插件。
创建consumer
apiVersion: configuration.konghq.com/v1
kind: KongConsumer
metadata:
name: team-a
username: goddy
---
apiVersion: configuration.konghq.com/v1
kind: KongCredential
metadata:
name: credential-a
consumerRef: team-a
type: oauth2
config:
name: goddy
client_id: kvcKEfrBn402kZkblQgRwe4j3Fv3A7GH
client_secret: 3ZwsnUIon3VWafhn39kjJ2iSFT75lFJf
redirect_uri: http://www.baidu.com
backend服务
参照https://www.jianshu.com/p/4ddb916d3195方案中的code repo。
还有一些调研的资料,也分享给大家
- [x] 泛域名配置
- 配置
*.dev.ruyi.ai
或其他直接指向kong的内网host和port即可,通过kong反向代理分配域名(配置service、route)
- 配置
- [x] postgreSQL数据保护策略
- 1)数据volume出来,
xxx:/var/lib/postgresql/data
- 2)手动备份出来
- pg_dump -U kong kong > /kong.bak
- docker cp postgresql_postgres_1:/kong.bak /Users/goddy/test/kong/postgresql
- 导入:pg_dump -U kong kong > /kong.bak
- 1)数据volume出来,
- [x] postgreSQL数据库故障后的应对策略
- 1)docker-compose配置healthcheck和restart
healthcheck: test: ["CMD", "pg_isready", "-U", "postgres"] interval: 30s timeout: 30s retries: 3 restart: on-failure
- 2)docker-compose手动重启
- 3)bak文件导入
- 1)docker-compose配置healthcheck和restart
- [x] kong扩展策略
- 复用k8s策略
- [x] 和k8s切合的方案
- [ ] 在生产环境怎么划分scope
- scope的定义: https://www.oauth.com/oauth2-servers/scope/ scope是用于划分用户行为的权限范围。[-对于魔戒建议具体还是根据 账号-角色 以及 角色-权限 来划分-]。
- 谷歌:https://developers.google.com/identity/protocols/googlescopes 先划分产品,然后邮件、事件 等细分功能, 然后读、写、上传等小功能的权限, 如
calendar.events.readonly
,classroom.rosters.readonly
- github: https://developer.github.com/apps/building-oauth-apps/understanding-scopes-for-oauth-apps/ 角色+功能,如
user:email
,admin:gpg_key
或者 权限+功能 ,如read:public_key
,write:repo_hook
- slack: https://api.slack.com/docs/oauth-scopes 功能+读写权限+角色,如
files:write:user
,users.profile:write:user
- [ ] consumer和user对应关系,找一些例子
- 两种实施方案:
- consumer与实际用户一一对应
- 创建:1.通过auth项目验证用户是否存在 2.通过auth项目创建用户: 1)填充uid、scope等信息,创建用户 2)创建用户及其uid对应的consumer至kong 3)添加oauth凭证至consumer
- 访问:1.auth项目验证用户名密码是否相符 2.通过uid获取到consumer的oauth凭证的client_id和client_secret 3.访问kong获取token
- 示例项目:https://gist.github.com/ernsheong/b4deb7ce391d43dad6a63272b94b8e2e
- 优点:kong的consumer是区分用户的最小级别,如果使用kong的log等插件,比较契合。
- 风险:kong依赖的postgresql需要存储一份用户数据信息,和auth依赖的数据库用户一一对应,每次访问需要请求kong获取一次client信息,[-对于kong kubernetes ingress(声明式)无法实现-]
- consumer与client对应,即一组用户共用一个client
- 创建:通过auth项目填充uid、scope等信息,创建用户
- 登录:auth项目验证用户名密码是否相符,使用公用的client信息,访问kong获取token
- 优点:简单
- 风险:用户使用kong的其他登录方式很难做到,
- consumer与实际用户一一对应
- 两种实施方案:
- [ ] oauth/token地址固定一个
- oauth插件是基于service或这service下的route的,所以endpoint会在服务的host生成,如
hbrainlab.ruyi.ai/oauth2/token
, 如果想固定一个地址的话,需要有一个获取token的服务,这个服务要求地址固定,而且生成的token对于其他服务都有效,那么[-其他服务对应的oauth plugin的global creditials需要设置为true-]
- oauth插件是基于service或这service下的route的,所以endpoint会在服务的host生成,如
资料:
- kubernetes中ingress的概念:https://kubernetes.io/docs/concepts/services-networking/ingress/
- kubernetes-ingress-controller的仓库:https://github.com/Kong/kubernetes-ingress-controller