Dockerは完全なPHP-RPC-Golang環境を配備する

10131 ワード

phpがrpcを介してgolangにアクセスする環境をdockerに完全に基づいて配置します.
基本アーキテクチャ
PHPのLaravelフレームワークを使用して、ユーザー登録Restful Apiを実現します.アドレスは次のとおりです.
POST /user/login

返される情報は、ユーザIdおよびJWT tokenである.
Golangは2つのサービスを実現するために使用され、1つはユーザー情報サービスであり、1つはログイン統計サービスであり、PHPはgRPCを通じてGolangと通信する.
最終的な導入が完了すると、4つのdockerのcontainerがあります.それぞれ:
  • Nginxサービス
  • PHP-FPMサービス
  • ユーザ情報サービス
  • 登録統計サービス
  • 詳細手順
  • ローカル環境私のホームディレクトリは/home/anakin
  • です.
    apt install protobuf
    apt install composer
    mkdir -p www/demo
    mkdir www/conf.d
    mkdir www/phpini
    

    wwwディレクトリに入りprotobufのコードをダウンロードし、その中の1つのツールを使用します.
    git clone https://github.com/grpc/grpc.git
    

    www/demoディレクトリに入り、Laravelプロジェクトを作成します.
    composer create-project laravel/laravel demo
    composer require grpc/grpc
    

    後でビジネスコードを書きます.
    www/conf.dに入り、nginx-hostを作成します.confは、PHPを解析するためのサービスで、内容は以下の通りです.
    server {
            listen  80;
                    server_name 192.168.32.131;
                    set $root_path '/var/www/html/public';
                    root $root_path;
    
                    index index.php index.html index.htm;
    
                    try_files $uri $uri/ @rewrite;
    
                    location @rewrite {
                            rewrite ^/(.*)$ /index.php?_url=/$1;
                    }
    
                    location ~ \.php {
                            fastcgi_pass 192.168.32.131:9000;
                            # fastcgi_pass unix:///run/php/php7.2-fpm.sock;
                            fastcgi_index /index.php;
                            fastcgi_split_path_info ^(.+\.php)(/.+)$;
                            fastcgi_param PATH_INFO       $fastcgi_path_info;
                            fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
                            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                            include                       fastcgi_params;
                    }
    
                    location ~* ^/(css|img|js|flv|swf|download)/(.+)$ {
                            root $root_path;
                    }
    
                    location ~ /\.ht {
                            deny all;
                    }
                    error_log  /tmp/error.anakin.com.log    error;
        }
    

    そのうち、192.168.32.3131は、ホストのipアドレスです.www/phpiniに入りcustomを書くiniファイル、phpに必要な拡張子をロードします.内容は次のとおりです.
    extension=grpc.so
    extension=protobuf.so
    
  • PHPを運転するcontainer
  • mkdir www/phpdocker
    cd www/phpdocker
    

    Dockerfileを作成します.内容は次のとおりです.
    FROM php:7.2-fpm
    RUN apt-get update && apt-get install -y \
            libfreetype6-dev \
            libjpeg62-turbo-dev \
            libpng-dev \
            procps \
        && docker-php-ext-install -j$(nproc) iconv \
        && docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \
        && docker-php-ext-install -j$(nproc) gd \
        && docker-php-ext-install pdo_mysql \
        && docker-php-ext-install zip \
        && pecl install grpc\
        && pecl install protobuf
    RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \
            && composer config -g repo.packagist composer https://packagist.phpcomposer.com
    

    イメージの作成:
    docker build . -t php-fpm:v1.0
    

    実行:
    docker run -d -p 9000:9000 -v /home/anakin/www/demo:/var/www/html -v /home/anakin/www/phpini:/usr/local/etc/php/conf.d --name php-fpm php72:v1.0
    

    Laravelプロジェクトコードを保持するディレクトリをマッピングしました.
  • Nginxを実行するcontainer
  • docker run -d --name nginx -p 80:80 -v /home/anakin/www/demo:/var/www/html -v /home/anakin/www/conf.d:/etc/nginx/conf.d --link php-fpm:php-fpm nginx
    

    さっきホストファイルを保存したディレクトリをマッピングしました
  • rpcサービスを準備するまずユーザ情報サービスのuserrpcを記述する.protoファイル、内容は以下の通り:
  • syntax = "proto3";
    package App.UserRpc;
    
    
    service User{   
      rpc UserLogin(LoginInfo) returns (UserInfo) {}
    }
    
    message LoginInfo{
      string loginname= 1;
      string password= 2;
    }
    
    
    message UserInfo{    
     int32 code= 1;
      string err_msg= 2;
      string token= 3;
      int32 userid= 4;
      string username= 5;
    }
    

    統計サービス用のtraceを作成する.protoファイル、内容は以下の通りです.
    syntax = "proto3";
    package App.Trace;
    
    
    service Trace{   
      rpc Event(EventInfo) returns (TraceResult) {}
    }
    
    message EventInfo{
      string eventtype= 1;
      int32 userid= 2;
      int32 timestamp= 3;
    }
    
    
    message TraceResult{    
      bool succ= 1;
    }
    

    PHPのクライアントコードを生成する:
    protoc --php_out=./ --grpc_out=./ --plugin=protoc-gen-grpc=/home/aaa/grpc/bins/opt/grpc_php_plugin userrpc.proto
    

    golangサービス・エンド・コードを生成するには、次の手順に従います.
    protoc --go_out=./ userrpc.proto
    

    traceの類似.
  • golangサービス開発
  • GOPATHの下にuserディレクトリを作成し、userの下にuserrpcディレクトリを作成し、生成したばかりのuserrpcを作成します.pb.goはuserrpcディレクトリに格納されます.userディレクトリの下にmainを記述する.go、内容は以下の通りです.
    package main
    
    import (
    	"context"
    	pb "github.com/anakin/user/userrpc"
    	"github.com/dgrijalva/jwt-go"
    	"google.golang.org/grpc"
    	"log"
    	"net"
    	"time"
    )
    
    const (
    	port = ":50052"
    )
    
    type User struct {
    }
    
    func (u *User) UserLogin(ctx context.Context, req *pb.LoginInfo) (*pb.UserInfo, error) {
    	log.Printf("received login_name:%v;password:%v", req.Loginname, req.Password)
    	//mock data
    	userId:=123
    	userName := "anakin"
    
    	//make jwt token
    	claim := jwt.MapClaims{
    		"id":       userId,
    		"username": userName,
    		"nbf":      time.Now().Unix(),
    		"iat":      time.Now().Unix(),
    	}
    	token := jwt.NewWithClaims(jwt.SigningMethodHS256,claim)
    	tokenString,err  := token.SignedString([]byte("token.secret"))
    	if err !=nil{
    		log.Printf("signed error")
    	}
    	return &pb.UserInfo{Code: 200, ErrMsg: "sss", Userid: 1, Token: tokenString, Username: "anakin"}, nil
    }
    
    func main() {
    	listener, err := net.Listen("tcp", port)
    	if err != nil {
    		log.Fatalf("failed to listen:%v", err)
    	}
    	s := grpc.NewServer()
    	pb.RegisterUserServer(s, &User{})
    	s.Serve(listener)
    }
    

    コンパイル
    GOOS=linux GOARCH=amd64 go build -o UserRpcService
    

    新しいディレクトリを作成し、コンパイルしたUserRpcServiceファイルを入れ、golangのDockerfileを作成します.内容は次のとおりです.
    FROM golang
    WORKDIR /go/src/
    COPY . .
    EXPOSE 50051
    CMD ["/go/src/UserRpcService"]
    

    このディレクトリをホストのある場所に配置し、ディレクトリに入り、imageを作成する操作を実行します.
    docker build .  -t userrpc:v1.0 
    

    サービスの実行:
    docker run  -p 50051:50051 -d userrpc:v1.0
    

    traceサービスはこの手順と全く同じで、復唱しません.
  • phpサービス
  • を開発
    www/demoディレクトリに入り、上で生成したrpcクライアントコードをLaravlプロジェクトに追加し、まず生成したGPBMetadataディレクトリをwww/demoディレクトリにコピーし、次に生成したApp下のUserRpcディレクトリをwww/demo/appディレクトリにコピーする.
    www/demoディレクトリの下のcomposerを開きます.json、classmapの下に行を追加します.
    GPBMetadata
    

    次に、
    composer dump-autoload
    

    www/demo/routes/webを編集します.phpファイル、次の行を追加します.
    Route::post('user/login','UserController@login');
    

    www/demo/configディレクトリの下にconstantsを作成する.phpファイル、内容は以下の通りです.
    "192.168.32.131:50051",
        "TRACE_RPC_SERVICE"=>"192.168.32.131:50052",
    ];
    

    UserControllerをapp/Http/Clontrollersディレクトリの下に作成します.phpファイル、内容は以下の通りです.
    input("loginname");
                    $password = (string)$request->input("password");
                    if($loginname == "" || $password == ""){
                            return response()->json(["code"=>400,"msg"=>"param error","data"=>[]]);
                    }
                    $user_rpc_service= Config::get('constants.USER_RPC_SERVICE');
                    $userrpc = new \App\UserRpc\UserClient($user_rpc_service,[
                                    'credentials' => \Grpc\ChannelCredentials::createInsecure()
                    ]);
                    $request = new \App\UserRpc\LoginInfo();
                    $request->setLoginname($loginname);
                    $request->setPassword($password);
                    list($recv,$status) = $userrpc->UserLogin($request)->wait();
                    $code = $recv->getCode();
                    $msg = $recv->getErrMsg();
                    $token = $recv->getToken();
                    $user_id = $recv->getUserid();
                    $username = $recv->getUsername();
                    if(200 !=$code){
                            return response()->json(["code"=>$code,"msg"=>$msg,"data"=>[]]);
                    }
                       $trace_rpc_service = Config::get('constants.TRACE_RPC_SERVICE');
                    $tracerpc = new \App\Trace\TraceClient($trace_rpc_service,[
                                    'credentials' => \Grpc\ChannelCredentials::createInsecure()
                    ]);
                    $info = new \App\Trace\EventInfo();
                    $info->setEventtype("user_login");
                    $info->setUserid("1");
                    $info->setTimestamp(time());
                    list($recv,$status) = $tracerpc->Event($info)->wait();
                    $trace_succ = $recv->getSucc();
                    $trace_res = $trace_succ == 1 ? "succ" : "fail";
                    Log::info("trace result:".$trace_res);
                    return response()->json(["code"=>200,"data"=>["token"=>$token,"userid" =>$user_id,"username"=>$username]]);
            }
    
    }
    

    今、POSTホストipの80ポートにアクセスできるかどうか見てみましょう.何の手順も漏れていないことを願っています.