AVt天堂网 手机版,亚洲va久久久噜噜噜久久4399,天天综合亚洲色在线精品,亚洲一级Av无码毛片久久精品

當(dāng)前位置:首頁(yè) > 科技  > 軟件

Envoy 基礎(chǔ)入門(mén)教程,看這一篇就夠了

來(lái)源: 責(zé)編: 時(shí)間:2023-10-30 09:07:16 316觀(guān)看
導(dǎo)讀Envoy 是一個(gè)用 C++ 開(kāi)發(fā)的高性能代理,Envoy 是一種 L7 代理和通信總線(xiàn),專(zhuān)為大型的現(xiàn)代面向服務(wù)的架構(gòu)而設(shè)計(jì)。核心能力Envoy 的誕生源于以下理念:網(wǎng)絡(luò)對(duì)于應(yīng)用程序來(lái)說(shuō)應(yīng)該是透明的,當(dāng)網(wǎng)絡(luò)和應(yīng)用程序出現(xiàn)問(wèn)題時(shí),應(yīng)該很容

qtF28資訊網(wǎng)——每日最新資訊28at.com

Envoy 是一個(gè)用 C++ 開(kāi)發(fā)的高性能代理,Envoy 是一種 L7 代理和通信總線(xiàn),專(zhuān)為大型的現(xiàn)代面向服務(wù)的架構(gòu)而設(shè)計(jì)。qtF28資訊網(wǎng)——每日最新資訊28at.com

核心能力

Envoy 的誕生源于以下理念:qtF28資訊網(wǎng)——每日最新資訊28at.com

網(wǎng)絡(luò)對(duì)于應(yīng)用程序來(lái)說(shuō)應(yīng)該是透明的,當(dāng)網(wǎng)絡(luò)和應(yīng)用程序出現(xiàn)問(wèn)題時(shí),應(yīng)該很容易確定問(wèn)題的源頭。qtF28資訊網(wǎng)——每日最新資訊28at.com

當(dāng)然要實(shí)現(xiàn)上述目標(biāo)是非常困難的。Envoy 試圖通過(guò)提供以下高級(jí)功能來(lái)實(shí)現(xiàn)這一目標(biāo):qtF28資訊網(wǎng)——每日最新資訊28at.com

非侵入架構(gòu): Envoy 是一個(gè)獨(dú)立的進(jìn)程,設(shè)計(jì)為伴隨每個(gè)應(yīng)用程序服務(wù)一起運(yùn)行。所有 Envoy 實(shí)例形成一個(gè)透明的通信網(wǎng)格,每個(gè)應(yīng)用程序通過(guò) localhost 發(fā)送和接收消息,不需要知道網(wǎng)絡(luò)拓?fù)洹?duì)服務(wù)的實(shí)現(xiàn)語(yǔ)言也完全無(wú)感知,這種模式也被稱(chēng)為 Sidecar 模式。qtF28資訊網(wǎng)——每日最新資訊28at.com

L3/L4 過(guò)濾器架構(gòu): Envoy 的核心是一個(gè) L3/L4 層的網(wǎng)絡(luò)代理。可插拔的過(guò)濾器鏈機(jī)制允許編寫(xiě)不同的 TCP/UDP 代理任務(wù)的過(guò)濾器,并將其插入到主服務(wù)器中。而且已經(jīng)內(nèi)置支持了各種任務(wù)的過(guò)濾器,例如原始 TCP 代理、UDP 代理、HTTP 代理、TLS 客戶(hù)端證書(shū)身份驗(yàn)證、Redis、MongoDB、Postgres 等。qtF28資訊網(wǎng)——每日最新資訊28at.com

HTTP L7 過(guò)濾器架構(gòu): HTTP 是現(xiàn)代應(yīng)用程序架構(gòu)的關(guān)鍵組件,因此 Envoy 支持了一個(gè)額外的 HTTP L7 過(guò)濾器層。HTTP 過(guò)濾器可以被插入到 HTTP 連接管理子系統(tǒng)中,執(zhí)行不同的任務(wù),如緩存、速率限制、路由/轉(zhuǎn)發(fā)、嗅探 Amazon 的 DynamoDB 等。qtF28資訊網(wǎng)——每日最新資訊28at.com

頂級(jí)的 HTTP/2 支持: 在 HTTP 模式下運(yùn)行時(shí),Envoy 同時(shí)支持 HTTP/1.1 和 HTTP/2。Envoy 可以作為透明的 HTTP/1.1 到 HTTP/2 雙向代理運(yùn)行。這意味著可以連接任何組合的 HTTP/1.1 和 HTTP/2 客戶(hù)端與目標(biāo)服務(wù)器。推薦的服務(wù)到服務(wù)配置在所有 Envoy 之間使用 HTTP/2 創(chuàng)建持久連接網(wǎng)格,請(qǐng)求和響應(yīng)可以在該連接上進(jìn)行多路復(fù)用。qtF28資訊網(wǎng)——每日最新資訊28at.com

HTTP/3 支持(目前處于 alpha 版): 從 Envoy 1.19.0 版本開(kāi)始,Envoy 現(xiàn)在支持上游和下游的 HTTP/3,而且可以在任何方向上進(jìn)行 HTTP/1.1、HTTP/2 和 HTTP/3 之間的轉(zhuǎn)換。qtF28資訊網(wǎng)——每日最新資訊28at.com

HTTP L7 路由: 在 HTTP 模式下運(yùn)行時(shí),Envoy 支持路由子系統(tǒng),該子系統(tǒng)能夠根據(jù)路徑、權(quán)限、內(nèi)容類(lèi)型、運(yùn)行時(shí)值等路由和重定向請(qǐng)求。在使用 Envoy 作為前端/邊緣代理時(shí),此功能非常有用,但在構(gòu)建服務(wù)到服務(wù)的網(wǎng)格時(shí)也可以利用它。qtF28資訊網(wǎng)——每日最新資訊28at.com

gRPC 支持: gRPC 是 Google 的一個(gè) RPC 框架,使用 HTTP/2 或更高版本作為底層多路復(fù)用傳輸。Envoy 支持用作 gRPC 請(qǐng)求和響應(yīng)的路由和負(fù)載均衡基礎(chǔ)所需的所有 HTTP/2 功能,這兩個(gè)系統(tǒng)非常互補(bǔ)。qtF28資訊網(wǎng)——每日最新資訊28at.com

服務(wù)發(fā)現(xiàn)和動(dòng)態(tài)配置: Envoy 可以選擇使用一組分層的動(dòng)態(tài)配置 API 來(lái)進(jìn)行集中管理。這些層向 Envoy 提供了關(guān)于后端集群中的主機(jī)、后端集群自身、HTTP 路由、監(jiān)聽(tīng)套接字和加密材料的動(dòng)態(tài)更新。對(duì)于更簡(jiǎn)單的部署,可以通過(guò) DNS 解析(甚至完全跳過(guò))來(lái)完成后端主機(jī)發(fā)現(xiàn),并且進(jìn)一步的層可以由靜態(tài)配置文件替代。qtF28資訊網(wǎng)——每日最新資訊28at.com

健康檢查: 構(gòu)建 Envoy 網(wǎng)格的推薦方法是將服務(wù)發(fā)現(xiàn)視為最終一致的過(guò)程。Envoy 包含一個(gè)健康檢查子系統(tǒng),可以選擇對(duì)上游服務(wù)集群執(zhí)行主動(dòng)健康檢查。然后,Envoy 使用服務(wù)發(fā)現(xiàn)和健康檢查信息的結(jié)合來(lái)確定健康的負(fù)載均衡目標(biāo)。Envoy 還通過(guò)異常值檢測(cè)子系統(tǒng)支持被動(dòng)健康檢查。qtF28資訊網(wǎng)——每日最新資訊28at.com

高級(jí)負(fù)載均衡: 分布式系統(tǒng)中不同組件之間的負(fù)載均衡是一個(gè)復(fù)雜的問(wèn)題。由于 Envoy 是一個(gè)獨(dú)立的代理而不是庫(kù),因此可以獨(dú)立實(shí)現(xiàn)高級(jí)負(fù)載均衡以供任何應(yīng)用程序訪(fǎng)問(wèn)。目前 Envoy 支持自動(dòng)重試、熔斷、通過(guò)外部速率限制服務(wù)進(jìn)行全局速率限制、異常檢測(cè)等。qtF28資訊網(wǎng)——每日最新資訊28at.com

前端/邊緣代理支持: 在邊緣使用相同的軟件有很大的好處(可觀(guān)察性、管理、相同的服務(wù)發(fā)現(xiàn)和負(fù)載均衡算法等)。Envoy 的功能集使其非常適合作為大多數(shù)現(xiàn)代 Web 應(yīng)用程序用例的邊緣代理。這包括 TLS 終止、HTTP/1.1、HTTP/2 和 HTTP/3 支持以及 HTTP L7 路由。qtF28資訊網(wǎng)——每日最新資訊28at.com

最佳的可觀(guān)測(cè)性: 如上所述,Envoy 的主要目標(biāo)是使網(wǎng)絡(luò)透明化。但是,問(wèn)題在網(wǎng)絡(luò)層面和應(yīng)用層面都可能會(huì)出現(xiàn)。Envoy 為所有子系統(tǒng)提供了強(qiáng)大的統(tǒng)計(jì)支持。目前支持的統(tǒng)計(jì)數(shù)據(jù)輸出端是 statsd(以及兼容的提供程序),但是接入其他不同的統(tǒng)計(jì)數(shù)據(jù)輸出端并不困難。統(tǒng)計(jì)數(shù)據(jù)也可以通過(guò)管理端口進(jìn)行查看,Envoy 還支持通過(guò)第三方提供者進(jìn)行分布式跟蹤。qtF28資訊網(wǎng)——每日最新資訊28at.com

常用術(shù)語(yǔ)

在我們介紹 Envoy 架構(gòu)之前,有必要先介紹一些常用的術(shù)語(yǔ)定義,因?yàn)檫@些術(shù)語(yǔ)貫穿整個(gè) Envoy 的架構(gòu)設(shè)計(jì)。qtF28資訊網(wǎng)——每日最新資訊28at.com

  • Host(主機(jī)): 能夠進(jìn)行網(wǎng)絡(luò)通信的實(shí)體(手機(jī)、服務(wù)器等上的應(yīng)用程序)。在 Envoy 中主機(jī)是邏輯網(wǎng)絡(luò)應(yīng)用程序。一個(gè)物理硬件可能運(yùn)行多個(gè)主機(jī),只要每個(gè)主機(jī)可以獨(dú)立進(jìn)行尋址。
  • Downstream(下游): 下游主機(jī)連接到 Envoy,發(fā)送請(qǐng)求并接收響應(yīng)。
  • Upstream(上游): 上游主機(jī)接收來(lái)自 Envoy 的連接和請(qǐng)求并返回響應(yīng)。
  • Listener(偵聽(tīng)器): 偵聽(tīng)器是一個(gè)帶有名稱(chēng)的網(wǎng)絡(luò)位置(例如端口、unix domain socket 等),下游客戶(hù)端可以連接到該位置。Envoy 暴露一個(gè)或多個(gè)監(jiān)聽(tīng)器,供下游主機(jī)連接。
  • Cluster(集群): 一個(gè)集群是一組邏輯上相似的上游主機(jī),Envoy 連接到這些主機(jī)。Envoy 通過(guò)服務(wù)發(fā)現(xiàn)來(lái)發(fā)現(xiàn)集群的成員。它還可以通過(guò)主動(dòng)健康檢查來(lái)確定集群成員的健康狀況。Envoy 根據(jù)負(fù)載均衡策略確定將請(qǐng)求路由到哪個(gè)集群成員。
  • Mesh(網(wǎng)格): 一組主機(jī)協(xié)同工作,提供一致的網(wǎng)絡(luò)拓?fù)浣Y(jié)構(gòu)。在這里 Envoy Mesh 是指一組 Envoy 代理,它們構(gòu)成了由多種不同服務(wù)和應(yīng)用程序平臺(tái)組成的分布式系統(tǒng)的消息傳遞基礎(chǔ)。
  • Runtime configuration(運(yùn)行時(shí)配置): 與 Envoy 一起部署的實(shí)時(shí)配置系統(tǒng)。可以更改配置設(shè)置,影響操作而無(wú)需重新啟動(dòng) Envoy 或更改主要配置。

架構(gòu)設(shè)計(jì)

Envoy 采用單進(jìn)程多線(xiàn)程架構(gòu)。qtF28資訊網(wǎng)——每日最新資訊28at.com

一個(gè)獨(dú)立的 primary 線(xiàn)程負(fù)責(zé)控制各種零散的協(xié)調(diào)任務(wù),而一些 worker 線(xiàn)程則負(fù)責(zé)執(zhí)行監(jiān)聽(tīng)、過(guò)濾和轉(zhuǎn)發(fā)任務(wù)。qtF28資訊網(wǎng)——每日最新資訊28at.com

一旦偵聽(tīng)器接受連接,該連接就會(huì)將其生命周期綁定到一個(gè)單獨(dú)的 worker 線(xiàn)程。這使得 Envoy 的大部分工作基本上是單線(xiàn)程來(lái)處理的,只有少量更復(fù)雜的代碼處理工作線(xiàn)程之間的協(xié)調(diào)。qtF28資訊網(wǎng)——每日最新資訊28at.com

通常情況下 Envoy 實(shí)現(xiàn)了 100% 非阻塞。對(duì)于大多數(shù)工作負(fù)載,我們建議將 worker 線(xiàn)程的數(shù)量配置為機(jī)器上的硬件線(xiàn)程數(shù)量。qtF28資訊網(wǎng)——每日最新資訊28at.com

Envoy 整體架構(gòu)如下圖所示:qtF28資訊網(wǎng)——每日最新資訊28at.com

qtF28資訊網(wǎng)——每日最新資訊28at.com

Envoy 架構(gòu)qtF28資訊網(wǎng)——每日最新資訊28at.com

Envoy 進(jìn)程中運(yùn)行著一系列 Inbound/Outbound 監(jiān)聽(tīng)器(Listener),Inbound 代理入站流量,Outbound 代理出站流量。Listener 的核心就是過(guò)濾器鏈(FilterChain),鏈中每個(gè)過(guò)濾器都能夠控制流量的處理流程。qtF28資訊網(wǎng)——每日最新資訊28at.com

Envoy 接收到請(qǐng)求后,會(huì)先走 FilterChain,通過(guò)各種 L3/L4/L7 Filter 對(duì)請(qǐng)求進(jìn)行處理,然后再路由到指定的集群,并通過(guò)負(fù)載均衡獲取一個(gè)目標(biāo)地址,最后再轉(zhuǎn)發(fā)出去。qtF28資訊網(wǎng)——每日最新資訊28at.com

其中每一個(gè)環(huán)節(jié)可以靜態(tài)配置,也可以動(dòng)態(tài)服務(wù)發(fā)現(xiàn),也就是所謂的 xDS,這里的 x 是一個(gè)代詞,是 lds、rds、cds、eds、sds 的總稱(chēng),即服務(wù)發(fā)現(xiàn),后 2 個(gè)字母 ds 就是 discovery service。qtF28資訊網(wǎng)——每日最新資訊28at.com

第一個(gè) Envoy 代理

下面我們通過(guò)一個(gè)簡(jiǎn)單的示例來(lái)介紹 Envoy 的基本使用。qtF28資訊網(wǎng)——每日最新資訊28at.com

配置

Envoy 使用 YAML 文件來(lái)控制代理的行為,整體配置結(jié)構(gòu)如下:qtF28資訊網(wǎng)——每日最新資訊28at.com

listen -- 監(jiān)聽(tīng)器    1.我監(jiān)聽(tīng)的地址    2.過(guò)濾鏈        filter1            路由: 轉(zhuǎn)發(fā)到哪里                virtual_hosts                    只轉(zhuǎn)發(fā)什么                    轉(zhuǎn)發(fā)到哪里 --> 由后面的 cluster 來(lái)定義        filter2        filter3        # envoyproxy.io/docs/envoy/v1.28.0/api-v3/config/filter/filtercluster    轉(zhuǎn)發(fā)規(guī)則    endpoints        --指定了我的后端地址

接下來(lái)我們就來(lái)創(chuàng)建一個(gè)簡(jiǎn)單的 Envoy 代理,它監(jiān)聽(tīng) 10000 端口,將請(qǐng)求轉(zhuǎn)發(fā)到 www.baidu.com 的 80 端口。在下面的步驟中,我們將使用靜態(tài)配置接口來(lái)構(gòu)建配置,也意味著所有設(shè)置都是預(yù)定義在配置文件中的。此外 Envoy 也支持動(dòng)態(tài)配置,這樣可以通過(guò)外部一些源來(lái)自動(dòng)發(fā)現(xiàn)進(jìn)行設(shè)置。qtF28資訊網(wǎng)——每日最新資訊28at.com

Envoy 代理使用開(kāi)源 xDS API 來(lái)交換信息,目前 xDS v2 已被廢棄,最新版本的 Envoy 不再支持 xDS v2,建議使用 xDS v3。qtF28資訊網(wǎng)——每日最新資訊28at.com

創(chuàng)建一個(gè)名為 envoy-1.yaml 的文件,在 Envoy 配置的第一行定義正在使用的接口配置,在這里我們將配置靜態(tài) API,因此第一行應(yīng)為 static_resources:qtF28資訊網(wǎng)——每日最新資訊28at.com

static_resources:

然后需要在靜態(tài)配置下面定義 Envoy 的監(jiān)聽(tīng)器(Listener),監(jiān)聽(tīng)器是 Envoy 監(jiān)聽(tīng)請(qǐng)求的網(wǎng)絡(luò)配置,例如 IP 地址和端口。我們這里設(shè)置監(jiān)聽(tīng) IP 地址為 0.0.0.0,并在端口 10000 上進(jìn)行監(jiān)聽(tīng)。對(duì)應(yīng)的監(jiān)聽(tīng)器的配置為qtF28資訊網(wǎng)——每日最新資訊28at.com

static_resources:  listeners:    - name: listener_0 # 監(jiān)聽(tīng)器的名稱(chēng)      address:        socket_address:          address: 0.0.0.0 # 監(jiān)聽(tīng)器的地址          port_value: 10000 # 監(jiān)聽(tīng)器的端口

