微服務API網關-Kong初探

原文網址:https://juejin.im/post/5d7201a15188256a013af421

一 概述

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;
  • 基於插件的可擴展。

四 架構圖

微服務API網關-Kong初探


五 部署

5.1 物理服務器部署

5.1.1 配置yum源

<code>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
複製代碼/<code>

5.1.2 數據庫安裝

Kong支持PostgreSQL v9.5+和Cassandra 3.x.x作為數據存儲。

按照文檔安裝PostgreSQL v11: www.postgresql.org/download/li…

<code># 安裝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
複製代碼/<code>
<code># 登錄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

複製代碼/<code>
<code># 這裡需要提前配置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.\t

# 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
複製代碼/<code>

5.1.2 啟動kong

在無數據庫模式配置Kong,一旦Kong啟動,訪問Admin API的/根端點已驗證它是否在沒有數據庫的情況下運行。

<code>
# 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.conf>/<code>
<code>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
複製代碼/<code>

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安裝
<code>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
複製代碼/<code>
  • 安裝konga
<code>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;
複製代碼/<code>
  • 配置
<code>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 |
複製代碼/<ctrl>/<code>
  • 訪問

IP:1338,默認用戶:admin,密碼:adminadminadmin

配置鏈接kong, http://localhost:8001

微服務API網關-Kong初探

微服務API網關-Kong初探

5.2 docker中運行

5.2.1 Docker中部署

<code>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
複製代碼/<code>

5.2.2 docker-compose部署

  • 創建虛擬網絡
<code>docker network create kong-net
複製代碼/<code>

後續的應用及數據庫都使用這個虛擬網絡。

  • 編寫docker-compose.yaml
<code>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

複製代碼/<code>

使用docker-compose up 命令啟動服務。會發現啟動時報數據庫錯誤,這是因為kong 使用的postgres 數據還需要進行初始化才能使用。

  • 初始化數據庫
<code>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

複製代碼/<code>

一定要在創建數據庫容器之後,並且保持數據庫的Docker容器在運行狀態,再執行初始化數據庫,數據庫初始化成功後,再次使用docker-compose up -d 啟動服務就可以了。

  • 驗證
<code>curl -i http://localhost:8001/
複製代碼/<code>
  • 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.
<code># 下載鏡像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
複製代碼/<none>/<none>/<none>/<none>/<code>

通過docker安裝一個Kong-Dashboard,安裝完成後,通過瀏覽器訪問:

5.3 kubernetes部署

5.3.1 前置條件

  • 已有Kubernetes 1.6+環境;
  • 已部署helm客戶端和tiller服務端(請參考:docs.helm.sh/using_helm/… 在Kubernetes中創建了具備足夠權限訪問權限的service account; 並通過此service account在Kubernetes部署了tiller服務端(請參考:docs.helm.sh/using_helm/…

5.3.2 helm char配置

下表列示了Kong chart的配置參數和默認值:

參數 說明 默認值 image.repository Kong image kong image.tag Kong image version 0.14.1 image.pullPolicy Image pull policy IfNotPresent image.pullSecrets Image pull secrets null replicaCount Kong instance count 1 admin.useTLS Secure Admin traffic true admin.servicePort TCP port on which the Kong admin service is exposed 8444 admin.containerPort TCP port on which Kong app listens for admin traffic 8444 admin.nodePort Node port when service type is NodePort admin.type k8s service type, Options: NodePort, ClusterIP, LoadBalancer NodePort admin.loadBalancerIP Will reuse an existing ingress static IP for the admin service null admin.loadBalancerSourceRanges Limit admin access to CIDRs if set and service type is LoadBalancer [] admin.ingress.enabled Enable ingress resource creation (works with proxy.type=ClusterIP) false 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 true proxy.servicePort TCP port on which the Kong Proxy Service is exposed 8443 proxy.containerPort TCP port on which the Kong app listens for Proxy traffic 8443 proxy.nodePort Node port when service type is NodePort proxy.type k8s service type. Options: NodePort, ClusterIP, LoadBalancer NodePort proxy.loadBalancerSourceRanges Limit proxy access to CIDRs if set and service type is LoadBalancer [] 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) false 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 true 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

<code>---
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
複製代碼/<code>
<code>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}')



複製代碼/<none>/<none>/<none>/<none>/<code>

5.3.4 驗證Kong(命令行)

通過執行下面的命令,進入Kong的容器:

<code>[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
複製代碼/<code>

並在kong中執行如下的命令:

<code>curl -k http://localhost:8444
複製代碼/<code>

如果kong正常運行的話,應該會返回一些內容。

<code>[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
複製代碼/<none>/<none>/<none>/<none>/<code>

通過瀏覽器查看


微服務API網關-Kong初探

<code>{
"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"
}
複製代碼/<code>
  • curl 創建一個service
<code>curl -i -k -X POST \\
--url https://10.234.2.204:30840/services/ \\
--data 'name=baidu-service' \\
--data 'url=https://www.baidu.com/'
複製代碼/<code>
  • 創建一個routes
<code>curl -ik -X POST \\
--url https://10.234.2.204:30840/services/baidu-service/routes \\
--data 'hosts[]=baidu.com' \\
--data 'paths[]=/api/baidu'
複製代碼/<code>
  • curl測試
<code>#訪問proxy
curl -k http://10.234.2.204:32582/api/baidu --header 'Host: baidu.com'
複製代碼/<code>


微服務API網關-Kong初探

六 使用

6.1 CLI使用

提供的CLI(命令行界面Command Line Interface)允許啟動,停止和管理Kong實例。CLI可以管理本地節點(如在當前計算機上)。

  • 通用參數
<code>--help:打印此命令的幫助信息
--v:啟用詳細模式
--vv:啟用調試模式(很多輸出)

複製代碼/<code>
  • 命令
<code>kong check <conf>\t\t#檢查給定Kong配置文件的有效性。
kong health [OPTIONS] #驗證Kong 的服務組件是否正常運行
複製代碼/<conf>/<code>
<code>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) 配置文件。
複製代碼/<code>
<code>kong quit\t[OPTIONS]\t#優雅地退出一個正在運行的Kong節點(Nginx和其他節點)在給定的前綴目錄中配置的服務。 

kong reload\t[OPTIONS]\t#重新加載Kong節點(並啟動其他已配置的服務)在給定的前綴目錄中。
kong restart [OPTIONS]\t#重新啟動Kong節點(以及其他配置的服務,如Serf)在給定的前綴目錄中。
複製代碼/<code>

更詳細的CLI參數可參考:CLI Reference

6.1 配置一個實例

配置一個訪問 www.baidu.com/ 的接口API,實際使用時會對接後端的業務數據接口地址。

路由定義了匹配客戶端請求的規則,每一個路由關聯一個 Service,每一個 Service 有可能被多個路由關聯,每一個匹配到指定的路由請求將被代理到它關聯的 Service 上,參見Kong Admin Api Route Object。

kong admin接口

<code>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
複製代碼/<code>

6.1.1 創建服務

服務是上游服務的抽象,可以是一個應用,或者具體某個接口。

  • 命令行方式創建服務:
<code>curl -i -X POST \\
--url http://134.175.74.48:8001/services/ \\
--data 'name=baidu-service' \\
--data 'url=https://www.baidu.com/'
複製代碼/<code>
  • postman創建
微服務API網關-Kong初探

微服務API網關-Kong初探

微服務API網關-Kong初探

6.1.2 創建路由

在剛才創建的baidu-service的服務上創建路由

  • Curl 創建
<code>curl -i -X POST \\
--url http://134.175.74.48:8001/services/baidu-service/routes \\
--data 'hosts[]=baidu.com' \\
--data 'paths[]=/api/baidu'
複製代碼/<code>
  • postman創建


6.1.3 測試

  • curl測試

這時候訪問kong的proxy地址時,如果host為baidu.com,請求被轉發到baidu.com

<code>curl  http://134.175.74.48:8000/api/baidu --header 'Host: baidu.com'
複製代碼/<code>
  • postman測試


微服務API網關-Kong初探

測試post


微服務API網關-Kong初探

利用konga web界面操作更為方便。

6.2 插件使用

插件是用來擴展API的,例如為API添加認證、設置ACL、限制速率等、集成oauth、ldap等。

6.2.1 認證-JWT

上面的配置,只要知道Router的地址,就可以訪問獲取數據,我們要把API加入身份認證。如果API面對不是具體用戶,而是其他的系統,可以使用JWT來進行系統間身份認證,使用Kong JWT插件就可能完成這功能。JWT 插件要在對應的Router上進行啟用。

<code>curl -X POST http://134.175.74.48:8001/routes/8e6a1982-5dee-492c-8fe0-c046ebae573c/plugins \\
--data "name=jwt"
複製代碼/<code>

fee36521-e549-410f-8986-9fbba02219c1 是創建的service的ID。

這時再通過Postman 訪問上面的接口就會提示:


<code>{
"message": "Unauthorized"
}
複製代碼/<code>
  • 創建用戶
<code>curl -i -X POST \\
--url http://134.175.74.48:8001/consumers/ \\
--data "username=kongauser1"
複製代碼/<code>
  • 用戶生成JWT憑證
<code>curl -i -X POST \\
--url http://134.175.74.48:8001/consumers/kongauser1/jwt \\
--header "Content-Type: application/x-www-form-urlencoded"

複製代碼/<code>

返回憑證信息,也可以通過 get 方法查詢憑證信息

<code>{
"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"
}

複製代碼/<code>


微服務API網關-Kong初探

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


再通過postman 訪問,就可以看到數據了。

6.2.2 安全-ACL

JWT插件可以保護API能夠被受信用戶訪問,但不能區別哪個用戶能夠訪問哪個API,即接口權限問題,我們使用ACL 插件解決這個問題.

在上面定義好的路由上啟用acl 插件,指定白名單,

<code>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"
複製代碼/<code>

此時再訪問api,會提示不能訪問這個服務。

<code>{
"message": "You cannot consume this service"
}
複製代碼/<code>


微服務API網關-Kong初探

只需將kongauser1這個用戶關聯到白名單內的go2cloud-api-group組裡即可。

<code>curl -i -X POST \\
--url http://134.175.74.48:8001/consumers/tianqiuser/acls \\
--data "group=tianqi"
複製代碼/<code>


微服務API網關-Kong初探

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


微服務API網關-Kong初探

現在就可以對網關暴露的接口進行身份認證和權限控制了。

6.2.3 認證-key-auth

  • 為服務或者路由創建key-auth,插件即可以應用在service上,也可以應用在route上
<code> curl -i -X POST \\
--url http://134.175.74.48:8001/services/go2cloud-api/plugins/ \\
--data 'name=key-auth'
複製代碼/<code>


微服務API網關-Kong初探

獲取到的結果為:

<code>{
"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
}
複製代碼/<code>
  • 創建用戶,在用戶中配置apk-key
<code>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'
複製代碼/<code>


微服務API網關-Kong初探

  • postman測試,認證方式為apikey
微服務API網關-Kong初探


docs.konghq.com/hub/)

