RPC、gRPC與K8S CRI


一、什么是PRC ?

1.1 定義

RPC(Remote Procedure Call),遠程過程調用。是一個計算機通信協議,該協議允許運行於一台計算機的程序調用另一個地址空間(通常為另一台開放網絡的計算機)的子程序。而在開發人員的視角看來,該調用過程和調用本地過程一樣,無需額外編程。在這個過程中,RPC也可以輕易的進行跨語言調用。

舉例來說:存在兩台服務器A,B,在A服務器上部署了一個應用程序,該應用程序需要調用在B服務器上應用提供的函數/方法。RPC的作用,就是讓A可以通過網絡跨內存空間調用B上的函數/方法。

為什么不用Restful接口要提出RPC? Restful接口每次調用時,都需要編寫http請求。RPC能做到的,是像本地調用一樣去發起遠程調用而讓使用者對遠程調用無感知

1.2 組件

  • Server:RPC服務的提供者,上述例子中為服務器B。

  • Client:RPC服務的調用方,上述例子中的服務器A。

  • Client Stub:存放Server的地址信息,再將服務端的請求打包成網絡消息,通過網絡遠程發送給服務方。

  • Server stub:接收客戶端發送過來的消息,將消息解包,並調用本地的方法。

1.3 RPC調用過程

img

(1) 客戶端(client)以本地調用方式(即以接口的方式)調用服務;
(2) 客戶端存根(client stub)接收到調用后,負責將方法、參數等組裝成能夠進行網絡傳輸的消息體(將消息體對象序列化為二進制);
(3) 客戶端通過sockets將消息發送到服務端;
(4) 服務端存根( server stub)收到消息后進行解碼(將消息對象反序列化);
(5) 服務端存根( server stub)根據解碼結果調用本地的服務;
(6) 本地服務執行並將結果返回給服務端存根( server stub);
(7) 服務端存根( server stub)將返回結果打包成消息(將結果消息對象序列化);
(8) 服務端(server)通過sockets將消息發送到客戶端;
(9) 客戶端存根(client stub)接收到結果消息,並進行解碼(將結果消息發序列化);
(10) 客戶端(client)得到最終結果。

RPC將中間過程封裝起來,使用戶無感知。

二、什么是GRPC?

gRPC (Google Remote Procedure Calls) 是Google發起的一個開源遠程過程調用 (Remote procedure call) 系統。該系統基於 HTTP/2 協議傳輸,使用Protocol Buffers 作為接口描述語言。

gRPC是RPC系統的一種。 其基於 HTTP/2 標准設計,帶來諸如雙向流、流控、頭部壓縮、單 TCP 連接上的多復用請求等特性。

2.1 Protocol Buffers

Protocol Buffers是一種序列化數據結構的協議。其包含一個接口描述語言用來描述一些方法與數據結構,並可以通過一些工具來將這些描述轉化為代碼。具體的Protocol語法這里不談,接下來用一個Python gRPC例子說明gRPC基礎概念。

2.2 gRPC Python示例 (參考:daydaygo)

通過代碼往往能加深理解!

環境需求:Python3、Proto3、pip包:grpcio、grpc-tools。

  • 編寫.proto 文件:定義服務 GreeterAPI SayHello。定義請求和回復message格式。
// helloworld.proto
syntax = "proto3";

service Greeter {
    rpc SayHello(HelloRequest) returns (HelloReply) {}
}

message HelloRequest {
    string name = 1;
}

message HelloReply {
    string message = 1;
}
  • 通過grpc-tools編譯protocol文件
python -m grpc_tools.protoc --python_out=. --grpc_python_out=. -I. helloworld.proto
  • python -m grpc_tools.protoc: python 下的 protoc 編譯器通過 python 模塊(module) 實現, 所以說這一步非常省心
  • --python_out=. : 編譯生成處理 protobuf 相關的代碼的路徑, 這里生成到當前目錄
  • --grpc_python_out=. : 編譯生成處理 grpc 相關的代碼的路徑, 這里生成到當前目錄
  • -I. helloworld.proto : proto 文件的路徑, 這里的 proto 文件在當前目錄

​ 編譯后生成兩個Python模塊

  • helloworld_pb2.py: 用來和 protobuf 數據進行交互

  • helloworld_pb2_grpc.py: 用來和 grpc 進行交互

  • gRPC Server實現
from concurrent import futures
import time
import grpc
import helloworld_pb2
import helloworld_pb2_grpc

# 實現 proto 文件中定義的 GreeterServicer
class Greeter(helloworld_pb2_grpc.GreeterServicer):
    # 實現 proto 文件中定義的 rpc 調用
    def SayHello(self, request, context):
        return helloworld_pb2.HelloReply(message = 'hello {msg}'.format(msg = request.name))

def serve():
    # 注冊啟動 rpc 服務
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
    server.add_insecure_port('[::]:50051')
    server.start()
    try:
        while True:
            time.sleep(60*60*24) # one day in seconds
    except KeyboardInterrupt:
        server.stop(0)

if __name__ == '__main__':
    serve()

server端提供了 rpc服務的實現並注冊開啟rpc服務。

  • gRPC Client實現
import grpc
import helloworld_pb2
import helloworld_pb2_grpc

def run():
    # 連接 rpc 服務器
    channel = grpc.insecure_channel('localhost:50051')
    # 調用 rpc 服務
    stub = helloworld_pb2_grpc.GreeterStub(channel)
    response = stub.SayHello(helloworld_pb2.HelloRequest(name='czl'))
    print("Greeter client received: " + response.message)

if __name__ == '__main__':
    run()

三、K8S CRI接口

3.1 CRI是什么?

CRI(Container Runtime Interface)容器運行時接口,定義了容器鏡像的服務的接口。因為容器運行時與鏡像的生命周期是彼此隔離的,因此需要定義兩個服務。該接口使用Protocol Buffer,基於gRPC。使用CRI接口,我們可以通過rpc的方式調用管理k8s集群容器。

3.2 iSula CRI

ISulad使用CRI接口,實現了和kubernetes 的對接。接下來演示python iSula CRI接口的調用。

首先需要通過grpc-io工具編譯CRI proto文件生成核心python模塊並開啟iSulad-CRI服務。

import grpc
import api_pb2_grpc
import api_pb2

if __name__ == '__main__':
	 # connect to rpc service
    channel = grpc.insecure_channel('unix:///var/run/isulad.sock')
    #  rpc server: container and image server
    runtime_stub = api_pb2_grpc.RuntimeServiceStub(channel)
    image_stub = api_pb2_grpc.ImageServiceStub(channel)
    # get iSulad version
    response = runtime_stub.Version(api_pb2.VersionRequest())
    print(response)

其余CRI API調用方式類似,具體參考其proto文件。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM