読者です 読者をやめる 読者になる 読者になる

SDN開発エンジニアを目指した活動ブログ

〜SDNなオープンソース製品を実際に使って試してみる〜

GoBGPでの内部構造で活用されている"gRPC"の仕組みを体験してみる

[ 2016.4.29修正:gRPC最新版への対応 ]
最近、GoBGPでの内部構造として活用されている"gRPC"に興味を持ち始めました。
GoBGP実践活用として、Ryu SDN Framework連携を実現するためには、gRPC技術の修得が必要不可欠になりそうなので、まずは、gRPCを体験するところから始めたいと思います。

◆ gRPCとは?

googleが開発したオープンソースベースのRPCフレームワークだそうです。各種プログラミング言語に対応しているみたいで、データ通信層には、HTTP/2が活用されるらしいです。
以下、Google Developers Japan: 新しいオープン ソース HTTP/2 RPC フレームワーク、gRPC のご紹介より引用です。

Google は本日( 2 月 26 日)、リモート プロシージャ コール処理の新しいフレームワークである gRPC をオープンソース化します。このフレームワークBSD ライセンスで、最近承認された HTTP/2 標準に基づき、一般的なプログラミング言語やプラットフォームにおける効率的で拡張性豊かな API やマイクロサービスの作成をサポートしています。Google では、長期的な HTTP/2 に対するコミットメントの一つの現れとして gRPC の使用を既に開始しており、gRPC エンドポイントを通じて数多くの正式なサービスを公開しています。

なお、サーバ/クライアント間でのシリアライズ化などの通信処理は、特に意識することなく、IDLのプリコンパイルによって自動生成されるスタブが担うことになります。
さらに、IDLの記述仕様は、以下のサイトが参考になります。
developers.google.com

このあたりの開発作業スタイルは、その昔の、"DCE/RPCプログラミング"による分散処理システム構築時の実装スタイルとそっくりな感じです。
... まず、rpcgenで、IDLファイルをプリコンパイルしてスタブを自動生成して、サーバ・クライアントアプリに組み込むあたりが...

◆ gRPC環境準備

今回は、Golang/Python版でのgRPC動作環境を作成してみます。
なお、Python版のgRPCのstable版がリリースされていないので、結構、煩雑なインストール手順になっております。
現時点でのインストール手順は、あくまでも参考程度にとどめておいてください。
今後のstable版リリースされる頃には、pipコマンド一発でインストールできることを期待したいところです。

0. Ubuntu環境準備
将来のRyu SDN Framework連携を想定して、ここでは、敢えて、Ubuntuサーバ環境を使用します。

$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=14.04
DISTRIB_CODENAME=trusty
DISTRIB_DESCRIPTION="Ubuntu 14.04.3 LTS"

1. GoBGPのインストール
今回は、gRPCサンプルアプリをサーバ側で動作させる際には、golangが必要になります。
GoBGP環境も、同時に作成しておきます。

$ vi $HOME/.profile
—————————
... (snip)
export GOPATH=$HOME/golang
export PATH=$GOPATH/bin:/usr/local/go/bin:$PATH

$ wget --no-check-certificate https://storage.googleapis.com/golang/go1.6.2.linux-amd64.tar.gz
$ sudo tar -C /usr/local -xzf go1.6.2.linux-amd64.tar.gz
$ mkdir $HOME/golang
$ source .profile

$ sudo apt-get update
$ sudo apt-get install git
$ go get -u github.com/osrg/gobgp/gobgpd
$ go get -u github.com/osrg/gobgp/gobgp
$ go get github.com/golang/protobuf/protoc-gen-go

2. Protocol Buffersのインストール
Protocol Buffersをインストールします。

$ cd $HOME
$ wget https://github.com/google/protobuf/archive/v3.0.0-beta-2.tar.gz
$ tar xvzf v3.0.0-beta-2.tar.gz
$ cd protobuf-3.0.0-beta-2

$ sudo apt-get install autoconf
$ sudo apt-get install unzip
$ sudo apt-get install Libtool
$ sudo apt-get install g++
$ sudo apt-get install make
$ ./autogen.sh
$ ./configure
$ make
$ sudo make install

$ cd $HOME
$ vi .profile
—————————
... (snip)
export LD_LIBRARY_PATH=/usr/local/lib

$ source .profile 
$ protoc --version
libprotoc 3.0.0

3. gRPC for Pythonのインストール
python版gRPCをインストールします。

$ sudo apt-get update
$ cd $HOME
$ mkdir work
$ cd work
$ git clone https://github.com/grpc/grpc.git
$ cd grpc
$ git checkout -b release-0_13_1 refs/tags/release-0_13_1
$ git submodule update --init
$ make
$ sudo make install

4. Python版Protocol Buffersライブラリのインストール
Python版Protocol Buffersライブラリをインストールします

$ sudo apt-get install python-dev
$ sudo apt-get install python-pip
$ cd $HOME/protobuf-3.0.0-beta-2/python
$ sudo python ./setup.py install
$ sudo pip install grpcio
$ sudo pip install gevent

5. Ryuのインストール
Ryu SDN Framework連携用に、Ryuをインストールします。

$ cd $HOME
$ sudo apt-get -y install libxml2-dev
$ sudo apt-get -y install python-lxml
$ sudo pip install --upgrade six
$ git clone https://github.com/osrg/ryu.git
$ cd ryu/tools
$ sudo pip install -r pip-requires
$ cd ..
$ sudo python ./setup.py install
$ ryu-manager --version
ryu-manager 4.1

◆ gRPCのサンプルアプリ"hello world"を動かしてみる

ここでのサンプルアプリの動作環境の特徴としては、サーバ/クライアント間で異なるプログラミング環境でも、gRPCサーバ/クライアント間での相互運用が可能になっております。
すなわち、サーバ側をgolangで実行し、クライアント側をpythonで実行させています。

1. IDLファイル準備
以下のIDLファイル”helloworld.proto”を、任意ディレクトリ(ここでは、"helloworld"とします)に保存します。

$ cd $HOME
$ mkdir helloworld
$ cd helloworld
$ vi helloworld.proto
------------
syntax = "proto3";

option java_package = "io.grpc.examples";

package helloworld;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}

2. クライアントアプリ準備
まずは、クライアント作業ディレクトリ"client"に移動して、先ほどのIDLファイルをコンパイルします。
すると、"helloworld_pb2.py"が自動生成されます。

$ cd $HOME/helloworld
$ mkdir client
$ cd client/
$ protoc -I .. --python_out=. --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_python_plugin` ../helloworld.proto
$ ls -l
total 8
-rw-rw-r-- 1 tsubo tsubo 5566 Apr 29 21:40 helloworld_pb2.py

さらに、"greeter_client.py"を同じディレクトリに配備します。

$ vi greeter_client.py
----------------------------
from grpc.beta import implementations

import helloworld_pb2

_TIMEOUT_SECONDS = 10


def run():
  channel = implementations.insecure_channel('localhost', 50051)
  stub = helloworld_pb2.beta_create_Greeter_stub(channel)
  response = stub.SayHello(helloworld_pb2.HelloRequest(name='you'), _TIMEOUT_SECONDS)
  print "Greeter client received: " + response.message


if __name__ == '__main__':
  run()

3. サーバアプリ準備
つぎに、サーバ作業ディレクトリ"server"に移動して、先ほどのIDLファイルをコンパイルします。
すると、"helloworld.pb.go"が自動生成されます。

$ cd $HOME/helloworld
$ mkdir server
$ cd server/
$ protoc -I .. --go_out=plugins=grpc:. ../helloworld.proto
$ ls -l
total 8
-rw-rw-r-- 1 tsubo tsubo 4903 Apr 29 21:55 helloworld.pb.go

さらに、"greeter_server.go"を配備します。

$ vi greeter_server.go
----------------------------
package main

import (
        "log"
        "net"

        pb "google.golang.org/grpc/examples/helloworld/helloworld"
        "golang.org/x/net/context"
        "google.golang.org/grpc"
)

const (
        port = ":50051"
)

// server is used to implement hellowrld.GreeterServer.
type server struct{}

// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
        return &pb.HelloReply{Message: "Hello " + in.Name}, nil
}

func main() {
        lis, err := net.Listen("tcp", port)
        if err != nil {
                log.Fatalf("failed to listen: %v", err)
        }
        s := grpc.NewServer()
        pb.RegisterGreeterServer(s, &server{})
        s.Serve(lis)
}

4. サンプルアプリ起動
まずは、サーバ側サンプルアプリを起動します。

$ go run greeter_server.go

続いて、別ターミナルから、クライアントアプリを起動します。
"Greeter client received: Hello you"と出力されるとサンプル起動は、成功です。

$ python greeter_client.py 
Greeter client received: Hello you

この時、gRPCクライアント/サーバ間でのデータ通信の様子をキャプチャしてみました。
HTTP2通信が使われていることが確認できました。
f:id:ttsubo:20151011182652p:plain

◆ 終わりに

GoBGP活用として、Ryu SDN Framework連携を目指した初めの一歩として、gRPCによるサンプルアプリを動作させてみました。
次回は、GoBGP実践活用の前段として、Pythonアプリ連携にチャレンジしてみます。