6.2.4 認證-basic auth

  • 在service或route上創建basic auth
  • 在consumers中創建basic credentials


微服務API網關-Kong初探

  • 利用postman測試
微服務API網關-Kong初探


6.2.5 安全-ip-restriction

顧名思義,用來設置接口IP的黑白名單

  • 在service或routes上創建basic auth,配置黑白名單


微服務API網關-Kong初探

  • postman測試


微服務API網關-Kong初探

將調用方的IP地址加入到白名單中,可以正常訪問。

6.2.6 安全-bot-detection

  • 為routes或service 創建bot-detection,'User-Agent: PostmanRuntime/7.15.2',將postman客戶端加入到黑名單進行測試,默認規則詳見:github.com/Kong/kong/b…
微服務API網關-Kong初探

微服務API網關-Kong初探

6.2.7 流控-rate-limiting

  • 在service或route配置流量控制

定義每秒/分鐘/小時/天/月/年可以發送的請求數量

限制可以根據服務或路由/ip地址/證書

策略可以利用本地,集群或redis

例如配置限制每天只能調用10次

  • postman測試


微服務API網關-Kong初探


6.2.8 流控-request/size-limiting/termination

request-size-limiting 請求payload size限制

request-termination 這允許(暫時)阻止API或消費者


微服務API網關-Kong初探


此處只簡單列舉幾個插件,更詳細的插件請查看,

測試在k8s中目前還沒有將konga做成helm部署,後期可以自己將起做成charts方便在k8s中圖形化管理。


分享到:


相關文章: