微服務API網關-Kong初探
- 2019 年 10 月 8 日
- 筆記
一 概述
Kong是一個clould-native、快速的、可擴展的、分佈式的微服務抽象層(也稱為API網關、API中間件或在某些情況下稱為服務網格)框架。更確切地說,Kong是一個在Nginx中運行的Lua應用程序,並且可以通過lua-nginx模塊實現。Kong不是用這個模塊編譯Nginx,而是與OpenResty一起發佈,OpenResty已經包含了lua-nginx-module。OpenResty 不是 Nginx的分支,而是一組擴展其功能的模塊。
這為可插拔架構奠定了基礎,可以在運行時啟用和執行Lua腳本(稱為「插件」)。因此,我們認為Kong是微服務架構的典範:它的核心是實現數據庫抽象,路由和插件管理。插件可以存在於單獨的代碼庫中,並且可以在幾行代碼中注入到請求生命周期的任何位置。Kong作為開源項目在2015年推出,它的核心價值是高性能和可擴展性。
Kong被廣泛用於從初創企業到全球5000家公司以及政府組織的生產環境中。
如果構建Web、移動或IoT(物聯網)應用,可能最終需要使用通用的功能來實現這些應用。Kong充當微服務請求的網關(或側車),通過插件能夠提供負載平衡、日誌記錄、身份驗證、速率限制、轉換等能力。
一個service可以創建多個routes,routes就相當於前端配置,可以隱藏業務真正的接口地址,service指定後端真實的轉發接口地址,在kong上進行認證/鑒權/日誌/分析/監控等控制。
二 特性
- 雲原生(Cloud-Native):Kong可以在Kubernetes或物理環境上運行;
- 動態負載平衡(Dynamic Load Balancing):跨多個上游服務的負載平衡業務。
- 基於哈希的負載平衡(Hash-based Load Balancing):一致的散列/粘性會話的負載平衡。
- 斷路器(Circuit-Breaker):智能跟蹤不健康的上游服務。
- 健康檢查(Health Checks):主動和被動監控您的上游服務。
- 服務發現(Service Discovery):解決如Consul等第三方DNS解析器的SRV記錄。
- 無服務器(Serverless):從Kong中直接調用和保證AWS或OpenWhisk函數安全。
- WebSockets:通過WebSockets與上游服務進行通信。
- OAuth2.0:輕鬆的向API中添加OAuth2.0認證。
- 日誌記錄(Logging):通過HTTP、TCP、UDP記錄請求或者相應的日誌,存儲在磁盤中。
- 安全(Security):ACL,Bot檢測,IPs白名單/黑名單等。
- 系統日誌(Syslog):記錄信息到系統日誌。
- SSL:為基礎服務或API設置特定的SSL證書。
- 監視(Monitoring):能夠實時對關鍵負載和性能指標進行監控。
- 轉發代理(Forward Proxy):使端口連接到中間透明的HTTP代理。
- 認證(Authentications):支持HMAC,JWT和BASIC方式進行認證等等。
- 速率限制(Rate-limiting):基於多個變量的阻塞和節流請求。
- 轉換(Transformations):添加、刪除或操作HTTP請求和響應。
- 緩存(Caching):在代理層進行緩存和服務響應。
- 命令行工具(CLI):能夠通過命令行控制Kong的集群。
- REST API:可以通過REST API靈活的操作Kong。
- GEO複製:在不同的區域,配置總是最新的。
- 故障檢測與恢復(Failure Detection & Recovery):如果Cassandra節點失效,Kong並不會受影響。
- 群集(Clustering):所有的Kong節點會自動加入群集,並更新各個節點上的配置。
- 可擴展性(Scalability):通過添加節點,實現水平縮放。
- 性能(Performance):通過縮放和使用Nigix,Kong能夠輕鬆處理負載。
- 插件(Plugins):基於插件的可擴展體系結構,能夠方便的向Kong和API添加功能。
三 依賴組件
Kong部署在Nginx和Apache Cassandra或PostgreSQL等可靠技術之上,並提供了易於使用的RESTful API來操作和配置系統。下面是Kong的技術邏輯圖。基於這些技術,Kong提供相關的特性支持:
3.1 Nginx
- 經過驗證的高性能基礎;
- HTTP和反向代理服務器;
- 處理低層級的操作。
3.2 OpenRestry
- 支持Lua腳本;
- 攔截請求/響應生命周期;
- 基於Nginx進行擴展。
3.3 Clustering&Datastore
- 支持Cassandra或PostgreSQL數據庫;
- 內存級的緩存;
- 支持水平擴展。
3.4 Plugins
- 使用Lua創建插件;
- 功能強大的定製能力;
- 與第三方服務實現集成。
3.5 Restful Administration API
- 通過Restful API管理Kong;
- 支持CI/CD&DevOps;
- 基於插件的可擴展。
四 架構圖

五 部署
5.1 物理服務器部署
5.1.1 配置yum源
sudo yum update -y sudo yum install -y wget wget https://bintray.com/kong/kong-rpm/rpm -O bintray-kong-kong-rpm.repo export major_version=`grep -oE '[0-9]+.[0-9]+' /etc/redhat-release | cut -d "." -f1` sed -i -e 's/baseurl.*/&/centos/'$major_version''/ bintray-kong-kong-rpm.repo sudo mv bintray-kong-kong-rpm.repo /etc/yum.repos.d/ sudo yum update -y sudo yum install -y kong
5.1.2 數據庫安裝
Kong支持PostgreSQL v9.5+和Cassandra 3.x.x作為數據存儲。
按照文檔安裝PostgreSQL v11: https://www.postgresql.org/download/linux/redhat/
# 安裝PostgreSQL v11 yum install -y https://download.postgresql.org/pub/repos/yum/11/redhat/rhel-7-x86_64/pgdg-centos11-11-2.noarch.rpm yum install -y postgresql11 postgresql11-server # 自啟 /usr/pgsql-11/bin/postgresql-11-setup initdb systemctl enable postgresql-11 systemctl start postgresql-11
# 登錄psql sudo su postgres psql # 創建數據庫,官方默認無密碼,此處我使用密碼 # CREATE USER kong; CREATE DATABASE kong OWNER kong; CREATE USER kong with password 'kong'; CREATE DATABASE kong OWNER kong; grant all privileges on database kong to kong; # 這裡可能會報連接錯誤 # psql: 致命錯誤: 對用戶"kong"的對等認證失敗 sudo find / -name pg_hba.conf /var/lib/pgsql/11/data/pg_hba.conf # 修改安全配置 vim /var/lib/pgsql/11/data/pg_hba.conf # METHOD指定如何處理客戶端的認證。常用的有ident,md5,password,trust,reject # ident是Linux下PostgreSQL默認的local認證方式,凡是能正確登錄服務器的操作系統用戶(註:不是數據庫用戶)就能使用本用戶映射的數據庫用戶不需密碼登錄數據庫。 # md5是常用的密碼認證方式,如果你不使用ident,最好使用md5。密碼是以md5形式傳送給數據庫,較安全,且不需建立同名的操作系統用戶。 # password是以明文密碼傳送給數據庫,建議不要在生產環境中使用。 # trust是只要知道數據庫用戶名就不需要密碼或ident就能登錄,建議不要在生產環境中使用。 # reject是拒絕認證。 # "local" is for Unix domain socket connections only local all all md5 # IPv4 local connections: host all all 127.0.0.1/32 md5 # IPv6 local connections: host all all ::1/128 md5 # 將peer改為md5() # "local" is for Unix domain socket connections only local all all md5 # IPv4 local connections: host all all 127.0.0.1/32 ident # IPv6 local connections: host all all ::1/128 ident # 重啟psql systemctl restart postgresql-11 # 登錄postgre psql -U kong # 輸入密碼 # 查看幫助 h # 退出 q
# 這裡需要提前配置kong配置文件,默認/etc/kong/kong.conf.default cp /etc/kong/kong.conf.default /etc/kong/kong.conf # 修改裏面的數據庫配置,寫入用戶、密碼、數據庫、端口等信息 vim /etc/kong/kong.conf [root@kong-server software]# egrep -v "^#|^$|^[[:space:]]+#" /etc/kong/kong.conf database = postgres # Determines which of PostgreSQL or Cassandra pg_host = 127.0.0.1 # Host of the Postgres server. pg_port = 5432 # Port of the Postgres server. pg_timeout = 5000 # Defines the timeout (in ms), for connecting, pg_user = kong # Postgres user. pg_password = kong # Postgres user's password. pg_database = kong # The database name to connect to. # Kong migrations kong migrations bootstrap [-c /path/to/kong.conf] [root@kong-server software]# kong migrations bootstrap -c /etc/kong/kong.conf Bootstrapping database... migrating core on database 'kong'... core migrated up to: 000_base (executed) core migrated up to: 001_14_to_15 (executed) core migrated up to: 002_15_to_1 (executed) core migrated up to: 003_100_to_110 (executed) core migrated up to: 004_110_to_120 (executed) core migrated up to: 005_120_to_130 (executed) migrating hmac-auth on database 'kong'... hmac-auth migrated up to: 000_base_hmac_auth (executed) hmac-auth migrated up to: 001_14_to_15 (executed) migrating oauth2 on database 'kong'... oauth2 migrated up to: 000_base_oauth2 (executed) oauth2 migrated up to: 001_14_to_15 (executed) oauth2 migrated up to: 002_15_to_10 (executed) migrating jwt on database 'kong'... jwt migrated up to: 000_base_jwt (executed) jwt migrated up to: 001_14_to_15 (executed) migrating basic-auth on database 'kong'... basic-auth migrated up to: 000_base_basic_auth (executed) basic-auth migrated up to: 001_14_to_15 (executed) migrating key-auth on database 'kong'... key-auth migrated up to: 000_base_key_auth (executed) key-auth migrated up to: 001_14_to_15 (executed) migrating rate-limiting on database 'kong'... rate-limiting migrated up to: 000_base_rate_limiting (executed) rate-limiting migrated up to: 001_14_to_15 (executed) rate-limiting migrated up to: 002_15_to_10 (executed) rate-limiting migrated up to: 003_10_to_112 (executed) migrating acl on database 'kong'... acl migrated up to: 000_base_acl (executed) acl migrated up to: 001_14_to_15 (executed) migrating response-ratelimiting on database 'kong'... response-ratelimiting migrated up to: 000_base_response_rate_limiting (executed) response-ratelimiting migrated up to: 001_14_to_15 (executed) response-ratelimiting migrated up to: 002_15_to_10 (executed) migrating session on database 'kong'... session migrated up to: 000_base_session (executed) 27 migrations processed 27 executed Database is up-to-date
5.1.2 啟動kong
在無數據庫模式配置Kong,一旦Kong啟動,訪問Admin API的/
根端點已驗證它是否在沒有數據庫的情況下運行。
# Setting Up Kong in DB-less mode 要在無數據庫模式下使用Kong,有兩種方式: 修改配置文件kong.conf vim /etc/kong/kong.conf # database = postgres database=off # 或 export KONG_DATABASE=off # 檢查配置,此命令將考慮您當前設置的環境變量,並在設置無效時報錯。此外,您還可以在調試模式下使用CLI,以便更深入地了解Kong的啟動屬性 kong start -c <kong.conf> --vv # 啟動kong kong start -c /etc/kong/kong.conf
kong start [-c /path/to/kong.conf] [root@kong-server software]# kong start -c /etc/kong/kong.conf Kong started [root@kong-server software]# kong health nginx.......running Kong is healthy at /usr/local/kong [root@kong-server software]# netstat -lntup Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 127.0.0.1:8444 0.0.0.0:* LISTEN 31050/nginx: master tcp 0 0 0.0.0.0:8000 0.0.0.0:* LISTEN 31050/nginx: master tcp 0 0 127.0.0.1:8001 0.0.0.0:* LISTEN 31050/nginx: master tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1453/sshd tcp 0 0 127.0.0.1:5432 0.0.0.0:* LISTEN 30638/postmaster tcp 0 0 0.0.0.0:8443 0.0.0.0:* LISTEN 31050/nginx: master tcp6 0 0 ::1:5432 :::* LISTEN 30638/postmaster udp 0 0 0.0.0.0:68 0.0.0.0:* 780/dhclient udp 0 0 172.16.16.16:123 0.0.0.0:* 3006/ntpd udp 0 0 127.0.0.1:123 0.0.0.0:* 3006/ntpd udp6 0 0 fe80::5054:ff:fe94::123 :::* 3006/ntpd udp6 0 0 ::1:123 :::* 3006/ntpd [root@kong-server software]# curl http://localhost:8001 停止: kong stop 重新加載: kong reload
5.1.3 安裝konga
konga為目前最先版本的kong的dashboard,由於kong-dashboard目前為更新適應新版本的kong,推薦使用konga
konga帶來的一個最大的便利就是可以很好地通過UI觀察到現在kong的所有的配置,並且可以對於管理kong節點情況進行查看、監控和預警,konga主要特性如下:
- 多用戶管理
- 管理多個Kong節點
- 電子郵件異常信息通知
- 管理所有Kong Admin API
- 使用快照備份,還原和遷移Kong節點
- 使用運行狀況檢查監控節點和API狀態
- 輕鬆的數據庫集成(MySQL,postgresSQL,MongoDB)
- node安裝
yum -y install git cd /data/software && wget https://npm.taobao.org/mirrors/node/v10.16.2/node-v10.16.2-linux-x64.tar.xz tar -xf node-v10.16.2-linux-x64.tar.xz mv node-v10.16.2-linux-x64 node # 修改為root的權限 chown root.root node -R cat > /etc/profile.d/node.sh << EOF export PATH=$PATH:/data/software/node/bin EOF source /etc/profile.d/node.sh node -v # 安裝插件 npm install -g glup npm install -g bower npm install -g sails npm install -g node-gyp npm install -g grunt-sass npm install -g node-sass npm run bower-deps npm install sails-postgresql
- 安裝konga
git clone https://github.com/pantsel/konga.git cd konga npm install konga #使用postgresql CREATE USER konga with password 'konga'; CREATE DATABASE konga OWNER konga; grant all privileges on database konga to konga;
- 配置
cp config/local_example.js config/local.js # 配置默認數據庫 vi ./local.js models: { connection: process.env.DB_ADAPTER || 'localDiskDb', }, # 改成 models: { connection: process.env.DB_ADAPTER || 'postgres', // 這裡可以用『mysql』,『mongo』,『sqlserver』,『postgres』 }, # 保存 # 修改數據庫默認配置 vi connections.js postgres: { adapter: 'sails-postgresql', url: process.env.DB_URI, host: process.env.DB_HOST || 'localhost', user: process.env.DB_USER || 'konga', password: process.env.DB_PASSWORD || 'konga', port: process.env.DB_PORT || 5432, database: process.env.DB_DATABASE ||'konga', // schema: process.env.DB_PG_SCHEMA ||'public', poolSize: process.env.DB_POOLSIZE || 10, ssl: process.env.DB_SSL ? true : false // If set, assume it's true }, # 保存 # 啟動 cd ../ npm start # pm2 管理 npm install -g pm2 cd konga pm2 start app.js --name konga pm2 logs 0|konga | info: Sails <| .-..-. 0|konga | info: v0.12.14 | 0|konga | info: /|. 0|konga | info: / || 0|konga | info: ,' |' 0|konga | info: .-'.-==|/_--' 0|konga | info: `--'-------' 0|konga | info: __---___--___---___--___---___--___ 0|konga | info: ____---___--___---___--___---___--___-__ 0|konga | info: 0|konga | info: Server lifted in `/data/software/konga` 0|konga | info: To see your app, visit http://localhost:1338 0|konga | info: To shut down Sails, press <CTRL> + C at any time. 0|konga | 0|konga |
- 訪問
IP:1338,默認用戶:admin,密碼:adminadminadmin
配置鏈接kong, http://localhost:8001


