Aeraki 教程系列:如何開發一個自定義協議?
MetaProtocol Proxy 提供了一個良好的協議擴充套件機制,使得我們可以基於 MetaProtocol Proxy 快速實現一個自定義協議的七層代理。
由於 MetaProtocol Proxy 已經實現了一個七層協議代理所需的大部分功能,包括七層負載均衡、RDS 動態路由、本地限流、全侷限流、請求 Metrics 收集等,更多豐富的功能還在持續開發中。因此基於 MetaProtocol 進行開發極大簡化了實現一個七層網路代理的工作,我們只需要實現編解碼的少量程式碼,即可得到一個自定義協議的七層代理。一般來說,實現一個自定義協議只需要數百行程式碼。
在基於 MetaProtocol 實現資料面代理後,無需任何控制面編碼,我們就可以通過 Aeraki 在 Isito 服務網格中對使用自定義協議的服務進行管理,為服務提供流量拆分、灰度釋出、流量映象、監控圖表等服務治理能力。這是因為 Aeraki 可以識別基於 MetaProtocol 的任何七層協議,並在控制面提供使用者友好的流量規則。Aeraki 會將這些流量規則翻譯為 MetaProtocol 的配置後下發到資料面。
除了快速開發,節省工作量之外,採用 MetaProtocol 為服務網格開發自定義協議的另一個好處是該方案對 Istio,Envoy,以及 MetaProtocol Proxy 自身等上游開源專案是完全無侵入的,可以跟隨上游專案進行快速迭代,充分利用上游專案新版本提供的新增能力,無需維護自有的 fork 分支。
實現編解碼介面
Aeraki 提供了一個應用協議擴充套件的示例 awesomerpc 。示例中包含了實現自定義協議的程式框架,可以該示例為基礎進行修改,編寫你自己的私有協議。
git clone http://github.com/aeraki-mesh/meta-protocol-awesomerpc.git my-protocol-proxy
我們主要需要關注的是 src/application_protocols/awesomerpc/
目錄下的 awesomerpc_codec.h
和 awesomerpc_codec.cc
。這兩個檔案定義了應用協議的 codec 的介面和實現程式碼。
awesomerpc_codec.h
的定義如下,可以看到應用協議的 codec 繼承於 MetaProtocolProxy::Codec
。實現應用協議只需要實現 decode
, encode
和 onError
三個方法即可。
/** * Codec for Awesomerpc protocol. */ class AwesomerpcCodec : public MetaProtocolProxy::Codec, public Logger::Loggable<Logger::Id::misc> { public: AwesomerpcCodec() {}; ~AwesomerpcCodec() override = default; //協議解碼,需要解析 buffer 並填充 Metadata, Metadata 將被用於 MetaProtocol Proxy 的 filter,例如限流,路由的匹配條件 MetaProtocolProxy::DecodeStatus decode(Buffer::Instance& buffer, MetaProtocolProxy::Metadata& metadata) override; //協議編碼,可以根據 Mutation 對請求或者響應資料包進行修改,例如增加、刪除或者修改 header,修改後需要回寫到 buffer 中 void encode(const MetaProtocolProxy::Metadata& metadata, const MetaProtocolProxy::Mutation& mutation, Buffer::Instance& buffer) override; //錯誤編碼,用於框架向客戶端返回錯誤資訊,例如未找到路由或者連線建立失敗等,編碼的資料需要寫入到 buffer 中 void onError(const MetaProtocolProxy::Metadata& metadata, const MetaProtocolProxy::Error& error, Buffer::Instance& buffer) override; ...
在編寫 codec 時也可以參考 dubbo 和 thrift 的 codec 實現。
配置 WORKSPACE
在根目錄的 WORKSPACE 檔案中配置 metaProtocol, envoy 和 Istio-Proxy 的依賴。
需要在 WORKSPACE 中配置 metaProtocol 的 git commit,envoy 和 Istio-Proxy 的依賴參考 metaProtocol 該 commit 中的 WORKSPACE 中的配置。版本依賴關係參見 Aeraki 和 MetaProtocol 以及 Istio 的版本相容性 。
# 從 meta_protocol_proxy 的程式碼中獲取 envoy 的依賴版本資訊 ENVOY_SHA = "98c1c9e9a40804b93b074badad1cdf284b47d58b" ENVOY_SHA256 = "4365a4c09b9a8b3c4ae34d75991fcd046f3e19d53d95dfd5c89209c30be94fe6" ...... # 從 meta_protocol_proxy 的程式碼中獲取 istio_proxy 的依賴版本資訊 http_archive( name = "io_istio_proxy", strip_prefix = "proxy-1.10.0", sha256 = "19d13bc4859dc8422b91fc28b0d8d12a34848393583eedfb08af971c658e7ffb", url = "http://github.com/istio/proxy/archive/refs/tags/1.10.0.tar.gz", ) ...... # 設定 metaProtocol 的 git commit git_repository( name = "meta_protocol_proxy", remote = "http://github.com/aeraki-mesh/meta-protocol-proxy.git", commit = "5ae1d11", )
編譯
建議使用 Ubuntu 18.04 作為編譯環境。
安裝編譯所需軟體:
sudo wget -O /usr/local/bin/bazel http://github.com/bazelbuild/bazelisk/releases/latest/download/bazelisk-linux-$([ $(uname -m) = "aarch64" ] && echo "arm64" || echo "amd64") sudo chmod +x /usr/local/bin/bazel sudo apt-get install \ autoconf \ automake \ cmake \ curl \ libtool \ make \ ninja-build \ patch \ python3-pip \ unzip \ virtualenv sudo add-apt-repository ppa:ubuntu-toolchain-r/test sudo apt update sudo apt-get install llvm-10 lldb-10 llvm-10-dev libllvm10 llvm-10-runtime clang-10 clang++-10 lld-10 gcc-10 g++-10
構建二進位制:
./build.sh
定義一個 ApplicationProtocol
要在 Istio 中識別自定義協議,需要建立一個 Aeraki 的 ApplicationProtocol CRD 資源。
apiVersion: metaprotocol.aeraki.io/v1alpha1 kind: ApplicationProtocol metadata: name: my-protocol namespace: istio-system spec: protocol: my-protocol codec: aeraki.meta_protocol.codec.my_protocol
協議選擇
Aeraki 通過服務的字首來識別基於 MetaProtocol 的應用協議,服務的埠名必須遵從該命名規則: tcp-metaprotocol-{application protocol}-xxx。 服務定義可以採用 K8s service 或者 Istio ServiceEntry。
下面的 ServiceEntry 定義了一個 dubbo 服務:
apiVersion: networking.istio.io/v1alpha3 kind: ServiceEntry metadata: name: dubbo-demoservice namespace: meta-dubbo spec: hosts: - org.apache.dubbo.samples.basic.api.demoservice ports: - number: 20880 name: tcp-metaprotocol-dubbo protocol: TCP workloadSelector: labels: app: dubbo-sample-provider resolution: STATIC
下面的 Service 定義了一個 Thrift 服務:
apiVersion: v1 kind: Service metadata: name: thrift-sample-server spec: selector: app: thrift-sample-server ports: - name: tcp-metaprotocol-thrift-hello-server protocol: TCP port: 9090 targetPort: 9090
參考文件
- Aeraki Mesh 加入 CNCF 雲原生全景圖
- Aeraki 教程系列:如何開發一個自定義協議?
- Aeraki 教程系列:如何設定全侷限流規則?
- Aeraki 教程系列:如何設定本地限流規則?
- Aeraki 教程系列:如何設定路由規則?
- 譯文:服務網格將使用 eBPF ?是的,但 Envoy 代理將繼續存在
- 合著:Istio 運維實戰(電子書)
- 譯著:雲原生資料中心網路
- 合著:Istio Handbook—Istio 服務網格進階實戰
- 騰訊雲容器網路介紹
- 如何將第三方服務中心註冊整合到 Istio ?
- 一文帶你徹底釐清 Isito 中的證書工作機制
- 一文帶你徹底釐清 Kubernetes 中的證書工作機制