整合一套高效能閘道器Kong

yi念之間發表於2021-04-12

前言

    相信大家對Api閘道器都比較的熟悉,我們之前的文章也介紹過ASP.NET Core的閘道器Ocelot,也介紹過Spring Cloud Gateway。說到閘道器的主要功能,其實總結起來就兩個字"統一",無論是作為應用的入口、認證授權、熔斷限流等等主要都是為了統一的地方做一些事情。今天我們介紹一款效能更高的閘道器Kong,相對於Ocelot或Gateway這些型別的閘道器來說,Kong的優勢是具有更高的效能,主要因為Kong是基於Nginx+Lua為核心的,接下來我們就詳細介紹一下。

概念介紹

    在使用Kong之前我們先來大致的介紹一下Kong是什麼,Kong是基於OpenResty的開源閘道器。而OpenResty是基於Nginx與Lua的高效能Web平臺。經常使用Nginx的同學們都知道,如果修改了Nginx的配置是需要重啟Nginx的。而OpenResty讓Nginx具備了動態程式設計的能力,使得Nginx成為了一個應用伺服器軟體,Kong正是基於OpenResty的,Nginx的效能不必多說,所以Kong可以理解為執行在Nginx上的高效能閘道器,在學習的過程中我們可以類比著Nginx進行了解。

Kong

說了這麼多接下來我們大致介紹一下Kong自學三件套

Kong有一點做的還是比較好的,無論是GitHub還是官方文件介紹的都比較詳細,而且比較通俗易懂,這裡我們就不過多的介紹了,有興趣的同學可以自行了解一下。介紹完了自學三件套之後,接下來我們瞭解一下搭建一套Kong的幾個組成部分,總結起來就是三個Kong服務、Kong依賴的儲存、Kong視覺化介面,下面我們大致的介紹一下。

  • 首先是Kong服務,一套可以正常工作的Kong會包含兩個對外提供服務的埠,一個是閘道器常規使用的埠,即對外提供訪問的入口。另一個則是管理Kong的Admin埠,比如對Kong管理服務的增刪改查以及Kong常用的Plugin管理以及一些常規的配置等,Kong的外掛非常的豐富,基本上可以到達常規的一些操作比如限流、認證授權、鏈路跟蹤、監控等都有而且形式非常的豐富。
  • 其次是Kong儲存服務,因為在Kong上配置的轉發服務、外掛、環境變數、認證等相關的資訊都是需要儲存的,但是外部儲存不是必須的,Kong可以將這些資訊儲存到程式內的快取中,但是重啟Kong之後這些配置將會丟失,因此在正常的使用過程中我們總會給他提供一個外部資料庫來儲存這些資訊。可供Kong使用的儲存資料庫也有好幾個選擇分別是Mysql、MongoDB、Postgresql等。本次演示我們使用的是Postgresql,也是官方推薦的方式。
  • 最後是Kong的視覺化UI,當然這個不是必須的。Kong提供了Admin管理介面的形式對服務和Plugin檢視、新增、修改、刪除等操作,但是有一個視覺化的管理介面,無疑讓有些操作變得更加簡單清晰,而且這些視覺化系統正式基於Kong的Admin介面開發的。可供選擇的視覺化UI也比較多,比較出名的有Konga、kong-ui、kong-admin-ui。本次演示我們選擇的是Konga,也是推薦使用的最多的一個。
Konga

    Konga並非Kong官方出品的視覺化UI,但是它是最流行的一個,也是使用最多的一個,目前最新版本是v0.6.3。Konga是基於Nodejs開發的,它的Github地址是https://github.com/pantsel/konga,同樣的Konga的GitHub文件上介紹的也非常的詳細。它的部署方式有兩種,一個是直接克隆GitHub上的倉庫上的程式碼通過npm的方式執行,另一種則是使用docker的方式部署。兩種方式都非常的簡單,本次我們選擇docker的方式。

環境搭建

    關於Kong的搭建,官方網站給出了好幾種部署方式可以基於Docker或K8S,也可以在Liunx作業系統Centos、Ubuntu、RHEL等都支援,目前最穩定版本為2.3.x,這些在官方文件上講解的非常詳細非常易懂,具體可參閱官方文件https://konghq.com/install/。如果想能快速的搭建起一套Kong+Postgresql+Konga的環境,docker-compose無疑是一個比較好的選擇,接下來我們將演示用過這種方式快速搭建起一條完整的Kong環境。
    Kong官方GitHub有專門的docker-kong倉庫地址為https://github.com/Kong/docker-kong,也已將這個倉庫Clone下來,找到compose檔案執行。但是我們這裡還要整合視覺化介面Konga,Konga並非官方出品,所以我要要修改一下compose檔案整合進去Konga,完整的呈現如下所示

version: '3.3'
#建立kong_data卷
volumes:
  kong_data: {}
#建立kong-net網路
networks:
  kong-net:
    external: false

services:
  #資料庫執行完成之後需要執行kong進行初始化操作
  kong-migrations:
    image: "${KONG_DOCKER_TAG:-kong:latest}"
    command: kong migrations bootstrap
    depends_on:
      - db
    environment:
      KONG_DATABASE: postgres
      KONG_PG_DATABASE: ${KONG_PG_DATABASE:-kong}
      KONG_PG_HOST: db
      KONG_PG_USER: ${KONG_PG_USER:-kong}
      KONG_PG_PASSWORD_FILE: /run/secrets/kong_postgres_password
    secrets:
      - kong_postgres_password
    networks:
      - kong-net
    restart: on-failure
    deploy:
      restart_policy:
        condition: on-failure
  #遷移過程依賴db
  kong-migrations-up:
    image: "${KONG_DOCKER_TAG:-kong:latest}"
    command: kong migrations up && kong migrations finish
    depends_on:
      - db
    environment:
      KONG_DATABASE: postgres
      KONG_PG_DATABASE: ${KONG_PG_DATABASE:-kong}
      KONG_PG_HOST: db
      KONG_PG_USER: ${KONG_PG_USER:-kong}
      KONG_PG_PASSWORD_FILE: /run/secrets/kong_postgres_password
    secrets:
      - kong_postgres_password
    networks:
      - kong-net
    restart: on-failure
    deploy:
      restart_policy:
        condition: on-failure
  # kong服務
  kong:
    image: "${KONG_DOCKER_TAG:-kong:latest}"
    user: "${KONG_USER:-kong}"
    depends_on:
      - db
    environment:
      KONG_ADMIN_ACCESS_LOG: /dev/stdout
      KONG_ADMIN_ERROR_LOG: /dev/stderr
      KONG_ADMIN_LISTEN: '0.0.0.0:8001'
      KONG_CASSANDRA_CONTACT_POINTS: db
      KONG_DATABASE: postgres
      KONG_PG_DATABASE: ${KONG_PG_DATABASE:-kong}
      KONG_PG_HOST: db
      KONG_PG_USER: ${KONG_PG_USER:-kong}
      KONG_PROXY_ACCESS_LOG: /dev/stdout
      KONG_PROXY_ERROR_LOG: /dev/stderr
      KONG_PG_PASSWORD_FILE: /run/secrets/kong_postgres_password
    secrets:
      - kong_postgres_password
    networks:
      - kong-net
    #kong的埠,非https使用8000和8001
    ports:
      - "8000:8000/tcp"
      - "8001:8001/tcp"
      - "8443:8443/tcp"
      - "8444:8444/tcp"
    #健康檢查
    healthcheck:
      test: ["CMD", "kong", "health"]
      interval: 10s
      timeout: 10s
      retries: 10
    restart: on-failure
    deploy:
      restart_policy:
        condition: on-failure

  #konga視覺化介面
  konga:
    image: pantsel/konga
    networks:
      - kong-net
    depends_on:
      - db
    ports:
      - "1337:1337/tcp"
    environment:
      TOKEN_SECRET: konga
      DB_ADAPTER: postgres
      DB_HOST: db
      DB_PORT: 5432
      DB_USER: kong
      DB_PASSWORD: kong
      DB_DATABASE: kong
    restart: on-failure
    deploy:
      restart_policy:
        condition: on-failure
  # postgres資料庫
  db:
    image: postgres:9.6
    environment:
      POSTGRES_DB: ${KONG_PG_DATABASE:-kong}
      POSTGRES_USER: ${KONG_PG_USER:-kong}
      POSTGRES_PASSWORD_FILE: /run/secrets/kong_postgres_password
    secrets:
      - kong_postgres_password
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "${KONG_PG_USER:-kong}"]
      interval: 30s
      timeout: 30s
      retries: 3
    restart: on-failure
    deploy:
      restart_policy:
        condition: on-failure
    stdin_open: true
    tty: true
    ports:
      - 5432:5432
    networks:
      - kong-net
    volumes:
      - kong_data:/var/lib/postgresql/data

