一铣卡、 概述
APISIX 是基于 OpenResty + etcd 實現(xiàn)的云原生、高性能缎玫、可擴展的微服務(wù) API 網(wǎng)關(guān)。它是國人開源解滓,目前已經(jīng)進入 Apache 進行孵化赃磨。
- OpenResty:通過 Lua 擴展 Nginx 實現(xiàn)的可伸縮的 Web 平臺。
- etcd:Key/Value 存儲系統(tǒng)洼裤。
APISIX 通過插件機制邻辉,提供了動態(tài)負載平衡、身份驗證腮鞍、限流限速等等功能值骇,當(dāng)然我們也可以自己開發(fā)插件進行拓展。
- 動態(tài)負載均衡:跨多個上游服務(wù)的動態(tài)負載均衡移国,目前已支持 round-robin 輪詢和一致性哈希算法吱瘩。
- 身份驗證:支持 key-auth、JWT迹缀、basic-auth使碾、wolf-rbac 等多種認證方式蜜徽。
- 限流限速:可以基于速率、請求數(shù)票摇、并發(fā)等維度限制拘鞋。
并且 APISIX 還支持 A/B 測試、金絲雀發(fā)布(灰度發(fā)布)矢门、藍綠部署盆色、監(jiān)控報警、服務(wù)可觀測性祟剔、服務(wù)治理等等高級功能隔躲,這在作為微服務(wù) API 網(wǎng)關(guān)非常重要的特性。
下面峡扩,我們正式進入 APISIX 的極簡入門之旅蹭越。
二、安裝
在《APISIX 官方文檔 —— 安裝》中教届,介紹了源碼包响鹃、RPM 包、Luarocks案训、Docker 四種安裝方式买置。這里我們使用 CentOS 7.X 系統(tǒng),所以采用 RPM 包强霎。
因為 APISIX 是基于 OpenResty + etcd 來實現(xiàn)忿项,所以需要安裝它們兩個。
2.1 安裝依賴
CentOS 7腳本
# 安裝 epel, `luarocks` 需要它
wget http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
sudo rpm -ivh epel-release-latest-7.noarch.rpm
# 添加 OpenResty 源
sudo yum install yum-utils
sudo yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo
# 安裝 OpenResty, etcd 和 編譯工具
sudo yum install -y etcd openresty curl git gcc luarocks lua-devel
# 開啟 etcd server
sudo service etcd start
2.2 安裝 Apache APISIX
通過 RPM 包安裝(CentOS 7),其他安裝方式見鏈接城舞。
2.2.1 安裝腳本
sudo yum install -y https://github.com/apache/incubator-apisix/releases/download/1.3/apisix-1.3-0.el7.noarch.rpm
一定要看到最后打印如下信息才安裝成功轩触,否則查看報錯信息來解決。
Installed:
apisix.noarch 0:1.3-0
Complete!
此時家夺,APISIX 安裝在/usr/local/apisix/
目錄脱柱,使用如下命令查看各個文件夾:
$ cd /usr/local/apisix/
$ ls -ls
total 40
4 drwxr-xr-x 8 root root 4096 May 1 11
:40 apisix # APISIX 程序
4 drwx------ 2 nobody root 4096 May 1 20:44 client_body_temp
4 drwxr-xr-x 3 root root 4096 May 1 20:50 conf # 配置文件
4 drwxr-xr-x 6 root root 4096 May 1 20:40 dashboard # APISIX 控制臺
4 drwxr-xr-x 5 root root 4096 May 1 20:40 deps
4 drwx------ 2 nobody root 4096 May 1 20:44 fastcgi_temp
4 drwxrwxr-x 2 root root 4096 May 1 20:44 logs # 日志文件
4 drwx------ 2 nobody root 4096 May 1 20:44 proxy_temp
4 drwx------ 2 nobody root 4096 May 1 20:44 scgi_temp
4 drwx------ 2 nobody root 4096 May 1 20:44 uwsgi_temp
2.2.2 啟動 APISIX
命令:sudo apisix start
默認情況下,APISIX 啟動在 9080 端口拉馋,使用如下命令測試服務(wù)是否正常啟動:
$ curl http://127.0.0.1:9080/
{"error_msg":"failed to match any routes"}
三榨为、APISIX 控制臺
APISIX 內(nèi)置控制臺功能,方便我們進行 APISIX 的 Route煌茴、Consumer随闺、Service、SSL蔓腐、Upstream 的查看與維護矩乐。也就是上面看到的dashboard
文件夾。
dashboard 缺陷:目前dashboard還存在一些不完善的地方回论,一些插件的函數(shù)配置等不可直接編輯绰精,還是得通過apisix api進行撒璧。不過基本的一些配置直接可視化配置、查看很直觀笨使,也夠用卿樱。
在/usr/local/apisix/conf/nginx.conf
配置文件中,設(shè)置了 APISIX 控制臺的訪問路徑為/apisix/dashboard
硫椰。如下文所示:
location /apisix/dashboard {
allow 127.0.0.0/24;
deny all;
alias dashboard/;
try_files $uri $uri/index.html /index.html;
}
考慮到安全性繁调,APISIX 控制臺只允許本機訪問,因此我們需要修改/usr/local/apisix/conf/config.yaml
配置文件靶草,增加允許訪問的遠程 IP 地址蹄胰。如下所示:
allow_admin: # http://nginx.org/en/docs/http/ngx_http_access_module.html#allow
- 127.0.0.0/24 # If we don't set any IP list, then any IP access is allowed by default.
- 211.94.246.0/24 # 新增加的遠程IP地址段。
修改完配置后奕翔,使用 apisix restart
命令裕寨,重啟 APISIX 來生效配置。然后派继,使用瀏覽器訪問 http://101.133.227.13:9080/apisix/dashboard地址宾袜,進入 APISIX 控制臺。結(jié)果如下圖所示:
使用默認的“admin/123456”賬號驾窟,登錄 APISIX 控制臺庆猫。
四、動態(tài)負載均衡
對后端服務(wù)提供的 API 接口進行負載均衡绅络。我們啟動同一個springboot服務(wù)在2個不同端口18080 和 28080
月培。
4.1啟動2個微服務(wù)命令
java -jar vue-springboot-0.0.1-SNAPSHOT-exec.jar --server.port=18080
java -jar vue-springboot-0.0.1-SNAPSHOT-exec.jar --server.port=28080
4.2 驗證服務(wù)是否正常
curl -k --tlsv1 https://localhost:18080/v2/vue/api/programLanguage/getAll
curl -k --tlsv1 https://localhost:28080/v2/vue/api/programLanguage/getAll
返回:
["C","vue","java","PHP","Python","C++"]
如果正常返回數(shù)據(jù)即可。
4.3 重要概念
一個微服務(wù)可以通過 APISIX 的路由恩急、服務(wù)杉畜、上游和插件等多個實體之間的關(guān)系進行配置。 Route(路由)與客戶端請求匹配衷恭,并指定它們到達 APISIX 后如何發(fā)送到 Upstream(上游此叠,后端 API 服務(wù))。 Service(服務(wù))為上游服務(wù)提供了抽象匾荆。因此,您可以創(chuàng)建單個 Service 并在多個 Route 中引用它杆烁。
4.4 創(chuàng)建 APISIX Upstream(上游牙丽,后端 API 服務(wù))
APISIX Upstream,是虛擬主機抽象兔魂,對給定的多個服務(wù)節(jié)點按照配置規(guī)則進行負載均衡烤芦。它根據(jù)配置規(guī)則在給定的一組服務(wù)節(jié)點上執(zhí)行負載平衡。 因此析校,單個上游配置可以由提供相同服務(wù)的多個服務(wù)器組成构罗。每個節(jié)點將包括一個 key(地址/ip:port)和一個 value (節(jié)點的權(quán)重)铜涉。 服務(wù)可以通過輪詢或一致哈希(cHash)機制進行負載平衡。
配置路由時遂唧,可以直接設(shè)置 Upstream 信息芙代,也可以使用服務(wù)抽象來引用 Upstream 信息。
在 APISIX 控制臺的「Upstream」
菜單中盖彭,創(chuàng)建一個 APISIX Upstream纹烹。如下圖所示:
4.5 創(chuàng)建 APISIX Route
APISIX Route,字面意思就是路由召边,通過定義一些規(guī)則來匹配客戶端的請求铺呵,然后根據(jù)匹配結(jié)果加載并執(zhí)行相應(yīng)的 插件,并把請求轉(zhuǎn)發(fā)給到指定 Upstream隧熙。
4.6 測試
我們來請求 APISIX 網(wǎng)關(guān)地址+url片挂,轉(zhuǎn)發(fā)請求到后端服務(wù)。
4.6.1 瀏覽器訪問
地址:http://101.133.227.13:9080/v2/vue/api/programLanguage/getAll
贞盯,注意:101.133.227.13:9080
是APISIX 網(wǎng)關(guān)IP和端口號音念,不是Springboot微服務(wù)的。
返回錯誤:
Bad Request
This combination of host and port requires TLS.
默認情況下邻悬,Apache APISIX 通過 HTTP 協(xié)議代理請求症昏。如果我們的后端托管在 HTTPS 環(huán)境中,讓我們使用proxy-rewrite
插件將方案更改為 HTTPS父丰,記得點擊頁面下方保存
按鈕才能生效肝谭。
4.6.2 瀏覽器再次訪問
http://101.133.227.13:9080/v2/vue/api/programLanguage/getAll
,
或者命令行方式訪問curl -i -X GET "http://101.133.227.13:9080/v2/vue/api/programLanguage/getAll"
蛾扇。
正常返回結(jié)果:["C","vue","java","PHP","Python","C++"]
攘烛。
API 也可以通過 HTTPs(9443)端口服務(wù)訪問。如果您使用的是自簽名證書镀首,那么通過 curl 命令使用 -k 參數(shù)忽略自簽名證書錯誤坟漱。注意:使用了https和9443端口。
curl -i -k -X GET "https://101.133.227.13:9443/v2/vue/api/programLanguage/getAll"
五更哄、限流限速
APISIX 內(nèi)置了三個限流限速插件:
- limit-count:基于“固定窗口”的限速實現(xiàn)芋齿。
- limit-req:基于漏桶原理的請求限速實現(xiàn)。
- limit-conn:限制并發(fā)請求(或并發(fā)連接)成翩。
5.1 配置 limit-req 插件
本小節(jié)觅捆,我們來演示使用 limit-req 插件,畢竟基于漏桶的限流算法麻敌,是目前較為常用的限流方式栅炒。
我們已經(jīng)創(chuàng)建了一個 APISIX Route叭披。這里,我們給該 Route 配置下 limit-req 插件秀鞭。如下圖所示:漏桶算法(Leaky Bucket)是網(wǎng)絡(luò)世界中流量整形(Traffic Shaping)或速率限制(Rate Limiting)時經(jīng)常使用的一種算法,它的主要目的是控制數(shù)據(jù)注入到網(wǎng)絡(luò)的速率,平滑網(wǎng)絡(luò)上的突發(fā)流量赢赊。
漏桶算法提供了一種機制乙漓,通過它,突發(fā)流量可以被整形以便為網(wǎng)絡(luò)提供一個穩(wěn)定的流量释移。
5.1.1 屬性說明
- rate:指定的請求速率(以秒為單位)趋观,請求速率超過 rate 但沒有超過 (rate + brust)的請求會被加上延時
- burst:請求速率超過 (rate + brust)的請求會被直接拒絕
- rejected_code:當(dāng)請求超過閾值被拒絕時,返回的 HTTP 狀態(tài)碼
- key:是用來做請求計數(shù)的依據(jù)锋边,當(dāng)前接受的 key 有:"remote_addr"(客戶端 IP 地址), "server_addr"(服務(wù)端 IP 地址), 請求頭中的"X-Forwarded-For" 或 "X-Real-IP"皱坛。
上述截圖配置含義:限制了每秒請求速率為 1
,大于 1 小于 3
的會被加上延時豆巨,速率超過 3
就會被拒絕剩辟。
快速訪問返回包含 503 返回碼的響應(yīng)頭:
HTTP/1.1 503 Service Temporarily Unavailable
Content-Type: text/html
Content-Length: 194
Connection: keep-alive
Server: APISIX web server
<html>
<head><title>503 Service Temporarily Unavailable</title></head>
<body>
<center><h1>503 Service Temporarily Unavailable</h1></center>
<hr><center>openresty</center>
</body>
</html>
5.2 limit-conn
Apisix 的限制并發(fā)請求(或并發(fā)連接)插件。
5.2.1屬性:
- conn: 允許的最大并發(fā)請求數(shù)往扔。 超過這個比率的請求(低于“ conn” + “ burst”)將被延遲以符合這個閾值贩猎。
- burst: 允許延遲的過多并發(fā)請求(或連接)的數(shù)量。
- default_conn_delay: 默認的典型連接(或請求)的處理延遲時間萍膛。
- key: 用戶指定的限制并發(fā)級別的關(guān)鍵字吭服,可以是客戶端IP或服務(wù)端IP。
例如:可以使用主機名(或服務(wù)器區(qū)域)作為關(guān)鍵字蝗罗,以便限制每個主機名的并發(fā)性艇棕。 另外,我們也可以使用客戶端地址作為關(guān)鍵字串塑,這樣我們就可以避免單個客戶端用太多的并行連接或請求淹沒我們的服務(wù)沼琉。
現(xiàn)在接受以下關(guān)鍵字: “remote_addr”(客戶端的 IP),“server_addr”(服務(wù)器的 IP)桩匪,請* 求頭中的“ X-Forwarded-For/X-Real-IP”打瘪。 - rejected_code: 當(dāng)請求超過閾值時返回的 HTTP狀態(tài)碼, 默認值是503傻昙。
5.2.2 在 route 頁面中添加 limit-conn 插件
上面啟用的插件的參數(shù)表示只允許一個并發(fā)請求闺骚。 當(dāng)收到多個并發(fā)請求時,將直接返回 503 拒絕請求妆档。
5.2.3 測試
為了區(qū)別limit-req返回的503錯誤僻爽,可以返回碼臨時改成504。
訪問不同的url模擬并發(fā):
https://101.133.227.13:9443/v2/vue/api/programLanguage/getAll
和
https://101.133.227.13:9443/v2/vue/api/programLanguage/getAll?param=value
返回:
504 Gateway Time-out
六过吻、 身份驗證
APISIX 內(nèi)置了四個身份驗證插件:
- key-auth:基于 Key Authentication 的用戶認證进泼。
- JWT-auth:基于 JWT (JSON Web Tokens) Authentication 的用戶認證。
- basic-auth:基于 basic auth 的用戶認證纤虽。
- wolf-rbac:基于 RBAC 的用戶認證及授權(quán)乳绕。需要額外搭建 wolf 服務(wù),提供用戶逼纸、角色洋措、資源等信息。
本小節(jié)杰刽,我們來演示使用 JWT-auth 插件菠发。
6.1 配置 JWT-auth 插件
在 APISIX 控制臺的「Consumer」菜單中,創(chuàng)建一個 APISIX Consumer贺嫂,Consumer 是某類服務(wù)的消費者滓鸠,需與用戶認證體系配合才能使用。添加 JWT Authentication 到一個 service 或 route第喳。 然后 consumer 將其密鑰添加到查詢字符串參數(shù)糜俗、請求頭或 cookie 中以驗證其請求。
6.1.1 屬性
- key: 不同的 consumer 對象應(yīng)有不同的值曲饱,它應(yīng)當(dāng)是唯一的悠抹。不同 consumer 使用了相同的 key ,將會出現(xiàn)請求匹配異常扩淀。
- secret: 可選字段楔敌,加密秘鑰。如果您未指定驻谆,后臺將會自動幫您生成卵凑。
- algorithm:可選字段,加密算法旺韭。目前支持 HS256, HS384, HS512, RS256 和 ES256氛谜,如果未指定,則默認使用 HS256区端。
- exp: 可選字段值漫,token 的超時時間,以秒為單位的計時织盼。比如有效期是 5 分鐘杨何,那么就應(yīng)設(shè)置為 5 * 60 = 300。
6.1.2 consumer使用 JWT-auth 插件
如下圖所示:6.1.3 Route使用 JWT-auth 插件
我們已經(jīng)創(chuàng)建了一個 APISIX Route沥邻。這里危虱,我們給該 Route 配置下 JWT-auth 插件。如下圖所示:
配置過程很奇怪唐全,官方文檔也沒怎么說明埃跷。
6.1.3 測試
調(diào)用 jwt-auth 插件提供的簽名接口蕊玷,獲取 Token。
# key 參數(shù)弥雹,為我們配置 jwt-auth 插件時垃帅,設(shè)置的 key 屬性。
curl -i -k -X GET https://101.133.227.13:9443/apisix/plugin/jwt/sign?key=erbadagang
eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJlcmJhZGFnYW5nIiwiZXhwIjoxNTk1ODQxNjM3fQ.TyTsIDMGe8bHeXBtZ_6VjnDabbVGTZ7vHGh-PwLIixFkrXkKWLGvN1v6mlKoNCm_ccfTqU9n8h7QDeWdQZMIsA
6.1.3.1 正常情況
使用 Postman 模擬調(diào)用示例 https://101.133.227.13:9443/v2/vue/api/programLanguage/getAll
接口剪勿,并附帶上 JWT贸诚。如下圖所示:
6.1.3.2 如果缺少token訪問會返回
{"message":"Missing JWT token in request"}
6.1.3.3 token 放到請求參數(shù)中
https://101.133.227.13:9443/v2/vue/api/programLanguage/getAll?jwt=eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJlcmJhZGFnYW5nIiwiZXhwIjoxNTk1ODQyMTg3fQ.KwOVcSIbo9hOk4Kije8tSdUSZIZ8c-ceViGrZpF6pvhZ7Ky6MZYhsDvoGVWvP9TK0FB-G0TPH_ankkiFFv7htw
6.1.3..4 token過期
{"message":"'exp' claim expired at Mon, 27 Jul 2020 09:20:37 GMT"}
七、配置證書
https://gitee.com/iresty/apisix/blob/master/doc/https-cn.md
八厕吉、健康檢查
支持對上游節(jié)點的主動和被動健康檢查酱固,在負載均衡時自動過濾掉不健康的節(jié)點。
由于控制臺dashboard沒有健康檢查的配置項头朱,所以需要通過APISIX api方式在服務(wù)端執(zhí)行如下語句运悲。
使用 REST Admin API 來控制 Apache APISIX,默認只允許 127.0.0.1 訪問项钮,你可以修改 conf/config.yaml 中的 allow_admin 字段扇苞,指定允許調(diào)用 Admin API 的 IP 列表。同時需要注意的是寄纵,Admin API 使用 key auth 來校驗調(diào)用者身份鳖敷,在部署前需要修改 conf/config.yaml 中的 admin_key 字段,來保證安全程拭。
8.1 Xshell登錄服務(wù)器執(zhí)行
# 配置上游節(jié)點負載均衡+健康檢查demo
curl http://127.0.0.1:9080/apisix/admin/routes/016 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"uris": ["/*"],
"plugins": {
"limit-count": {
"count": 2,
"time_window": 60,
"rejected_code": 503,
"key": "remote_addr"
},
"proxy-rewrite": {
"scheme": "https"
}
},
"upstream": {
"desc": "guoxiuzhi_upstream",
"nodes": {
"127.0.0.1:18080": 1,
"127.0.0.1:28080": 2
},
"type": "roundrobin",
"retries": 2,
"checks": {
"active": {
"http_path": "/status",
"healthy": {
"interval": 2,
"successes": 1
},
"unhealthy": {
"interval": 1,
"http_failures": 2
},
"req_headers": ["User-Agent: curl/7.29.0"]
},
"passive": {
"healthy": {
"http_statuses": [200, 201],
"successes": 3
},
"unhealthy": {
"http_statuses": [500],
"http_failures": 3,
"tcp_failures": 3
}
}
}
}
}'
注意:
- 由于我們的后端springboot是https訪問的定踱,所以配置了
proxy-rewrite
插件的schema
,官方文檔和api調(diào)用的單詞拼寫錯誤都是scheme
恃鞋,所以要將錯就錯崖媚。 - X-API-KEY: edd1c9f034335f136f87ad84b625c8f1是admin賬號的key,可以在
conf\config.yaml
的找到對應(yīng)的值恤浪。
name: "admin"
key: edd1c9f034335f136f87ad84b625c8f1
role: admin
8.2 成功執(zhí)行上面語句后輸出
{"node":{"value":{"priority":0,"plugins":{"limit-count":{"time_window":60,"count":2,"rejected_code":503,"key":"remote_addr","policy":"local"},"proxy-rewrite":{"scheme":"https"}},"uris":["\/*"],"upstream":{"retries":2,"hash_on":"vars","type":"roundrobin","nodes":{"127.0.0.1:18080":1,"127.0.0.1:28080":2},"desc":"guoxiuzhi_upstream","checks":{"active":{"unhealthy":{"http_statuses":[429,404,500,501,502,503,504,505],"interval":1,"timeouts":3,"http_failures":2,"tcp_failures":2},"concurrency":10,"http_path":"\/status","healthy":{"successes":1,"interval":2,"http_statuses":[200,302]},"req_headers":["User-Agent: curl\/7.29.0"],"https_verify_certificate":true,"timeout":1,"type":"http"},"passive":{"unhealthy":{"http_failures":3,"http_statuses":[500],"tcp_failures":3,"timeouts":7},"healthy":{"http_statuses":[200,201],"successes":3},"type":"http"}}}},"createdIndex":37,"key":"\/apisix\/routes\/016","modifiedIndex":37},"prevNode":{"value":"{\"priority\":0,\"plugins\":{\"limit-count\":{\"time_window\":60,\"count\":2,\"rejected_code\":503,\"key\":\"remote_addr\",\"policy\":\"local\"},\"proxy-rewrite\":{\"scheme\":\"https\"}},\"uris\":[\"\\\/*\"],\"upstream\":{\"retries\":2,\"nodes\":{\"127.0.0.1:18080\":1,\"127.0.0.1:28080\":2},\"hash_on\":\"vars\",\"checks\":{\"active\":{\"unhealthy\":{\"http_statuses\":[429,404,500,501,502,503,504,505],\"interval\":1,\"timeouts\":3,\"http_failures\":2,\"tcp_failures\":2},\"type\":\"http\",\"http_path\":\"\\\/status\",\"healthy\":{\"successes\":1,\"interval\":2,\"http_statuses\":[200,302]},\"req_headers\":[\"User-Agent: curl\\\/7.29.0\"],\"timeout\":1,\"https_verify_certificate\":true,\"concurrency\":10},\"passive\":{\"unhealthy\":{\"http_failures\":3,\"http_statuses\":[500],\"tcp_failures\":3,\"timeouts\":7},\"type\":\"http\",\"healthy\":{\"successes\":3,\"http_statuses\":[200,201]}}},\"desc\":\"guoxiuzhi_upstream\",\"type\":\"roundrobin\"}}","createdIndex":36,"key":"\/apisix\/routes\/016","modifiedIndex":36},"action":"set"}
8.3 使配置熱部署執(zhí)行
curl http://127.0.0.1:9080/apisix/admin/plugins/reload -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT
返回:
done
8.4 查看狀態(tài)
http://101.133.227.13:9080/apisix/status
返回