通過(guò) Envoy 監(jiān)聽(tīng)傳入的流量,下一步是定義如何處理這些請(qǐng)求。每個(gè)監(jiān)聽(tīng)器都有一組過(guò)濾器,并且不同的監(jiān)聽(tīng)器可以具有一組不同的過(guò)濾器。qtF28資訊網(wǎng)——每日最新資訊28at.com

在我們這個(gè)示例中,我們將所有流量代理到 baidu.com,配置完成后我們應(yīng)該能夠通過(guò)請(qǐng)求 Envoy 的端點(diǎn)就可以直接看到百度的主頁(yè)了,而無(wú)需更改 URL 地址。qtF28資訊網(wǎng)——每日最新資訊28at.com

過(guò)濾器是通過(guò) filter_chains 來(lái)定義的,每個(gè)過(guò)濾器的目的是找到傳入請(qǐng)求的匹配項(xiàng),以使其與目標(biāo)地址進(jìn)行匹配。Filter 過(guò)濾器的寫(xiě)法如下所示:qtF28資訊網(wǎng)——每日最新資訊28at.com

name: 指定使用哪個(gè)過(guò)濾器typed_config:  "@type": type.googleapis.com/envoy.過(guò)濾器的具體值  參數(shù)1:值1  參數(shù)2:值2  。。。這里選擇什么參數(shù),要看name里選擇的什么參數(shù)要根據(jù)所選擇的過(guò)濾器來(lái)判定和 http 相關(guān)的,一般選擇 HTTP connection manager。在 https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/filter/filter 里找參數(shù)name 的位置應(yīng)該寫(xiě) envoy.filterswork.http_connection_manager@type 的值到文檔里找具體的值

比如我們這里的配置如下所示:qtF28資訊網(wǎng)——每日最新資訊28at.com

static_resources:  listeners:    - name: listener_0 # 監(jiān)聽(tīng)器的名稱(chēng)      address:        socket_address:          address: 0.0.0.0 # 監(jiān)聽(tīng)器的地址          port_value: 10000 # 監(jiān)聽(tīng)器的端口      filter_chains: # 配置過(guò)濾器鏈        # 在此地址收到的任何請(qǐng)求都會(huì)通過(guò)這一系列過(guò)濾鏈發(fā)送。        - filters:            # 指定要使用哪個(gè)過(guò)濾器,下面是envoy內(nèi)置的網(wǎng)絡(luò)過(guò)濾器,如果請(qǐng)求是 HTTP 它將通過(guò)此 HTTP 過(guò)濾器            # 該過(guò)濾器將原始字節(jié)轉(zhuǎn)換為HTTP級(jí)別的消息和事件(例如接收到的header、接收到的正文數(shù)據(jù)等)            # 它還處理所有HTTP連接和請(qǐng)求中常見(jiàn)的功能,例如訪(fǎng)問(wèn)日志記錄、請(qǐng)求ID生成和跟蹤、請(qǐng)求/響應(yīng)頭操作、路由表管理和統(tǒng)計(jì)信息。            - name: envoy.filterswork.http_connection_manager              typed_config:                # 需要配置下面的類(lèi)型,啟用 http_connection_manager                "@type": type.googleapis.com/envoy.extensions.filterswork.http_connection_manager.v3.HttpConnectionManager                stat_prefix: ingress_http                access_log: # 連接管理器發(fā)出的 HTTP 訪(fǎng)問(wèn)日志的配置                  - name: envoy.access_loggers.stdout # 輸出到stdout                    typed_config:                      "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog                http_filters: # 定義http過(guò)濾器鏈                  - name: envoy.filters.http.router # 調(diào)用7層的路由過(guò)濾器                    typed_config:                      "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router                route_config:                  name: local_route                  virtual_hosts:                    - name: local_service                      domains: ["*"] # 要匹配的主機(jī)名列表,*表示匹配所有主機(jī)                      routes:                        - match:                            prefix: "/" # 要匹配的 URL 前綴                          route: # 路由規(guī)則,發(fā)送請(qǐng)求到 service_baidu 集群                            host_rewrite_literal: www.baidu.com # 更改 HTTP 請(qǐng)求的入站 Host 頭信息                            cluster: service_baidu # 將要處理請(qǐng)求的集群名稱(chēng),下面會(huì)有相應(yīng)的實(shí)現(xiàn)

這里我們使用的過(guò)濾器使用了 envoy.filterswork.http_connection_manager,這是為 HTTP 連接設(shè)計(jì)的一個(gè)內(nèi)置過(guò)濾器,該過(guò)濾器將原始字節(jié)轉(zhuǎn)換為 HTTP 級(jí)別的消息和事件(例如接收到的 header、接收到的正文數(shù)據(jù)等),它還處理所有 HTTP 連接和請(qǐng)求中常見(jiàn)的功能,例如訪(fǎng)問(wèn)日志記錄、請(qǐng)求 ID 生成和跟蹤、請(qǐng)求/響應(yīng)頭操作、路由表管理和統(tǒng)計(jì)信息。qtF28資訊網(wǎng)——每日最新資訊28at.com

  • stat_prefix:為連接管理器發(fā)出統(tǒng)計(jì)信息時(shí)使用的一個(gè)前綴。
  • route_config:路由配置,如果虛擬主機(jī)匹配上了則檢查路由。在我們這里的配置中,無(wú)論請(qǐng)求的主機(jī)域名是什么,route_config 都匹配所有傳入的 HTTP 請(qǐng)求。
  • routes:如果 URL 前綴匹配,則一組路由規(guī)則定義了下一步將發(fā)生的狀況。/ 表示匹配根路由。
  • host_rewrite_literal:更改 HTTP 請(qǐng)求的入站 Host 頭信息。
  • cluster: 將要處理請(qǐng)求的集群名稱(chēng),下面會(huì)有相應(yīng)的實(shí)現(xiàn)。
  • http_filters: 該過(guò)濾器允許 Envoy 在處理請(qǐng)求時(shí)去適應(yīng)和修改請(qǐng)求。

當(dāng)請(qǐng)求于過(guò)濾器匹配時(shí),該請(qǐng)求將會(huì)傳遞到集群。下面的配置就是將主機(jī)定義為訪(fǎng)問(wèn) HTTPS 的 baidu.com 域名,如果定義了多個(gè)主機(jī),則 Envoy 將執(zhí)行輪詢(xún)(Round Robin)策略。配置如下所示:qtF28資訊網(wǎng)——每日最新資訊28at.com

clusters:  - name: service_baidu # 集群的名稱(chēng),與上面的 router 中的 cluster 對(duì)應(yīng)    type: LOGICAL_DNS # 用于解析集群(生成集群端點(diǎn))時(shí)使用的服務(wù)發(fā)現(xiàn)類(lèi)型,可用值有STATIC、STRICT_DNS 、LOGICAL_DNS、ORIGINAL_DST和EDS等;    connect_timeout: 0.25s    dns_lookup_family: V4_ONLY    lb_policy: ROUND_ROBIN # 負(fù)載均衡算法,支持ROUND_ROBIN、LEAST_REQUEST、RING_HASH、RANDOM、MAGLEV和CLUSTER_PROVIDED;    load_assignment: # 以前的 v2 版本的 hosts 字段廢棄了,現(xiàn)在使用 load_assignment 來(lái)定義集群的成員,指定 STATIC、STRICT_DNS 或 LOGICAL_DNS 集群的成員需要設(shè)置此項(xiàng)。      cluster_name: service_baidu # 集群的名稱(chēng)      endpoints: # 需要進(jìn)行負(fù)載均衡的端點(diǎn)列表        - lb_endpoints:            - endpoint:                address:                  socket_address:                    address: www.baidu.com                    port_value: 443    transport_socket: # 用于與上游集群通信的傳輸層配置      name: envoy.transport_sockets.tls # tls 傳輸層      typed_config:        "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext        sni: www.baidu.com

最后,還需要配置一個(gè)管理模塊:qtF28資訊網(wǎng)——每日最新資訊28at.com

admin:  access_log_path: /tmp/admin_access.log  address:    socket_address:      address: 0.0.0.0      port_value: 9901

上面的配置定義了 Envoy 的靜態(tài)配置模板,監(jiān)聽(tīng)器定義了 Envoy 的端口和 IP 地址,監(jiān)聽(tīng)器具有一組過(guò)濾器來(lái)匹配傳入的請(qǐng)求,匹配請(qǐng)求后,將請(qǐng)求轉(zhuǎn)發(fā)到集群,完整的配置如下所示:qtF28資訊網(wǎng)——每日最新資訊28at.com