# 用檔案統一管理資料庫密碼
secrets:
  kong_postgres_password:
    file: ./POSTGRES_PASSWORD

通過docker-compose直接執行上面的yaml檔案,便可以直接執行一套完整的kong專案,這裡在強調一下上面說過GitHub上有官方專門提供的docker-kong倉庫,直接Clone便可以直接得到執行Kong的yaml,但是本示例我們加入了Konga,如果需要可直接下載我修改後的包[點選下載?]下載完成之後進入docker-compose.yml所在的資料夾,執行docker-compose up -d指令,首次的話會下載依賴的映象檔案可能稍微慢一點,出現如下介面的時候說明正常執行完成

整合一套高效能閘道器Kong
完成之後開啟http://localhost:8000/這個是kong提供轉發服務的地址,出現如下執行結果

{
  "message": "no Route matched with those values"
}

因為我們沒有配置任何路由規則,所以會提升匹配不到路由。然後我們在瀏覽器開啟konga的地址http://localhost:1337/出現如下介面,則表示kong和konga執行成功

整合一套高效能閘道器Kong

操作使用

通過上面的操作我們已經成功執行起來了Kong+Konga+Postgresql的執行環境,然後我們就可以使用這套閘道器完成服務的轉發相關的操作,常用的方式有兩種,一種是通過Konga直接配置,另一種則是直接通過Kong服務的8001埠訪問管理的restful介面進行操作,當然Konga也是基於這套介面來操作的,接下來我們就來大致演示一下使用這兩種方式完成相關操作。

通過Konga介面配置

開啟Konga之後首次會讓註冊登入資訊,註冊完成之後會讓完成Konga的配置連線操作,主要就是配置Kong的管理介面