5.2 docker中運行
5.2.1 Docker中部署
1.您需要創建一個自定義網絡,以允許容器相互發現和通信。在此示例中kong-net是網絡名稱,您可以使用任何名稱。 docker network create kong-net 2.啟動數據庫PostgreSQL docker run -d --name kong-database --network=kong-net -p 5432:5432 -e "POSTGRES_USER=kong" -e "POSTGRES_DB=kong" -e "POSTGRES_PASSWORD=kong" postgres 3.準備數據庫 docker run --rm --network=kong-net -e "KONG_DATABASE=postgres" -e "KONG_PG_HOST=kong-database" -e "KONG_CASSANDRA_CONTACT_POINTS=kong-database" -e "KONG_PG_PASSWORD=kong" kong kong migrations bootstrap 4.啟動kong docker run -d --name kong --network=kong-net -e "KONG_DATABASE=postgres" -e "KONG_PG_HOST=kong-database" -e "KONG_PG_PASSWORD=kong" -e "KONG_CASSANDRA_CONTACT_POINTS=kong-database" -e "KONG_PROXY_ACCESS_LOG=/dev/stdout" -e "KONG_ADMIN_ACCESS_LOG=/dev/stdout" -e "KONG_PROXY_ERROR_LOG=/dev/stderr" -e "KONG_ADMIN_ERROR_LOG=/dev/stderr" -e "KONG_ADMIN_LISTEN=0.0.0.0:8001, 0.0.0.0:8444 ssl" -p 8000:8000 -p 8443:8443 -p 8001:8001 -p 8444:8444 kong 5.運行konga 注意DB_HOST為自己的ip地址 docker run -d -p 1337:1337 --network kong-net -e "TOKEN_SECRET=mark666" -e "DB_ADAPTER=postgres" -e "DB_HOST=10.234.2.204" -e "DB_PORT=5432:5432" -e "DB_USER=kong" -e "DB_PASSWORD=kong" -e "DB_DATABASE=kong_database" --name konga pantsel/konga
5.2.2 docker-compose部署
- 創建虛擬網絡
docker network create kong-net
後續的應用及數據庫都使用這個虛擬網絡。
- 編寫docker-compose.yaml
version: "3.7" services: kong: # 鏡像版本,目前最新 image: kong:1.1.2 environment: # 數據持久化方式,使用postgres數據庫 - "KONG_DATABASE=postgres" # 數據庫容器名稱,Kong連接數據時使用些名稱 - "KONG_PG_HOST=kong-database" # 數據庫名稱 - "KONG_CASSANDRA_CONTACT_POINTS=kong-database" # 日誌記錄目錄 - "KONG_PROXY_ACCESS_LOG=/dev/stdout" - "KONG_ADMIN_ACCESS_LOG=/dev/stdout" - "KONG_PROXY_ERROR_LOG=/dev/stderr" - "KONG_ADMIN_ERROR_LOG=/dev/stderr" # 暴露的端口 - "KONG_ADMIN_LISTEN=0.0.0.0:8001, 0.0.0.0:8444 ssl" ports: - 8000:8000 - 8443:8443 - 8001:8001 - 8444:8444 # 使用docker網絡 networks: - kong-net # 依賴數據庫服務 depends_on: - kong-database # kong 管理界面 konga: image: pantsel/konga environment: - "TOKEN_SECRET=51liveup.cn" - "NODE_ENV=production" ports: - 8080:1337 networks: - kong-net depends_on: - kong-database - # 數據庫服務 kong-database: image: postgres:9.6 ports: - "5432:5432" environment: # 訪問數據庫的用戶 - POSTGRES_USER=kong - POSTGRES_DB=kong networks: - kong-net volumes: # 同步時間 - /etc/localtime:/etc/localtime:ro # 數據庫持久化目錄 - /data/data/postgresql:/var/lib/postgresql/data networks: kong-net: external: true
使用docker-compose up 命令啟動服務。會發現啟動時報數據庫錯誤,這是因為kong 使用的postgres 數據還需要進行初始化才能使用。
- 初始化數據庫
docker run --rm --network=kong-net -e "KONG_DATABASE=postgres" -e "KONG_PG_HOST=kong-database" -e "KONG_CASSANDRA_CONTACT_POINTS=kong-database" kong:latest kong migrations bootstrap
一定要在創建數據庫容器之後,並且保持數據庫的Docker容器在運行狀態,再執行初始化數據庫,數據庫初始化成功後,再次使用docker-compose up -d 啟動服務就可以了。
- 驗證
curl -i http://localhost:8001/
- dashboard
另外,也可以安裝一個Kong的客戶端來驗證。在安裝有Docker引擎的操作系統上執行如下的命令:
1.0之後的kong-dashboard就已經不兼容了,建議使用konga
5.2.3 安裝kong-dashboard
- Kong Dashboard 3.3.0 is only partially compatible with Kong 0.13. It does not support the new Service and Route objects introduced in Kong 0.13.
# 下載鏡像pgbi/kong-dashboard [root@master data]# docker run --rm -p 8080:8080 pgbi/kong-dashboard start --kong-url http://10.234.2.204:30493 --basic-auth [email protected] Connecting to Kong on http://10.234.2.204:30493 ... What's on http://10.234.2.204:30493 isn't Kong [root@master data]# kubectl get svc |grep kong kong-kong-admin NodePort 10.104.75.151 <none> 8444:30493/TCP 52m kong-kong-proxy NodePort 10.99.141.23 <none> 80:30877/TCP,443:31201/TCP 52m kong-postgresql ClusterIP 10.109.249.105 <none> 5432/TCP 52m kong-postgresql-headless ClusterIP None <none> 5432/TCP 52m
通過docker安裝一個Kong-Dashboard,安裝完成後,通過瀏覽器訪問:
5.3 kubernetes部署
5.3.1 前置條件
- 已有Kubernetes 1.6+環境;
- 已部署helm客戶端和tiller服務端(請參考:https://docs.helm.sh/using_helm/#installing-helm)
- 在Kubernetes中創建了具備足夠權限訪問權限的service account;
- 並通過此service account在Kubernetes部署了tiller服務端(請參考:https://docs.helm.sh/using_helm/#role-based-access-control)。
5.3.2 helm char配置
下表列示了Kong chart的配置參數和默認值:
參數 |
說明 |
默認值 |
---|---|---|
image.repository |
Kong image |
|
image.tag |
Kong image version |
|
image.pullPolicy |
Image pull policy |
|
image.pullSecrets |
Image pull secrets |
|
replicaCount |
Kong instance count |
|
admin.useTLS |
Secure Admin traffic |
|
admin.servicePort |
TCP port on which the Kong admin service is exposed |
|
admin.containerPort |
TCP port on which Kong app listens for admin traffic |
|
admin.nodePort |
Node port when service type is |
|
admin.type |
k8s service type, Options: NodePort, ClusterIP, LoadBalancer |
|
admin.loadBalancerIP |
Will reuse an existing ingress static IP for the admin service |
|
admin.loadBalancerSourceRanges |
Limit admin access to CIDRs if set and service type is |
|
admin.ingress.enabled |
Enable ingress resource creation (works with proxy.type=ClusterIP) |
|
admin.ingress.tls |
Name of secret resource, containing TLS secret |
|
admin.ingress.hosts |
List of ingress hosts. |
|
admin.ingress.path |
Ingress path. |
|
admin.ingress.annotations |
Ingress annotations. See documentation for your ingress controller for details |
|
proxy.useTLS |
Secure Proxy traffic |
|
proxy.servicePort |
TCP port on which the Kong Proxy Service is exposed |
|
proxy.containerPort |
TCP port on which the Kong app listens for Proxy traffic |
|
proxy.nodePort |
Node port when service type is |
|
proxy.type |
k8s service type. Options: NodePort, ClusterIP, LoadBalancer |
|
proxy.loadBalancerSourceRanges |
Limit proxy access to CIDRs if set and service type is |
|
proxy.loadBalancerIP |
To reuse an existing ingress static IP for the admin service |
|
proxy.ingress.enabled |
Enable ingress resource creation (works with proxy.type=ClusterIP) |
|
proxy.ingress.tls |
Name of secret resource, containing TLS secret |
|
proxy.ingress.hosts |
List of ingress hosts. |
|
proxy.ingress.path |
Ingress path. |
|
proxy.ingress.annotations |
Ingress annotations. See documentation for your ingress controller for details |
|
env |
Additional Kong configurations |
|
runMigrations |
Run Kong migrations job |
|
readinessProbe |
Kong readiness probe |
|
livenessProbe |
Kong liveness probe |
|
affinity |
Node/pod affinities |
|
nodeSelector |
Node labels for pod assignment |
|
podAnnotations |
Annotations to add to each pod |
|
resources |
Pod resource requests & limits |
|
tolerations |
List of node taints to tolerate |
|
5.3.3 安裝chart
啟用數據庫需要先安裝pvc
--- kind: PersistentVolumeClaim apiVersion: v1 metadata: name: data-kong-postgresql-0 spec: storageClassName: ceph-rdb accessModes: - ReadWriteOnce resources: requests: storage: 4Gi # 部署pvc [root@master data]# kubectl get pvc |grep api-gateway data-api-gateway-postgresql-0 Bound pvc-d280166c-c03d-11e9-a45a-facf8ddba000 8Gi RWO ceph-rdb 11s
helm fetch stable/kong --version 0.13.0 [root@master kong-deploy]# helm install -n api-gateway kong/ NAME: api-gateway LAST DEPLOYED: Fri Aug 16 23:53:37 2019 NAMESPACE: default STATUS: DEPLOYED RESOURCES: ==> v1/Job NAME COMPLETIONS DURATION AGE api-gateway-kong-init-migrations 0/1 0s 0s ==> v1/Pod(related) NAME READY STATUS RESTARTS AGE api-gateway-kong-79f697ff7c-bcr7m 0/1 Init:0/1 0 0s api-gateway-kong-init-migrations-hxgd6 0/1 Init:0/1 0 0s api-gateway-postgresql-0 0/1 Init:0/1 0 0s ==> v1/Secret NAME TYPE DATA AGE api-gateway-postgresql Opaque 1 0s ==> v1/Service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE api-gateway-kong-admin NodePort 10.100.226.67 <none> 8444:31466/TCP 0s api-gateway-kong-proxy NodePort 10.109.4.127 <none> 80:32287/TCP,443:32742/TCP 0s api-gateway-postgresql ClusterIP 10.102.197.253 <none> 5432/TCP 0s api-gateway-postgresql-headless ClusterIP None <none> 5432/TCP 0s ==> v1beta2/Deployment NAME READY UP-TO-DATE AVAILABLE AGE api-gateway-kong 0/1 1 0 0s ==> v1beta2/StatefulSet NAME READY AGE api-gateway-postgresql 0/1 0s NOTES: 1. Kong Admin can be accessed inside the cluster using: DNS=api-gateway-kong-admin.default.svc.cluster.local PORT=8444 To connect from outside the K8s cluster: HOST=$(kubectl get nodes --namespace default -o jsonpath='{.items[0].status.addresses[0].address}') PORT=$(kubectl get svc --namespace default api-gateway-kong-admin -o jsonpath='{.spec.ports[0].nodePort}') 2. Kong Proxy can be accessed inside the cluster using: DNS=api-gateway-kong-proxy.default.svc.cluster.localPORT=443To connect from outside the K8s cluster: HOST=$(kubectl get nodes --namespace default -o jsonpath='{.items[0].status.addresses[0].address}') PORT=$(kubectl get svc --namespace default api-gateway-kong-proxy -o jsonpath='{.spec.ports[0].nodePort}')
5.3.4 驗證Kong(命令行)
通過執行下面的命令,進入Kong的容器:
[root@master kong-deploy]# kubectl exec -it api-gateway-kong-79f697ff7c-bcr7m /bin/sh / # netstat -lntup Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:8443 0.0.0.0:* LISTEN - tcp 0 0 0.0.0.0:8444 0.0.0.0:* LISTEN - tcp 0 0 0.0.0.0:8000 0.0.0.0:* LISTEN - / # curl -k https://localhost:8444
並在kong中執行如下的命令:
curl -k http://localhost:8444
如果kong正常運行的話,應該會返回一些內容。
[root@master ~]# kubectl get all |grep api-gateway pod/api-gateway-kong-8cf4ddcbf-qb87c 1/1 Running 0 15h pod/api-gateway-kong-init-migrations-fsfqb 0/1 Completed 0 15h pod/api-gateway-postgresql-0 1/1 Running 0 15h service/api-gateway-kong-admin NodePort 10.103.90.21 <none> 8444:30840/TCP 15h service/api-gateway-kong-proxy NodePort 10.96.32.21 <none> 80:32582/TCP,443:31941/TCP 15h service/api-gateway-postgresql ClusterIP 10.109.28.2 <none> 5432/TCP 15h service/api-gateway-postgresql-headless ClusterIP None <none> 5432/TCP 15h deployment.apps/api-gateway-kong 1/1 1 1 15h replicaset.apps/api-gateway-kong-8cf4ddcbf 1 1 1 15h statefulset.apps/api-gateway-postgresql 1/1 15h job.batch/api-gateway-kong-init-migrations 1/1 51s 15h
通過瀏覽器查看

{ "plugins": { "enabled_in_cluster": [], "available_on_server": { "correlation-id": true, "pre-function": true, "cors": true, "ldap-auth": true, "loggly": true, "hmac-auth": true, "zipkin": true, "request-size-limiting": true, "azure-functions": true, "request-transformer": true, "oauth2": true, "response-transformer": true, "ip-restriction": true, "statsd": true, "jwt": true, "proxy-cache": true, "basic-auth": true, "key-auth": true, "http-log": true, "datadog": true, "tcp-log": true, "post-function": true, "prometheus": true, "acl": true, "kubernetes-sidecar-injector": true, "syslog": true, "file-log": true, "udp-log": true, "response-ratelimiting": true, "aws-lambda": true, "bot-detection": true, "rate-limiting": true, "request-termination": true } }, "tagline": "Welcome to kong", "configuration": { "error_default_type": "text/plain", "admin_listen": [ "0.0.0.0:8444 ssl" ], "proxy_access_log": "/dev/stdout", "trusted_ips": {}, "prefix": "/usr/local/kong", "loaded_plugins": { "correlation-id": true, "pre-function": true, "cors": true, "rate-limiting": true, "loggly": true, "hmac-auth": true, "zipkin": true, "bot-detection": true, "azure-functions": true, "request-transformer": true, "oauth2": true, "response-transformer": true, "syslog": true, "statsd": true, "jwt": true, "proxy-cache": true, "basic-auth": true, "key-auth": true, "http-log": true, "datadog": true, "tcp-log": true, "post-function": true, "ldap-auth": true, "acl": true, "kubernetes-sidecar-injector": true, "ip-restriction": true, "file-log": true, "udp-log": true, "response-ratelimiting": true, "aws-lambda": true, "prometheus": true, "request-size-limiting": true, "request-termination": true }, "cassandra_username": "kong", "ssl_cert_key": "/usr/local/kong/ssl/kong-default.key", "admin_ssl_cert_key": "/usr/local/kong/ssl/admin-kong-default.key", "dns_resolver": {}, "pg_user": "kong", "pg_password": "******", "cassandra_data_centers": [ "dc1:2", "dc2:3" ], "nginx_admin_directives": {}, "nginx_http_directives": [ { "value": "prometheus_metrics 5m", "name": "lua_shared_dict" } ], "pg_host": "api-gateway-postgresql", "nginx_acc_logs": "/usr/local/kong/logs/access.log", "pg_semaphore_timeout": 60000, "proxy_listen": [ "0.0.0.0:8000", "0.0.0.0:8443 ssl" ], "client_ssl_cert_default": "/usr/local/kong/ssl/kong-default.crt", "cassandra_ssl": false, "db_update_frequency": 5, "db_update_propagation": 0, "stream_listen": [ "off" ], "nginx_err_logs": "/usr/local/kong/logs/error.log", "cassandra_port": 9042, "dns_order": [ "LAST", "SRV", "A", "CNAME" ], "dns_error_ttl": 1, "headers": [ "server_tokens", "latency_tokens" ], "cassandra_lb_policy": "RequestRoundRobin", "nginx_optimizations": true, "pg_timeout": 5000, "database": "postgres", "pg_database": "kong", "nginx_worker_processes": "auto", "lua_package_cpath": "", "admin_ssl_cert": "/usr/local/kong/ssl/admin-kong-default.crt", "admin_acc_logs": "/usr/local/kong/logs/admin_access.log", "real_ip_header": "X-Real-IP", "ssl_cert_key_default": "/usr/local/kong/ssl/kong-default.key", "lua_package_path": "./?.lua;./?/init.lua;", "nginx_pid": "/usr/local/kong/pids/nginx.pid", "upstream_keepalive": 60, "nginx_conf": "/usr/local/kong/nginx.conf", "router_consistency": "strict", "dns_no_sync": false, "origins": {}, "admin_access_log": "/dev/stdout", "admin_ssl_cert_default": "/usr/local/kong/ssl/admin-kong-default.crt", "client_ssl": false, "proxy_listeners": [ { "transparent": false, "ssl": false, "ip": "0.0.0.0", "proxy_protocol": false, "port": 8000, "http2": false, "listener": "0.0.0.0:8000" }, { "transparent": false, "ssl": true, "ip": "0.0.0.0", "proxy_protocol": false, "port": 8443, "http2": false, "listener": "0.0.0.0:8443 ssl" } ], "proxy_ssl_enabled": true, "stream_listeners": {}, "db_cache_warmup_entities": [ "services", "plugins" ], "enabled_headers": { "latency_tokens": true, "X-Kong-Proxy-Latency": true, "Via": true, "server_tokens": true, "Server": true, "X-Kong-Upstream-Latency": true, "X-Kong-Upstream-Status": false }, "plugins": [ "bundled" ], "ssl_ciphers": "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256", "db_resurrect_ttl": 30, "nginx_proxy_directives": {}, "cassandra_consistency": "ONE", "client_max_body_size": "0", "admin_error_log": "/dev/stderr", "pg_ssl_verify": false, "dns_not_found_ttl": 30, "pg_ssl": false, "lua_ssl_verify_depth": 1, "ssl_cipher_suite": "modern", "cassandra_repl_strategy": "SimpleStrategy", "proxy_error_log": "/dev/stderr", "kong_env": "/usr/local/kong/.kong_env", "db_cache_ttl": 0, "pg_max_concurrent_queries": 0, "nginx_kong_conf": "/usr/local/kong/nginx-kong.conf", "cassandra_schema_consensus_timeout": 10000, "dns_hostsfile": "/etc/hosts", "admin_listeners": [ { "transparent": false, "ssl": true, "ip": "0.0.0.0", "proxy_protocol": false, "port": 8444, "http2": false, "listener": "0.0.0.0:8444 ssl" } ], "dns_stale_ttl": 4, "ssl_cert": "/usr/local/kong/ssl/kong-default.crt", "cassandra_timeout": 5000, "admin_ssl_cert_key_default": "/usr/local/kong/ssl/admin-kong-default.key", "cassandra_ssl_verify": false, "mem_cache_size": "128m", "log_level": "notice", "real_ip_recursive": "off", "cassandra_repl_factor": 1, "client_ssl_cert_key_default": "/usr/local/kong/ssl/kong-default.key", "nginx_daemon": "off", "anonymous_reports": true, "nginx_sproxy_directives": {}, "nginx_stream_directives": {}, "pg_port": 5432, "nginx_kong_stream_conf": "/usr/local/kong/nginx-kong-stream.conf", "client_body_buffer_size": "8k", "ssl_preread_enabled": true, "ssl_cert_csr_default": "/usr/local/kong/ssl/kong-default.csr", "cassandra_contact_points": [ "127.0.0.1" ], "cassandra_keyspace": "kong", "ssl_cert_default": "/usr/local/kong/ssl/kong-default.crt", "lua_socket_pool_size": 30, "admin_ssl_enabled": true }, "version": "1.2.2", "node_id": "cc0f6fa7-3c2c-44f8-a523-8f9e53d7e41e", "lua_version": "LuaJIT 2.1.0-beta3", "prng_seeds": { "pid: 36": 195221171165, "pid: 35": 148625059221, "pid: 39": 191125165965, "pid: 1": 173981549072, "pid: 34": 137193103112, "pid: 38": 175366916141, "pid: 37": 192138146579, "pid: 32": 214162161921, "pid: 33": 152108231211 }, "timers": { "pending": 6, "running": 0 }, "hostname": "api-gateway-kong-79f697ff7c-bcr7m" }
- curl 創建一個service
curl -i -k -X POST --url https://10.234.2.204:30840/services/ --data 'name=baidu-service' --data 'url=https://www.baidu.com/'
- 創建一個routes
curl -ik -X POST --url https://10.234.2.204:30840/services/baidu-service/routes --data 'hosts[]=baidu.com' --data 'paths[]=/api/baidu'
- curl測試
#訪問proxy curl -k http://10.234.2.204:32582/api/baidu --header 'Host: baidu.com'

六 使用
6.1 CLI使用
提供的CLI(命令行界面Command Line Interface)允許啟動,停止和管理Kong實例。CLI可以管理本地節點(如在當前計算機上)。
- 通用參數
--help:打印此命令的幫助信息 --v:啟用詳細模式 --vv:啟用調試模式(很多輸出)
- 命令
kong check <conf> #檢查給定Kong配置文件的有效性。 kong health [OPTIONS] #驗證Kong 的服務組件是否正常運行
kong migrations COMMAND [OPTIONS] 可用的命令如下: bootstrap 引導數據庫並運行全部遷移(初始化)。 up 運行新遷移。 finish 完成正在等待中的遷移命令,在執行`up`後。 list 列出已執行的遷移。 reset 重置數據庫。 Options(可選): -y,--yes 假設提示「yes」,並運行非交互模式 -q,--quiet 忽略所有輸出 -f,--force 依舊執行遷移,即使數據庫報告已經執行過了。 --db-timeout (default 60) 超時時間,以秒為單位,所有數據庫操作通用(包括Cassandra的schema consensus)。 --lock-timeout (default 60) 超時時間,以秒為單位, 節點等待領導節點遷移完成。 -c,--conf (optional string) 配置文件。
kong quit [OPTIONS] #優雅地退出一個正在運行的Kong節點(Nginx和其他節點)在給定的前綴目錄中配置的服務。 kong reload [OPTIONS] #重新加載Kong節點(並啟動其他已配置的服務)在給定的前綴目錄中。 kong restart [OPTIONS] #重新啟動Kong節點(以及其他配置的服務,如Serf)在給定的前綴目錄中。
更詳細的CLI參數可參考:CLI Reference
6.1 配置一個實例
配置一個訪問 www.baidu.com/ 的接口API,實際使用時會對接後端的業務數據接口地址。
路由定義了匹配客戶端請求的規則,每一個路由關聯一個 Service,每一個 Service 有可能被多個路由關聯,每一個匹配到指定的路由請求將被代理到它關聯的 Service 上,參見Kong Admin Api Route Object。
kong admin接口
GET /routers/ #列出所有路由 GET /services/ #列出所有服務 GET /consumers/ #列出所有用戶 GET /services/{service name or id}/routes #列出服務關聯的路由 GET /plugins/ #列出所有的插件配置 GET /plugins/enabled #列出所有可以使用的插件 GET /plugins/schema/{plugin name} #獲得插件的配置模版 GET /certificates/ #列出所有的證書 GET /snis/ #列出所有域名與證書的對應 GET /upstreams/ #列出所有的upstream GET /upstreams/{name or id}/health/ #查看upstream的健康狀態 GET /upstreams/{name or id}/targets/all #列出upstream中所有的target
6.1.1 創建服務
服務是上游服務的抽象,可以是一個應用,或者具體某個接口。
- 命令行方式創建服務:
curl -i -X POST --url http://134.175.74.48:8001/services/ --data 'name=baidu-service' --data 'url=https://www.baidu.com/'
- postman創建



6.1.2 創建路由
在剛才創建的baidu-service的服務上創建路由
- Curl 創建
curl -i -X POST --url http://134.175.74.48:8001/services/baidu-service/routes --data 'hosts[]=baidu.com' --data 'paths[]=/api/baidu'
- postman創建


6.1.3 測試
- curl測試
這時候訪問kong的proxy地址
時,如果host為baidu.com,請求被轉發到
http://baidu.com
curl http://134.175.74.48:8000/api/baidu --header 'Host: baidu.com'
- postman測試

測試post

利用konga web界面操作更為方便。
6.2 插件使用
插件是用來擴展API的,例如為API添加認證、設置ACL、限制速率等、集成oauth、ldap等。
6.2.1 認證-JWT
上面的配置,只要知道Router的地址,就可以訪問獲取數據,我們要把API加入身份認證。如果API面對不是具體用戶,而是其他的系統,可以使用JWT來進行系統間身份認證,使用Kong JWT插件就可能完成這功能。JWT 插件要在對應的Router上進行啟用。
curl -X POST http://134.175.74.48:8001/routes/8e6a1982-5dee-492c-8fe0-c046ebae573c/plugins --data "name=jwt"
fee36521-e549-410f-8986-9fbba02219c1 是創建的service的ID。
這時再通過Postman 訪問上面的接口就會提示:

{ "message": "Unauthorized" }
- 創建用戶
curl -i -X POST --url http://134.175.74.48:8001/consumers/ --data "username=kongauser1"
- 用戶生成JWT憑證
curl -i -X POST --url http://134.175.74.48:8001/consumers/kongauser1/jwt --header "Content-Type: application/x-www-form-urlencoded"
返回憑證信息,也可以通過 get 方法查詢憑證信息
{ "rsa_public_key": null, "created_at": 1560723665, "consumer": { "id": "8bb94f49-22a6-4d77-9a64-21f13adc0342" }, "id": "a110d234-6dc1-4443-9da2-21acddc66e09", "algorithm": "HS256", "secret": "lCe8Lbb7F0KtLccaBcBnOvYg76V7wmQx", "key": "7yQoUdF0aFUC9N593uLQLbqL7RSPj2qM" }

使用key和secret在 jwt.io/ 可以生成jwt 憑證信息.


再通過postman 訪問,就可以看到數據了。
6.2.2 安全-ACL
JWT插件可以保護API能夠被受信用戶訪問,但不能區別哪個用戶能夠訪問哪個API,即接口權限問題,我們使用ACL 插件解決這個問題.
在上面定義好的路由上啟用acl 插件,指定白名單,
curl -i -X POST --url http://134.175.74.48:8001/routes/afb8bfbd-977e-464f-8c94-05d6c5c98429/plugins --data "name=acl" --data "config.whitelist=go2cloud-api-group"
此時再訪問api,會提示不能訪問這個服務。
{ "message": "You cannot consume this service" }

只需將kongauser1這個用戶關聯到白名單內的go2cloud-api-group組裡即可。
curl -i -X POST --url http://134.175.74.48:8001/consumers/tianqiuser/acls --data "group=tianqi"

再次訪問接口,能正常返回數據。

現在就可以對網關暴露的接口進行身份認證和權限控制了。
6.2.3 認證-key-auth
- 為服務或者路由創建key-auth,插件即可以應用在service上,也可以應用在route上
curl -i -X POST --url http://134.175.74.48:8001/services/go2cloud-api/plugins/ --data 'name=key-auth'

獲取到的結果為:
{ "created_at": 1566027525, "config": { "key_names": [ "apikey" ], "run_on_preflight": true, "anonymous": null, "hide_credentials": false, "key_in_body": false }, "id": "9be2def2-df65-41a4-97b7-52e44b207427", "service": { "id": "ceb337a3-a6e0-4520-ba7a-f61403e36dcf" }, "name": "key-auth", "protocols": [ "grpc", "grpcs", "http", "https" ], "enabled": true, "run_on": "first", "consumer": null, "route": null, "tags": null }
- 創建用戶,在用戶中配置apk-key
curl -i -X POST --url http://localhost:8001/consumers/ --data "username=Jason" curl -i -X POST --url http://localhost:8001/consumers/Jason/key-auth/ --data 'key=123456'

- postman測試,認證方式為apikey

6.2.4 認證-basic auth
- 在service或route上創建basic auth
圖片描述 - 在consumers中創建basic credentials

- 利用postman測試

6.2.5 安全-ip-restriction
顧名思義,用來設置接口IP的黑白名單
- 在service或routes上創建basic auth,配置黑白名單

- postman測試

將調用方的IP地址加入到白名單中,可以正常訪問。
6.2.6 安全-bot-detection
- 為routes或service 創建bot-detection,'User-Agent: PostmanRuntime/7.15.2',將postman客戶端加入到黑名單進行測試,默認規則詳見:https://github.com/Kong/kong/blob/master/kong/plugins/bot-detection/rules.lua


6.2.7 流控-rate-limiting
- 在service或route配置流量控制
定義每秒/分鐘/小時/天/月/年可以發送的請求數量
限制可以根據服務或路由/ip地址/證書
策略可以利用本地,集群或redis
例如配置限制每天只能調用10次
- postman測試

6.2.8 流控-request/size-limiting/termination
request-size-limiting 請求payload size限制
request-termination 這允許(暫時)阻止API或消費者

此處只簡單列舉幾個插件,更詳細的插件請查看,
測試在k8s中目前還沒有將konga做成helm部署,後期可以自己將起做成charts方便在k8s中圖形化管理。
參考鏈接
- https://docs.konghq.com/0.13.x/admin-api/#route-object
- https://www.kubernetes.org.cn/4952.html
- https://www.lijiaocn.com/tags/all.html#kong
- https://github.com/Kong/kong
- https://docs.konghq.com/install/kubernetes/
- https://github.com/PGBI/kong-dashboard
- konga官網
- konga github
- kong中文地址
- http://www.102no.com/archives/tag/kong%E6%95%99%E7%A8%8B