# envoy-1.yamladmin:  access_log_path: /tmp/admin_access.log  address:    socket_address:      address: 0.0.0.0      port_value: 9901static_resources:  listeners:    - name: listener_0 # 監(jiān)聽(tīng)器的名稱(chēng)      address:        socket_address:          address: 0.0.0.0 # 監(jiān)聽(tīng)器的地址          port_value: 10000 # 監(jiān)聽(tīng)器的端口      filter_chains: # 配置過(guò)濾器鏈        - filters:            # 過(guò)濾器配置的名稱(chēng),要填寫(xiě) typed_config 配置的過(guò)濾器指定的名稱(chēng)            - name: envoy.filterswork.http_connection_manager              typed_config:                # 啟用 http_connection_manager                "@type": type.googleapis.com/envoy.extensions.filterswork.http_connection_manager.v3.HttpConnectionManager                stat_prefix: ingress_http                access_log:                  - name: envoy.access_loggers.stdout                    typed_config:                      "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog                http_filters: # 定義http過(guò)濾器鏈                  - name: envoy.filters.http.router # 調(diào)用7層的路由過(guò)濾器                    typed_config:                      "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router                route_config:                  name: local_route                  virtual_hosts:                    - name: local_service                      domains: ["*"]                      routes:                        - match:                            prefix: "/"                          route:                            host_rewrite_literal: www.baidu.com                            cluster: service_baidu  clusters:    - name: service_baidu # 集群的名稱(chēng)      type: LOGICAL_DNS # 用于解析集群(生成集群端點(diǎn))時(shí)使用的服務(wù)發(fā)現(xiàn)類(lèi)型,可用值有STATIC、STRICT_DNS 、LOGICAL_DNS、ORIGINAL_DST和EDS等;      connect_timeout: 0.25s      dns_lookup_family: V4_ONLY      lb_policy: ROUND_ROBIN # 負(fù)載均衡算法,支持ROUND_ROBIN、LEAST_REQUEST、RING_HASH、RANDOM、MAGLEV和CLUSTER_PROVIDED;      load_assignment:        cluster_name: service_baidu        endpoints:          - lb_endpoints:              - endpoint:                  address:                    socket_address:                      address: www.baidu.com                      port_value: 443      transport_socket:        name: envoy.transport_sockets.tls        typed_config:          "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext          sni: www.baidu.com

第一次使用 Envoy,可能會(huì)覺(jué)得它的配置太復(fù)雜了,讓人眼花繚亂。其實(shí)只要我們理解了網(wǎng)絡(luò)代理程序的流程就不難配置了,比如作為一個(gè)代理,首先要能獲取請(qǐng)求流量,通常是采用監(jiān)聽(tīng)端口的方式實(shí)現(xiàn);其次拿到請(qǐng)求數(shù)據(jù)后需要對(duì)其做微處理,例如附加 Header 或校驗(yàn)?zāi)硞€(gè) Header 字段的內(nèi)容等,這里針對(duì)來(lái)源數(shù)據(jù)的層次不同,可以分為 L3/L4/L7,然后將請(qǐng)求轉(zhuǎn)發(fā)出去;轉(zhuǎn)發(fā)這里又可以衍生出如果后端是一個(gè)集群,需要從中挑選一臺(tái)機(jī)器,如何挑選又涉及到負(fù)載均衡等。qtF28資訊網(wǎng)——每日最新資訊28at.com

腦補(bǔ)完大致流程后,再來(lái)看 Envoy 是如何組織配置信息的,我們?cè)賮?lái)解釋一下其中的關(guān)鍵字段。qtF28資訊網(wǎng)——每日最新資訊28at.com

  • listener: Envoy 的監(jiān)聽(tīng)地址,就是真正干活的。Envoy 會(huì)暴露一個(gè)或多個(gè) Listener 來(lái)監(jiān)聽(tīng)客戶(hù)端的請(qǐng)求。
  • filter: 過(guò)濾器,在 Envoy 中指的是一些可插拔和可組合的邏輯處理層,是 Envoy 核心邏輯處理單元。
  • route_config: 路由規(guī)則配置,即將請(qǐng)求路由到后端的哪個(gè)集群。
  • cluster: 服務(wù)提供方集群,Envoy 通過(guò)服務(wù)發(fā)現(xiàn)定位集群成員并獲取服務(wù),具體路由到哪個(gè)集群成員由負(fù)載均衡策略決定。

結(jié)合關(guān)鍵字段和上面的腦補(bǔ)流程,可以看出 Envoy 的大致處理流程如下:qtF28資訊網(wǎng)——每日最新資訊28at.com

qtF28資訊網(wǎng)——每日最新資訊28at.com

Envoy 配置流程qtF28資訊網(wǎng)——每日最新資訊28at.com

Envoy 內(nèi)部對(duì)請(qǐng)求的處理流程其實(shí)跟我們上面腦補(bǔ)的流程大致相同,即對(duì)請(qǐng)求的處理流程基本是不變的,而對(duì)于變化的部分,即對(duì)請(qǐng)求數(shù)據(jù)的微處理,全部抽象為 Filter,例如對(duì)請(qǐng)求的讀寫(xiě)是 ReadFilter、WriteFilter,對(duì) HTTP 請(qǐng)求數(shù)據(jù)的編解碼是 StreamEncoderFilter、StreamDecoderFilter,對(duì) TCP 的處理是 TcpProxyFilter,其繼承自 ReadFilter,對(duì) HTTP 的處理是 ConnectionManager,其也是繼承自 ReadFilter 等等,各個(gè) Filter 最終會(huì)組織成一個(gè) FilterChain,在收到請(qǐng)求后首先走 FilterChain,其次路由到指定集群并做負(fù)載均衡獲取一個(gè)目標(biāo)地址,然后轉(zhuǎn)發(fā)出去。qtF28資訊網(wǎng)——每日最新資訊28at.com

啟動(dòng) Envoy

配置完成后,我們就可以去啟動(dòng) Envoy 了,首先當(dāng)然需要去安裝 Envoy 了,因?yàn)?Envoy 是 C++ 開(kāi)發(fā)的,編譯起來(lái)非常麻煩,如果是 Mac 用戶(hù)可以使用 brew install envoy 來(lái)一鍵安裝,但是最簡(jiǎn)單的方式還是使用 Docker 來(lái)啟動(dòng) Envoy。qtF28資訊網(wǎng)——每日最新資訊28at.com

我們這里也通過(guò) Docker 容器來(lái)啟動(dòng) Envoy,將上面的配置文件通過(guò) Volume 掛載到容器中的 /etc/envoy/envoy.yaml 去。qtF28資訊網(wǎng)——每日最新資訊28at.com

然后使用以下命令啟動(dòng)綁定到端口 80 的 Envoy 容器:qtF28資訊網(wǎng)——每日最新資訊28at.com

$ docker run --name=envoy -d /  -p 80:10000 /  -v $(pwd)/manifests/2.Envoy/envoy-1.yaml:/etc/envoy/envoy.yaml /  envoyproxy/envoy:v1.28.0

啟動(dòng)后,我們可以在本地的 80 端口上去訪(fǎng)問(wèn)應(yīng)用 curl localhost 來(lái)測(cè)試代理是否成功。同樣我們也可以通過(guò)在本地瀏覽器中訪(fǎng)問(wèn) localhost 來(lái)查看:qtF28資訊網(wǎng)——每日最新資訊28at.com

qtF28資訊網(wǎng)——每日最新資訊28at.com

localhostqtF28資訊網(wǎng)——每日最新資訊28at.com

可以看到請(qǐng)求被代理到了 baidu.com,而且應(yīng)該也可以看到 URL 地址沒(méi)有變化,還是 localhost,查看 Envoy 日志可以看到如下信息:qtF28資訊網(wǎng)——每日最新資訊28at.com

[2023-10-25T06:53:50.003Z] "GET / HTTP/1.1" 200 - 0 103079 399 235 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36" "e081fa5b-31a4-4285-92d9-b8a8c896f2d4" "www.baidu.com" "110.242.68.3:443"[2023-10-25T06:53:50.819Z] "GET /sugrec?&prod=pc_his&from=pc_web&jsnotallow=1&sid=&hisdata=%5B%7B%22time%22%3A1698206660%2C%22kw%22%3A%22envovy%20typed_config%22%2C%22fq%22%3A2%7D%5D&_t=1698216830777&req=2&csor=0 HTTP/1.1" 200 - 0 155 57 57 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36" "9a9351e7-e7ef-4fa8-9aec-fba96600e4df" "www.baidu.com" "110.242.68.3:443"

此外 Envoy 還提供了一個(gè)管理視圖,可以讓我們?nèi)ゲ榭磁渲谩⒔y(tǒng)計(jì)信息、日志以及其他 Envoy 內(nèi)部的一些數(shù)據(jù)。上面我們定義的管理視圖的端口為 9901,當(dāng)然我們也可以通過(guò) Docker 容器將管理端口暴露給外部用戶(hù)。qtF28資訊網(wǎng)——每日最新資訊28at.com

docker run --name=envoy -d /  -p 9901:9901 /  -p 80:10000 /  -v $(pwd)/manifests/2.Envoy/envoy-1.yaml:/etc/envoy/envoy.yaml /  envoyproxy/envoy:v1.28.0

上面的配置就會(huì)將管理頁(yè)面暴露給外部用戶(hù),當(dāng)然我們這里僅僅用于演示是可以的,如果你是用于線(xiàn)上環(huán)境還需要做好一些安全保護(hù)措施。運(yùn)行成功后,現(xiàn)在我們可以在瀏覽器里面輸入 localhost:9901 來(lái)訪(fǎng)問(wèn) Envoy 的管理頁(yè)面:qtF28資訊網(wǎng)——每日最新資訊28at.com