整合一套高效能閘道器Kong
配置成功之後左側選單欄會出現配置相關的操作比如Service、Route、Target相關如下圖所示
整合一套高效能閘道器Kong
如果只是配置類似代理的功能,即通過閘道器轉發到一個真實地址的場景,那麼只需要新增Service,並且配置Route即可,首先新增Service
整合一套高效能閘道器Kong
然後新增Route資訊
整合一套高效能閘道器Kong
當然這是最簡單的方式去實現類似反向代理的操作,有的時候其實我們需要的是不僅僅能夠實現轉發,而且還能實現負載均衡的場景。這時候的請求模式就是一個高可用和負載均衡的模式,這個時候僅僅通過配置Service和Route是不夠的,我們需要的是Nginx的Upstream的情況,一個Upstream對應多個真實的後端地址。
首先配置Upstreams,由於kong本質處理請求還是通過nginx進行的,所以概念可以直接和nginx類比過來,其實就是是類似配置一個轉發操作,這個操作既可以是一個服務地址,也可以是一組服務集合
整合一套高效能閘道器Kong
然後對這個upstream的資訊進行配置,除了Name必填其他都可以選填
整合一套高效能閘道器Kong
如果選擇了header或cookie策略,就要為對應的策略設定具體的值,以header為例
整合一套高效能閘道器Kong
健康檢查相關分為主動檢測和被動檢測。主動監測是kong定時像Target傳送請求探測,根據探測的結果判斷服務是否健康。被動檢測是通過攔截外部請求到Target,然後根據Target的響應狀態判斷轉發的節點是否健康
整合一套高效能閘道器Kong
下圖為被動檢查的相關配置,其實無論是主動監測還是被動檢測,他們的概念都是一樣的只是方式不一樣,一個是Kong主動探測,一個是根據外部請求攔截真實服務節點的返回狀態判斷。它們判斷的依據和Nginx健康檢查的判斷邏輯也是一致的,主要通過http狀態碼、tpc連線是否正常、請求是否超時為主要評估依據。
整合一套高效能閘道器Kong
Upstream除了Name之外其他的配置都是選填的,配置完成直接點選儲存即可,這樣Upstream就配置完成了。接下來就是為Upstreams配置Target。Target等同於Nginx上在Upstream節點內配置真實的轉發節點地址,如果用一句話描述Upstream與Target代表的含義的話,可以理解為Upstream是一組可以提供相同服務的虛擬節點,而Target是這一組真實節點中的一個,是真實提供服務的節點之一。
整合一套高效能閘道器Kong
Target的配置也很簡單,一個是配置Target的地址,另一個是當前這個Target的權重。上面我們們說過,一個Upstream是一組Target的集合,所以每個Target配置都可以配置對應的權重,我們們說的權重其實一種優先順序的概念,每一次請求優先順序比較高的會優先被訪問到。如果真是的伺服器配置基本上一致的話,那麼權重理應是一樣的,如果存在弱機的情況,那麼弱機的權重應該配置的稍微低一些。
整合一套高效能閘道器Kong
接下來就是新增Service,Service在Kong閘道器裡的概念就是一個服務,比如我要訪問商品服務、訂單服務、優惠券服務,而Service正是表示著這種概念。如果說Upstreams代表著一組真實的服務,那麼Service就是Upstream的門面,通過Service才能訪問到Upstream。
整合一套高效能閘道器Kong
配置Service主要配置Name和訪問地址即可,這裡的訪問地址在Konga裡有兩種配置形式,一個是直接配置Url,另一個是配置protocol、host、port、path。比如上圖的Url屬性等同於下面的 協議+主機+埠+路徑,均是針對Upstream的訪問配置,和具體訪問路由屬於不同概念,如果是通過Service訪問Upstream的場景,那麼Host就是是Upstream的名稱或真實的訪問目標地址名稱
整合一套高效能閘道器Kong
接下來就是配置Route,上面我們們說到了Service和Upstream的概念,那麼Route起到的作用就是,當我訪問了Service那麼我通過什麼樣的路由規則才能訪問到Upstream,比如特定的Host頭資訊或者路徑資訊等。在Konga裡,通過Service列表介面點選具體Service進入ServiceDetail介面配置Route
整合一套高效能閘道器Kong
點選ADD ROUTE會彈出新增Route資訊的彈窗,主要配置Name、Host Paths Strip Path具體含義可看截圖
整合一套高效能閘道器Kong整合一套高效能閘道器Kong
這裡我們們重點說一下Strip Path,它代表的含義是如果通過一個路徑訪問到了真實的服務地址,那麼在訪問真實的服務地址的時候是否要帶上這個Path資訊,還是這個Path只是為了提供訪問到具體服務的一個標識。比如真實的OrderService服務裡獲取訂單詳情的地址為http://localhost:5001/order/get/1,我們在通過閘道器訪問OrderService的時候地址是http://localhost:8000/orderservice/order/get/1,這種情況Path裡的orderservice對我來說只是為了能訪問到OrderService的一個路徑標識,真實服務OrderService的時候並不需要,這個時候我就可以設定Strip Path的值為true,這樣在轉發地址的時候就不會在Url上帶上orderservice這個標識了。到這裡,關於通過Konga配置的常用操作介紹的就差不多了,截圖上也標註了常用欄位的含義,想更詳細的瞭解還需要自己搭建一套Konga實操一下。

通過Kong的Admin介面配置

    上面我們介紹了通過Konga的方式配置Kong的服務,我們開始的時候也說過,Konga也是通過Kong Admin API的介面完成對服務的增刪改查的操作的,Kong Admin API是Kong自帶的管理介面,通過這些介面我們可以通過更原生的方式去操作Kong。而且如果你通過Konga配置的時候不太瞭解哪些欄位是必須的,或者需要理解每個欄位詳細代表的含義,這時候就可以通過原生的介面瞭解,這樣有助於更深刻的瞭解。Admin API的官方文件地址位於https://docs.konghq.com/gateway-oss/2.3.x/admin-api/文件介紹的非常的詳細,接下來我們就大致的介紹Admin API的一些常規操作。

  • 預設情況Admin API的監聽埠是8001,如果是https的話預設為8444
  • API可接收的內容格式即ContentType為application/json、application/x-www-form-urlencoded、multipart/form-data
  • Kong Admin API是標準的Restful風格的介面,這對於我們操作來說非常的便捷