qtF28資訊網(wǎng)——每日最新資訊28at.com

envoy adminqtF28資訊網(wǎng)——每日最新資訊28at.com

需要注意的是當(dāng)前的管理頁(yè)面不僅允許執(zhí)行一些破壞性的操作(比如,關(guān)閉服務(wù)),而且還可能暴露一些私有信息(比如統(tǒng)計(jì)信息、集群名稱(chēng)、證書(shū)信息等)。所以應(yīng)該只允許通過(guò)安全網(wǎng)絡(luò)去訪(fǎng)問(wèn)管理頁(yè)面。qtF28資訊網(wǎng)——每日最新資訊28at.com

遷移 NGINX 到 Envoy

因?yàn)楝F(xiàn)階段大部分的應(yīng)用可能還是使用的比較傳統(tǒng)的 Nginx 來(lái)做服務(wù)代理,為了對(duì)比 Envoy 和 Nginx 的區(qū)別,我們這里將來(lái)嘗試將 Nginx 的配置遷移到 Envoy 上來(lái),這樣也有助于我們?nèi)チ私?Envoy 的配置。qtF28資訊網(wǎng)——每日最新資訊28at.com

首先我們使用 Nginx 官方 Wiki 的完整示例來(lái)進(jìn)行說(shuō)明,完整的 nginx.conf 配置如下所示:qtF28資訊網(wǎng)——每日最新資訊28at.com

user  www www;pid /var/run/nginx.pid;worker_processes  2;events {  worker_connections   2000;}http {  gzip on;  gzip_min_length  1100;  gzip_buffers     4 8k;  gzip_types       text/plain;  log_format main      '$remote_addr - $remote_user [$time_local]  '    '"$request" $status $bytes_sent '    '"$http_referer" "$http_user_agent" '    '"$gzip_ratio"';  log_format download  '$remote_addr - $remote_user [$time_local]  '    '"$request" $status $bytes_sent '    '"$http_referer" "$http_user_agent" '    '"$http_range" "$sent_http_content_range"';  upstream targetCluster {    192.168.215.3:80;    192.168.215.4:80;  }  server {    listen        8080;    server_name   one.example.com  www.one.example.com;    access_log   /var/log/nginx.access_log  main;    error_log  /var/log/nginx.error_log  info;    location / {      proxy_pass         http://targetCluster/;      proxy_redirect     off;      proxy_set_header   Host             $host;      proxy_set_header   X-Real-IP        $remote_addr;    }  }}

上面的 Nginx 配置有 3 個(gè)核心配置:qtF28資訊網(wǎng)——每日最新資訊28at.com

  • 配置 Nginx 服務(wù)、日志結(jié)構(gòu)和 Gzip 功能
  • 配置 Nginx 在端口 8080 上接受對(duì) one.example.com 域名的請(qǐng)求
  • 根據(jù)不同的路徑配置將流量轉(zhuǎn)發(fā)給目標(biāo)服務(wù)

并不是所有的 Nginx 的配置都適用于 Envoy,有些方面的配置我們可以不用。Envoy 代理主要有 4 中主要的配置類(lèi)型,它們是支持 Nginx 提供的核心基礎(chǔ)結(jié)構(gòu)的:qtF28資訊網(wǎng)——每日最新資訊28at.com

  • Listeners(監(jiān)聽(tīng)器):他們定義 Envoy 代理如何接收傳入的網(wǎng)絡(luò)請(qǐng)求,建立連接后,它會(huì)傳遞到一組過(guò)濾器進(jìn)行處理
  • Filters(過(guò)濾器):過(guò)濾器是處理傳入和傳出請(qǐng)求的管道結(jié)構(gòu)的一部分,比如可以開(kāi)啟類(lèi)似于 Gzip 之類(lèi)的過(guò)濾器,該過(guò)濾器就會(huì)在將數(shù)據(jù)發(fā)送到客戶(hù)端之前進(jìn)行壓縮
  • Routers(路由器):這些路由器負(fù)責(zé)將流量轉(zhuǎn)發(fā)到定義的目的集群去
  • Clusters(集群):集群定義了流量的目標(biāo)端點(diǎn)和相關(guān)配置。

我們將使用這 4 個(gè)組件來(lái)創(chuàng)建 Envoy 代理配置,去匹配 Nginx 中的配置。Envoy 的重點(diǎn)一直是在 API 和動(dòng)態(tài)配置上,但是我們這里仍然使用靜態(tài)配置。qtF28資訊網(wǎng)——每日最新資訊28at.com

Nginx 配置的核心是 HTTP 配置配置,里面包含了:qtF28資訊網(wǎng)——每日最新資訊28at.com

  • 定義支持哪些 MIME 類(lèi)型
  • 默認(rèn)的超時(shí)時(shí)間
  • Gzip 配置

我們可以通過(guò) Envoy 代理中的過(guò)濾器來(lái)配置這些內(nèi)容。在 HTTP 配置部分,Nginx 配置指定了監(jiān)聽(tīng)的端口 8080,并響應(yīng)域名 one.example.com 和 www.one.example.com 的傳入請(qǐng)求:qtF28資訊網(wǎng)——每日最新資訊28at.com

server {    listen        8080;    server_name   one.example.com  www.one.example.com;    ......}

在 Envoy 中,這部分就是監(jiān)聽(tīng)器來(lái)管理的。開(kāi)始一個(gè) Envoy 代理最重要的方面就是定義監(jiān)聽(tīng)器,我們需要?jiǎng)?chuàng)建一個(gè)配置文件來(lái)描述我們?nèi)绾稳ミ\(yùn)行 Envoy 實(shí)例。qtF28資訊網(wǎng)——每日最新資訊28at.com

這里我們定義一個(gè) static_resources 配置,它是 Envoy 配置的根節(jié)點(diǎn),它包含了所有的靜態(tài)配置,包括監(jiān)聽(tīng)器、集群、路由等。我們將創(chuàng)建一個(gè)新的監(jiān)聽(tīng)器并將其綁定到 8080 端口上,該配置指示了 Envoy 代理用于接收網(wǎng)絡(luò)請(qǐng)求的端口,如下所示:qtF28資訊網(wǎng)——每日最新資訊28at.com

static_resources:  listeners:    - name: listener_0 # 監(jiān)聽(tīng)器的名稱(chēng)      address:        socket_address:          address: 0.0.0.0 # 監(jiān)聽(tīng)器的地址          port_value: 8080 # 監(jiān)聽(tīng)器的端口

需要注意的是我們沒(méi)有在監(jiān)聽(tīng)器部分定義 server_name,這需要在過(guò)濾器部分進(jìn)行處理。qtF28資訊網(wǎng)——每日最新資訊28at.com

當(dāng)請(qǐng)求進(jìn)入 Nginx 時(shí),location 部分定義了如何處理流量以及在什么地方轉(zhuǎn)發(fā)流量。在下面的配置中,站點(diǎn)的所有傳入流量都將被代理到一個(gè)名為 targetCluster 的上游(upstream)集群,上游集群定義了處理請(qǐng)求的節(jié)點(diǎn)。qtF28資訊網(wǎng)——每日最新資訊28at.com

location / {    proxy_pass         http://targetCluster/;    proxy_redirect     off;    proxy_set_header   Host             $host;    proxy_set_header   X-Real-IP        $remote_addr;}

在 Envoy 中,這部分將由過(guò)濾器來(lái)進(jìn)行配置管理。在靜態(tài)配置中,過(guò)濾器定義了如何處理傳入的請(qǐng)求,在我們這里,將配置一個(gè)過(guò)濾器去匹配上一步中的 server_names,當(dāng)接收到與定義的域名和路由匹配的傳入請(qǐng)求時(shí),流量將轉(zhuǎn)發(fā)到集群,集群和 Nginx 配置中的 upstream 是一致的。qtF28資訊網(wǎng)——每日最新資訊28at.com

filter_chains:  - filters:      - name: envoy.filterswork.http_connection_manager        typed_config:          "@type": type.googleapis.com/envoy.extensions.filterswork.http_connection_manager.v3.HttpConnectionManager          stat_prefix: ingress_http          http_filters: # 定義http過(guò)濾器鏈            - name: envoy.filters.http.router # 調(diào)用7層的路由過(guò)濾器              typed_config:                "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router          route_config:            name: local_route            virtual_hosts:              - name: backend                domains:                  - "one.example.com"                  - "www.one.example.com"                routes:                  - match:                      prefix: "/"                    route:                      cluster: targetCluster

其中 envoy.filterswork.http_connection_manager 是 Envoy 內(nèi)置的一個(gè)過(guò)濾器,用于處理 HTTP 連接的,除此之外,還有其他的一些內(nèi)置的過(guò)濾器,比如 Redis、Mongo、TCP。qtF28資訊網(wǎng)——每日最新資訊28at.com

在 Nginx 中,upstream(上游)配置定義了處理請(qǐng)求的目標(biāo)服務(wù)器集群,在我們這里的示例中,分配了兩個(gè)集群。qtF28資訊網(wǎng)——每日最新資訊28at.com

upstream targetCluster {  192.168.215.3:80;  192.168.215.4:80;}

在 Envoy 代理中,這部分是通過(guò) clusters 進(jìn)行配置管理的。upstream 等同與 Envoy 中的 clusters 定義,我們這里通過(guò)集群定義了主機(jī)被訪(fǎng)問(wèn)的方式,還可以配置超時(shí)和負(fù)載均衡等方面更精細(xì)的控制。qtF28資訊網(wǎng)——每日最新資訊28at.com

clusters:  - name: targetCluster    connect_timeout: 0.25s    type: STRICT_DNS    dns_lookup_family: V4_ONLY    lb_policy: ROUND_ROBIN    load_assignment:      cluster_name: targetCluster      endpoints:        - lb_endpoints:            - endpoint:                address:                  socket_address:                    address: 192.168.215.3                    port_value: 80            - endpoint:                address:                  socket_address:                    address: 192.168.215.4                    port_value: 80

上面我們配置了 STRICT_DNS 類(lèi)型的服務(wù)發(fā)現(xiàn),Envoy 會(huì)持續(xù)異步地解析指定的 DNS 目標(biāo)。DNS 解析結(jié)果返回的每個(gè) IP 地址都將被視為上游集群的主機(jī)。所以如果返回兩個(gè) IP 地址,則 Envoy 將認(rèn)為集群有兩個(gè)主機(jī),并且兩個(gè)主機(jī)都應(yīng)進(jìn)行負(fù)載均衡,如果從結(jié)果中刪除了一個(gè)主機(jī),則 Envoy 會(huì)從現(xiàn)有的連接池中將其剔出掉。qtF28資訊網(wǎng)——每日最新資訊28at.com

最后需要配置的日志部分,Envoy 采用云原生的方式,將應(yīng)用程序日志都輸出到 stdout 和 stderr,而不是將錯(cuò)誤日志輸出到磁盤(pán)。qtF28資訊網(wǎng)——每日最新資訊28at.com

當(dāng)用戶(hù)發(fā)起一個(gè)請(qǐng)求時(shí),訪(fǎng)問(wèn)日志默認(rèn)是被禁用的,我們可以手動(dòng)開(kāi)啟。要為 HTTP 請(qǐng)求開(kāi)啟訪(fǎng)問(wèn)日志,需要在 HTTP 連接管理器中包含一個(gè) access_log 的配置,該路徑可以是設(shè)備,比如 stdout,也可以是磁盤(pán)上的某個(gè)文件,這依賴(lài)于我們自己的實(shí)際情況。qtF28資訊網(wǎng)——每日最新資訊28at.com

下面過(guò)濾器中的配置就會(huì)將所有訪(fǎng)問(wèn)日志通過(guò)管理傳輸?shù)?nbsp;stdout:qtF28資訊網(wǎng)——每日最新資訊28at.com

- name: envoy.filterswork.http_connection_manager  typed_config:    # 啟用 http_connection_manager    "@type": type.googleapis.com/envoy.extensions.filterswork.http_connection_manager.v3.HttpConnectionManager    stat_prefix: ingress_http    access_log:      - name: envoy.access_loggers.stdout        typed_config:          "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog    http_filters: # 定義http過(guò)濾器鏈      - name: envoy.filters.http.router # 調(diào)用7層的路由過(guò)濾器        typed_config:          "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router    route_config:    # ......

默認(rèn)情況下,Envoy 訪(fǎng)問(wèn)日志格式包含整個(gè) HTTP 請(qǐng)求的詳細(xì)信息:qtF28資訊網(wǎng)——每日最新資訊28at.com

[%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%"%RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION%%RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-FORWARDED-FOR)%" "%REQ(USER-AGENT)%""%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%"/n

輸出結(jié)果格式化后如下所示:qtF28資訊網(wǎng)——每日最新資訊28at.com

[2023-10-25T07:25:09.826Z] "GET / HTTP/1.1" 200 - 0 102931 361 210 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36" "6e19ddda-e0a1-41f9-9355-ea5db8d23bcc" "one.example.com" "192.168.215.4:80"

我們也可以通過(guò)設(shè)置 format 字段來(lái)自定義輸出日志的格式,例如:qtF28資訊網(wǎng)——每日最新資訊28at.com

access_log:  - name: envoy.access_loggers.stdout    typed_config:      "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog      log_format:        text_format: "[%START_TIME%] %REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL% %RESPONSE_CODE% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% %REQ(X-REQUEST-ID)% %REQ(:AUTHORITY)% %UPSTREAM_HOST%/n"

此外我們也可以通過(guò)設(shè)置 json_format 字段來(lái)將日志作為 JSON 格式輸出,例如:qtF28資訊網(wǎng)——每日最新資訊28at.com

access_log:  - name: envoy.access_loggers.stdout    typed_config:      "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog      log_format:        json_format:          {            "protocol": "%PROTOCOL%",            "duration": "%DURATION%",            "request_method": "%REQ(:METHOD)%",          }

要注意的是,訪(fǎng)問(wèn)日志會(huì)在未設(shè)置、或者空值的位置加入一個(gè)字符:-。不同類(lèi)型的訪(fǎng)問(wèn)日志(例如 HTTP 和 TCP)共用同樣的格式字符串。不同類(lèi)型的日志中,某些字段可能會(huì)有不同的含義。有關(guān) Envoy 日志的更多信息,可以查看官方文檔對(duì)應(yīng)的說(shuō)明。當(dāng)然日志并不是 Envoy 代理獲得請(qǐng)求可見(jiàn)性的唯一方法,Envoy 還內(nèi)置了高級(jí)跟蹤和指標(biāo)功能。qtF28資訊網(wǎng)——每日最新資訊28at.com

最后我們完整的 Envoy 配置如下所示:qtF28資訊網(wǎng)——每日最新資訊28at.com

# envoy-2.yamlstatic_resources:  listeners:    - name: listener_0 # 監(jiān)聽(tīng)器的名稱(chēng)      address:        socket_address:          address: 0.0.0.0 # 監(jiān)聽(tīng)器的地址          port_value: 8080 # 監(jiān)聽(tīng)器的端口      filter_chains:        - filters:            - name: envoy.filterswork.http_connection_manager              typed_config:                "@type": type.googleapis.com/envoy.extensions.filterswork.http_connection_manager.v3.HttpConnectionManager                stat_prefix: ingress_http                access_log:                  - name: envoy.access_loggers.stdout                    typed_config:                      "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog                http_filters: # 定義http過(guò)濾器鏈                  - name: envoy.filters.http.router # 調(diào)用7層的路由過(guò)濾器                    typed_config:                      "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router                route_config:                  name: local_route                  virtual_hosts:                    - name: backend                      domains:                        - "one.example.com"                        - "www.one.example.com"                      routes:                        - match:                            prefix: "/"                          route:                            cluster: targetCluster  clusters:    - name: targetCluster      connect_timeout: 0.25s      type: STRICT_DNS      dns_lookup_family: V4_ONLY      lb_policy: ROUND_ROBIN      load_assignment:        cluster_name: targetCluster        endpoints:          - lb_endpoints:              - endpoint:                  address:                    socket_address:                      address: 192.168.215.3                      port_value: 80              - endpoint:                  address:                    socket_address:                      address: 192.168.215.4                      port_value: 80

現(xiàn)在我們已經(jīng)將 Nginx 配置轉(zhuǎn)換為了 Envoy 代理,接下來(lái)我們可以來(lái)啟動(dòng) Envoy 代理進(jìn)行測(cè)試驗(yàn)證。qtF28資訊網(wǎng)——每日最新資訊28at.com

在 Nginx 配置的頂部,有一行配置 user www www;,表示用非 root 用戶(hù)來(lái)運(yùn)行 Nginx 以提高安全性。而 Envoy 代理采用云原生的方法來(lái)管理使用這,我們通過(guò)容器啟動(dòng) Envoy 代理的時(shí)候,可以指定一個(gè)低特權(quán)的用戶(hù)。qtF28資訊網(wǎng)——每日最新資訊28at.com

下面的命令將通過(guò) Docker 容器來(lái)啟動(dòng)一個(gè) Envoy 實(shí)例,該命令使 Envoy 可以監(jiān)聽(tīng) 80 端口上的流量請(qǐng)求,但是我們?cè)?Envoy 的監(jiān)聽(tīng)器配置中指定的是 8080 端口,所以我們用一個(gè)低特權(quán)用戶(hù)身份來(lái)運(yùn)行:qtF28資訊網(wǎng)——每日最新資訊28at.com

$ docker run --name proxy1 -p 80:8080 --user 1000:1000 -v $(pwd)/manifests/2.Envoy/envoy-2.yaml:/etc/envoy/envoy.yaml envoyproxy/envoy:v1.28.0

啟動(dòng)代理后,就可以開(kāi)始測(cè)試了,下面我們用 curl 命令使用代理配置的 host 頭發(fā)起一個(gè)網(wǎng)絡(luò)請(qǐng)求:qtF28資訊網(wǎng)——每日最新資訊28at.com

$ curl -H "Host: one.example.com" localhost -iHTTP/1.1 503 Service Unavailablecontent-length: 91content-type: text/plaindate: Wed, 25 Oct 2023 07:37:55 GMTserver: envoyupstream connect error or disconnect/reset before headers. reset reason: connection timeout%