由於Admin API官方文件介紹的非常詳細了,這裡我們們就不一一的介紹了,我們們這裡簡單的介紹一下有代表性的介面和一些注意相關的操作。強烈建議,學習Kong的話一定要看這個文件,這樣的話能解決很多的困惑。首先介紹Service的List的介面,這個介面是返回註冊在Kong上的所有Service

  • 請求方式是curl http://localhost:8001/services
  • 成功的狀態碼為HTTP 200 OK
  • 返回的json格式代表的含義,文件中介紹的也非常詳細
{
    "data": [{
        "id": "a5fb8d9b-a99d-40e9-9d35-72d42a62d83a",
        "created_at": 1422386534,
        "updated_at": 1422386534,
        "name": "my-service",
        "retries": 5,
        "protocol": "http",
        "host": "example.com",
        "port": 80,
        "path": "/some_api",
        "connect_timeout": 60000,
        "write_timeout": 60000,
        "read_timeout": 60000,
        "tags": ["user-level", "low-priority"],
        "client_certificate": {"id":"51e77dc2-8f3e-4afa-9d0e-0e3bbbcfd515"},
        "tls_verify": true,
        "tls_verify_depth": null,
        "ca_certificates": ["4e3ad2e4-0bc4-4638-8e34-c84a417ba39b", "51e77dc2-8f3e-4afa-9d0e-0e3bbbcfd515"]
    }],
    "next": "http://localhost:8001/services?offset=6378122c-a0a1-438d-a5c6-efabae9fb969"
}

data為資料結果,next是下一批資料查詢的地址。這一點做得還是考慮的比較周全的,如果Service比較多的話,一次性返回不是一個明智的操作,通過判斷next的方式可以知道是否存在分頁的情況,根據判斷狀態碼可以知道請求是否成功。
其次Service還有一個檢索介面,它主要用於返回指定的Service資訊,它的請求方式是curl http://localhost:8001/services/{service name or id},如果返回的狀態碼為404則說明服務沒有被註冊過,如果服務存在則狀態碼為200並返回服務詳情的json。
還有一個比較實用的介面是Update Or Create Service翻譯過來就是修改或建立,即如果Service存在則執行更新操作,如果不存在則直接建立一個Service。試著想一下,如果不存在這個介面,我們每次註冊Service之前還要呼叫一下檢索介面判斷一下Service是否被註冊過。
請求方式是curl -X PUT -H "Content-Type: application/json" -d '{}' "http://localhost:8001/services/{service name or id}"它的請求資料格式和Add的是一樣的只是請求方式是PUT它的資料格式是

{
    "id": "9748f662-7711-4a90-8186-dc02f10eb0f5",
    "created_at": 1422386534,
    "updated_at": 1422386534,
    "name": "my-service",
    "retries": 5,
    "protocol": "http",
    "host": "example.com",
    "port": 80,
    "path": "/some_api",
    "connect_timeout": 60000,
    "write_timeout": 60000,
    "read_timeout": 60000,
    "tags": ["user-level", "low-priority"],
    "client_certificate": {"id":"4e3ad2e4-0bc4-4638-8e34-c84a417ba39b"},
    "tls_verify": true,
    "tls_verify_depth": null,
    "ca_certificates": ["4e3ad2e4-0bc4-4638-8e34-c84a417ba39b", "51e77dc2-8f3e-4afa-9d0e-0e3bbbcfd515"]
}'

它返回的結果是HTTP 201 Created or HTTP 200 OK

這裡需要特別注意的是Add相關的介面返回的Http是HTTP 201 Created

    我們就通過關於Service的操作,大致介紹一下關於Admin API的大致操作方式,關於每一個Service、Route、Upstream、Target的操作都有完整的增刪改查介面,我們們上面介紹的是除了這些之外實用操作的介面。這裡還需要注意的是有些操作是有關聯關係的,比如Service和Route的操作,Upstream和Target的操作,因此在實際通過介面開發的過程中要注意對Service的Id或Upstream的Id的儲存。

因為Kong對註冊中心這些比如Consul、Eureka、Nacos這種支援的並不是很完善,雖然Kong支援自己編寫Lua指令碼的方式完成這些操作,但是這些編寫成本還是比較高的,所以這個時候Admin API就顯得格外的實用。

總結

    本次我們主要講解了對Kong的大致入門操作,相信很多同學都聽說過或者用過它,我個人覺得Kong這種級別的元件很多時候能瞭解它的大致場景和結構並能搭建出來一套可執行的環境,那麼入門就已經完成一半了。我覺得Kong做的比較好的一點是,它的學習文件和GitHub倉庫上的一些操作都非常的完整而且很詳細。我每次寫這種型別的文章其實初衷都非常的簡單,就是能讓對這些東西有興趣的同學,能通過這篇文章入門,算是能有一個好的開始吧。

?歡迎掃碼關注我的公眾號? 整合一套高效能閘道器Kong

相關文章