我們可以看到會(huì)出現(xiàn) 503 錯(cuò)誤,這是因?yàn)槲覀兣渲玫纳嫌渭褐鳈C(jī)根本就沒(méi)有運(yùn)行,所以 Envoy 代理請(qǐng)求到不可用的主機(jī)上去了,就出現(xiàn)了這樣的錯(cuò)誤。我們可以使用下面的命令啟動(dòng)兩個(gè) HTTP 服務(wù),用來(lái)表示上游主機(jī):qtF28資訊網(wǎng)——每日最新資訊28at.com

$ docker run -d cnych/docker-http-server; docker run -d cnych/docker-http-server;$ docker psCONTAINER ID   IMAGE                      COMMAND                  CREATED         STATUS         PORTS                                              NAMES3ecf1125bd0c   cnych/docker-http-server   "/app"                   2 minutes ago   Up 2 minutes   80/tcp                                             loving_babbage0195f14ec57a   cnych/docker-http-server   "/app"                   2 minutes ago   Up 2 minutes   80/tcp                                             heuristic_torvaldsa55f6175c5c7   envoyproxy/envoy:v1.28.0   "/docker-entrypoint.…"   3 minutes ago   Up 3 minutes   10000/tcp, 0.0.0.0:80->8080/tcp, :::80->8080/tcp   proxy1

當(dāng)上面兩個(gè)服務(wù)啟動(dòng)成功后,現(xiàn)在我們?cè)偻ㄟ^(guò) Envoy 去訪(fǎng)問(wèn)目標(biāo)服務(wù)就正常了:qtF28資訊網(wǎng)——每日最新資訊28at.com

$ curl -H "Host: one.example.com" localhost -iHTTP/1.1 200 OKdate: Wed, 25 Oct 2023 07:42:51 GMTcontent-length: 58content-type: text/html; charset=utf-8x-envoy-upstream-service-time: 1server: envoy<h1>This request was processed by host: 3ecf1125bd0c</h1>$ curl -H "Host: one.example.com" localhost -iHTTP/1.1 200 OKdate: Wed, 25 Oct 2023 07:42:53 GMTcontent-length: 58content-type: text/html; charset=utf-8x-envoy-upstream-service-time: 8server: envoy<h1>This request was processed by host: 0195f14ec57a</h1>

當(dāng)訪(fǎng)問(wèn)請(qǐng)求的時(shí)候,我們可以看到是哪個(gè)容器處理了請(qǐng)求,在 Envoy 代理容器中,也可以看到請(qǐng)求的日志輸出:qtF28資訊網(wǎng)——每日最新資訊28at.com

[2023-10-25T07:42:51.297Z] "GET / HTTP/1.1" 200 - 0 58 3 1 "-" "curl/7.87.0" "ff1e1009-d5a3-4a71-87ef-479e234c9858" "one.example.com" "192.168.215.4:80"[2023-10-25T07:42:53.153Z] "GET / HTTP/1.1" 200 - 0 58 9 8 "-" "curl/7.87.0" "d0ebdd10-a1d2-406e-8c6e-6fd8451aded3" "one.example.com" "192.168.215.3:80"

到這里我們就完成了將 Nginx 配置遷移到 Envoy 的過(guò)程,可以看到 Envoy 的配置和 Nginx 的配置還是有很大的區(qū)別的,但是我們可以看到 Envoy 的配置更加的靈活,而且 Envoy 代理的配置是可以動(dòng)態(tài)更新的,這樣就可以實(shí)現(xiàn)無(wú)縫的服務(wù)升級(jí)。qtF28資訊網(wǎng)——每日最新資訊28at.com

使用 SSL/TLS 保護(hù)流量

接下來(lái)我們將來(lái)了解下如何使用 Envoy 保護(hù) HTTP 網(wǎng)絡(luò)請(qǐng)求。確保 HTTP 流量安全對(duì)于保護(hù)用戶(hù)隱私和數(shù)據(jù)是至關(guān)重要的。下面我們來(lái)了解下如何在 Envoy 中配置 SSL 證書(shū)。qtF28資訊網(wǎng)——每日最新資訊28at.com

SSL 證書(shū)

這里我們將為 example.com 域名生成一個(gè)自簽名的證書(shū),當(dāng)然如果在生產(chǎn)環(huán)境時(shí)候,需要使用正規(guī) CA 機(jī)構(gòu)購(gòu)買(mǎi)的證書(shū),或者使用 Let's Encrypt 的免費(fèi)證書(shū)服務(wù)。qtF28資訊網(wǎng)——每日最新資訊28at.com

下面的命令會(huì)在目錄 certs/ 中創(chuàng)建一個(gè)新的證書(shū)和密鑰:qtF28資訊網(wǎng)——每日最新資訊28at.com

$ mkdir certs; cd certs;$ openssl req -nodes -new -x509 /  -keyout example-com.key -out example-com.crt /  -days 365 /  -subj '/CN=example.com/O=youdianzhishi.com/C=CN';  Generating a RSA private key....+..+....+..+.......+.....+...+....+++++++++++++++++++++++++++++++++++++++*....+...+................+......+........+...+...+.+...+......+.....+......+.+.....+++++++++++++++++++++++++++++++++++++++*............+.....+................+....................+......+....+..............+.+..+...+...............+.......+............+...+...+......+.....+....+..+....+.........+....................+.+......+..+...+.........+.+..+..........+...............+..+...+.+......+...+..+......+.......+............+......+..+......+......++++++.....+............+.+..+....+.....+.+.........+.....+++++++++++++++++++++++++++++++++++++++*...+...+............+.....+.+...........+...+...+...............+...+......+.........+.+.....+...+.+......+...+...+++++++++++++++++++++++++++++++++++++++*........+..........+...+...+......+.........++++++-----$ cd -

流量保護(hù)

在 Envoy 中保護(hù) HTTP 流量,需要通過(guò)添加 transport_socket 過(guò)濾器,該過(guò)濾器提供了為 Envoy 代理中配置的域名指定證書(shū)的功能,請(qǐng)求 HTTPS 請(qǐng)求時(shí)候,就使用匹配的證書(shū)。我們這里直接使用上一步中生成的自簽名證書(shū)即可。qtF28資訊網(wǎng)——每日最新資訊28at.com

我們這里的 Envoy 配置文件中包含了所需的 HTTPS 支持的配置,我們添加了兩個(gè)監(jiān)聽(tīng)器,一個(gè)監(jiān)聽(tīng)器在 8080 端口上用于 HTTP 通信,另外一個(gè)監(jiān)聽(tīng)器在 8443 端口上用于 HTTPS 通信。qtF28資訊網(wǎng)——每日最新資訊28at.com

在 HTTPS 監(jiān)聽(tīng)器中定義了 HTTP 連接管理器,該代理將代理 /service/1 和 /service/2 這兩個(gè)端點(diǎn)的傳入請(qǐng)求,這里我們需要通過(guò) envoy.transport_sockets.tls 配置相關(guān)證書(shū),如下所示:qtF28資訊網(wǎng)——每日最新資訊28at.com

transport_socket:  name: envoy.transport_sockets.tls  typed_config:    # 一個(gè)監(jiān)聽(tīng)傳輸套接字,用于使用 TLS 接受下游連接(客戶(hù)端)。    "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext    common_tls_context:      tls_certificates:        - certificate_chain:            filename: "/etc/certs/example-com.crt"          private_key:            filename: "/etc/certs/example-com.key"

在 TLS 上下文中定義了生成的證書(shū)和密鑰,如果我們有多個(gè)域名,每個(gè)域名都有自己的證書(shū),則需要通過(guò) tls_certificates 定義多個(gè)證書(shū)鏈。qtF28資訊網(wǎng)——每日最新資訊28at.com

自動(dòng)跳轉(zhuǎn)qtF28資訊網(wǎng)——每日最新資訊28at.com

定義了 TLS 上下文后,該站點(diǎn)將能夠通過(guò) HTTPS 提供流量了,但是如果用戶(hù)是通過(guò) HTTP 來(lái)訪(fǎng)問(wèn)的服務(wù),為了確保安全,我們可以將其重定向到 HTTPS 版本服務(wù)上去。qtF28資訊網(wǎng)——每日最新資訊28at.com

在 HTTP 配置中,我們將 https_redirect: true 的標(biāo)志添加到過(guò)濾器的配置中即可實(shí)現(xiàn)跳轉(zhuǎn)功能。qtF28資訊網(wǎng)——每日最新資訊28at.com

route_config:  virtual_hosts:    - name: backend      domains:        - "example.com"      routes:        - match:            prefix: "/"          redirect:            path_redirect: "/"            https_redirect: true

當(dāng)用戶(hù)訪(fǎng)問(wèn)網(wǎng)站的 HTTP 版本時(shí),Envoy 代理將根據(jù)過(guò)濾器配置來(lái)匹配域名和路徑,匹配到過(guò)后將請(qǐng)求重定向到站點(diǎn)的 HTTPS 版本去。完整的 Envoy 配置如下所示:qtF28資訊網(wǎng)——每日最新資訊28at.com

# envoy-3.yamladmin:  access_log_path: /tmp/admin_access.log  address:    socket_address:      address: 0.0.0.0      port_value: 8001static_resources:  listeners:    - name: listener_http # 監(jiān)聽(tīng)器的名稱(chēng)      address:        socket_address:          address: 0.0.0.0 # 監(jiān)聽(tīng)器的地址          port_value: 8080 # 監(jiān)聽(tīng)器的端口      filter_chains:        - filters:            - name: envoy.filterswork.http_connection_manager              typed_config:                "@type": type.googleapis.com/envoy.extensions.filterswork.http_connection_manager.v3.HttpConnectionManager                stat_prefix: ingress_http                access_log:                  - name: envoy.access_loggers.stdout                    typed_config:                      "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog                http_filters: # 定義http過(guò)濾器鏈                  - name: envoy.filters.http.router # 調(diào)用7層的路由過(guò)濾器                    typed_config:                      "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router                route_config:                  name: local_route                  virtual_hosts:                    - name: backend                      domains:                        - "example.com"                      routes:                        - match:                            prefix: "/"                          redirect:                            path_redirect: "/"                            https_redirect: true    - name: listener_https # 監(jiān)聽(tīng)器的名稱(chēng)      address:        socket_address:          address: 0.0.0.0 # 監(jiān)聽(tīng)器的地址          port_value: 8443 # 監(jiān)聽(tīng)器的端口      filter_chains:        - transport_socket:            name: envoy.transport_sockets.tls            typed_config:              # 一個(gè)監(jiān)聽(tīng)傳輸套接字,用于使用 TLS 接受下游連接(客戶(hù)端)。              "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext              common_tls_context:                tls_certificates:                  - certificate_chain:                      filename: "/etc/certs/example-com.crt"                    private_key:                      filename: "/etc/certs/example-com.key"          filters:            - name: envoy.filterswork.http_connection_manager              typed_config:                "@type": type.googleapis.com/envoy.extensions.filterswork.http_connection_manager.v3.HttpConnectionManager                stat_prefix: ingress_http                access_log:                  - name: envoy.access_loggers.stdout                    typed_config:                      "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog                http_filters: # 定義http過(guò)濾器鏈                  - name: envoy.filters.http.router # 調(diào)用7層的路由過(guò)濾器                    typed_config:                      "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router                route_config:                  name: local_route                  virtual_hosts:                    - name: backend                      domains:                        - "example.com"                      routes:                        - match:                            prefix: "/service/1"                          route:                            cluster: service1                        - match:                            prefix: "/service/2"                          route:                            cluster: service2  clusters:    - name: service1      connect_timeout: 0.25s      type: STRICT_DNS      dns_lookup_family: V4_ONLY      lb_policy: ROUND_ROBIN      load_assignment:        cluster_name: service1        endpoints:          - lb_endpoints:              - endpoint:                  address:                    socket_address:                      address: 192.168.215.3                      port_value: 80    - name: service2      connect_timeout: 0.25s      type: STRICT_DNS      dns_lookup_family: V4_ONLY      lb_policy: ROUND_ROBIN      load_assignment:        cluster_name: service2        endpoints:          - lb_endpoints:              - endpoint:                  address:                    socket_address:                      address: 192.168.215.4                      port_value: 80

測(cè)試

現(xiàn)在配置已經(jīng)完成了,我們就可以啟動(dòng) Envoy 實(shí)例來(lái)進(jìn)行測(cè)試了。在我們這個(gè)示例中,Envoy 暴露 80 端口來(lái)處理 HTTP 請(qǐng)求,暴露 443 端口來(lái)處理 HTTPS 請(qǐng)求,此外還在 8001 端口上暴露了管理頁(yè)面,我們可以通過(guò)管理頁(yè)面查看有關(guān)證書(shū)的信息。qtF28資訊網(wǎng)——每日最新資訊28at.com

使用如下命令啟動(dòng) Envoy 代理:qtF28資訊網(wǎng)——每日最新資訊28at.com

$ docker run -it --name tls-proxy -p 80:8080 -p 443:8443 -p 8001:8001 -v $(pwd)/manifests/2.Envoy/certs:/etc/certs/ -v $(pwd)/manifests/2.Envoy/envoy-3.yaml:/etc/envoy/envoy.yaml envoyproxy/envoy:v1.28.0

啟動(dòng)完成后所有的 HTTPS 和 TLS 校驗(yàn)都是通過(guò) Envoy 來(lái)進(jìn)行處理的,所以我們不需要去修改應(yīng)該程序。同樣我們啟動(dòng)兩個(gè) HTTP 服務(wù)來(lái)處理傳入的請(qǐng)求:qtF28資訊網(wǎng)——每日最新資訊28at.com

$ docker run -d cnych/docker-http-server; docker run -d cnych/docker-http-server;$ docker psCONTAINER ID   IMAGE                      COMMAND                  CREATED          STATUS          PORTS                                                                                                                                  NAMES1690f6562870   cnych/docker-http-server   "/app"                   32 seconds ago   Up 32 seconds   80/tcp                                                                                                                                 distracted_ridef86925657e62   cnych/docker-http-server   "/app"                   32 seconds ago   Up 32 seconds   80/tcp                                                                                                                                 festive_almeidad02e37b26b22   envoyproxy/envoy:v1.28.0   "/docker-entrypoint.…"   3 minutes ago    Up 3 minutes    0.0.0.0:8001->8001/tcp, :::8001->8001/tcp, 10000/tcp, 0.0.0.0:80->8080/tcp, :::80->8080/tcp, 0.0.0.0:443->8443/tcp, :::443->8443/tcp   tls-proxy

上面的幾個(gè)容器啟動(dòng)完成后,就可以進(jìn)行測(cè)試了,首先我們請(qǐng)求 HTTP 的服務(wù),由于配置了自動(dòng)跳轉(zhuǎn),所以應(yīng)該會(huì)被重定向到 HTTPS 的版本上去:qtF28資訊網(wǎng)——每日最新資訊28at.com

$ curl -H "Host: example.com" http://localhost -iHTTP/1.1 301 Moved Permanentlylocation: https://example.com/date: Wed, 25 Oct 2023 08:30:48 GMTserver: envoycontent-length: 0

我們可以看到上面有 HTTP/1.1 301 Moved Permanently 這樣的重定向響應(yīng)信息。然后我們嘗試直接請(qǐng)求 HTTPS 的服務(wù):qtF28資訊網(wǎng)——每日最新資訊28at.com

$ curl -k -H "Host: example.com" https://localhost/service/1 -iHTTP/1.1 200 OKdate: Wed, 25 Oct 2023 08:31:17 GMTcontent-length: 58content-type: text/html; charset=utf-8x-envoy-upstream-service-time: 24server: envoy<h1>This request was processed by host: f86925657e62</h1>$ curl -k -H "Host: example.com" https://localhost/service/2 -iHTTP/1.1 200 OKdate: Wed, 25 Oct 2023 08:31:28 GMTcontent-length: 58content-type: text/html; charset=utf-8x-envoy-upstream-service-time: 22server: envoy<h1>This request was processed by host: 1690f6562870</h1>

我們可以看到通過(guò) HTTPS 進(jìn)行訪(fǎng)問(wèn)可以正常得到對(duì)應(yīng)的響應(yīng),需要注意的是由于我們這里使用的是自簽名的證書(shū),所以需要加上 -k 參數(shù)來(lái)忽略證書(shū)校驗(yàn),如果沒(méi)有這個(gè)參數(shù)則在請(qǐng)求的時(shí)候會(huì)報(bào)錯(cuò):qtF28資訊網(wǎng)——每日最新資訊28at.com

$ curl -H "Host: example.com" https://localhost/service/2 -icurl: (60) SSL certificate problem: self signed certificateMore details here: https://curl.se/docs/sslcerts.htmlcurl failed to verify the legitimacy of the server and therefore could notestablish a secure connection to it. To learn more about this situation andhow to fix it, please visit the web page mentioned above.

我們也可以通過(guò)管理頁(yè)面去查看證書(shū)相關(guān)的信息,上面我們啟動(dòng)容器的時(shí)候綁定了宿主機(jī)的 8001 端口,所以我們可以通過(guò)訪(fǎng)問(wèn) http://localhost:8001/certs 來(lái)獲取到證書(shū)相關(guān)的信息:qtF28資訊網(wǎng)——每日最新資訊28at.com

qtF28資訊網(wǎng)——每日最新資訊28at.com

證書(shū)信息qtF28資訊網(wǎng)——每日最新資訊28at.com

到這里我們就基本了解了 Envoy 的靜態(tài)配置方式,接下來(lái)的 xDS 才是 Envoy 中的精華部分。qtF28資訊網(wǎng)——每日最新資訊28at.com

本文鏈接:http://www.tebozhan.com/showinfo-26-15753-0.htmlEnvoy 基礎(chǔ)入門(mén)教程,看這一篇就夠了

聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com

上一篇: 點(diǎn)擊產(chǎn)生水波紋效果,Vue自定義指令20行代碼搞定~

下一篇: Git詳細(xì)使用教程,你學(xué)會(huì)了嗎?

標(biāo)簽:
  • 熱門(mén)焦點(diǎn)
Top