前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Docker部署完整的PHP-RPC-Golang环境

Docker部署完整的PHP-RPC-Golang环境

作者头像
anakinsun
发布2019-06-11 10:37:41
2.1K1
发布2019-06-11 10:37:41
举报
文章被收录于专栏:学习日记学习日记

完全基于docker部署一个php通过rpc访问golang的环境。

基本架构

我们用PHP的Laravel框架来实现一个用户登录的Restful Api,地址为:

代码语言:javascript
复制
POST /user/login

返回信息为用户Id以及JWT token。

Golang用来实现两个服务,一个是用户信息服务,一个是登录的统计服务,PHP通过gRPC与Golang通讯。

最终部署完成后,共有4个docker的container,分别是:

  1. Nginx服务
  2. PHP-FPM服务
  3. 用户信息服务
  4. 登录统计服务

详细步骤

  1. 本地环境准备 我的home目录是/home/anakin
代码语言:javascript
复制
apt install protobuf
apt install composer
mkdir -p www/demo
mkdir www/conf.d
mkdir www/phpini

进入www目录,下载protobuf的代码,我们要用到其中的一个工具:

代码语言:javascript
复制
git clone https://github.com/grpc/grpc.git

进入www/demo目录,创建Laravel项目:

代码语言:javascript
复制
composer create-project laravel/laravel demo
composer require grpc/grpc

稍后我们再来写业务代码。

进入www/conf.d,编写nginx-host.conf,用来解析PHP的服务,内容如下:

代码语言:javascript
复制
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.131,是宿主机的ip地址。 进入www/phpini,编写custom.ini文件,用来加载php需要的扩展,内容如下:

代码语言:javascript
复制
extension=grpc.so
extension=protobuf.so
  1. 运行PHP的container
代码语言:javascript
复制
mkdir www/phpdocker
cd www/phpdocker

编写Dockerfile,内容如下:

代码语言:javascript
复制
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

创建image:

代码语言:javascript
复制
docker build . -t php-fpm:v1.0

运行起来:

代码语言:javascript
复制
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项目代码的目录进去。

  1. 运行Nginx的container
代码语言:javascript
复制
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

映射了我们刚才存放host文件的目录进去

  1. 准备rpc服务 首先编写用户信息服务的userrpc.proto文件,内容如下:
代码语言:javascript
复制
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文件,内容如下:

代码语言:javascript
复制
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的客户端代码:

代码语言:javascript
复制
protoc --php_out=./ --grpc_out=./ --plugin=protoc-gen-grpc=/home/aaa/grpc/bins/opt/grpc_php_plugin userrpc.proto

生成golang服务端代码:

代码语言:javascript
复制
protoc --go_out=./ userrpc.proto

trace的类似。

  1. 开发golang服务

在GOPATH下面创建一个user目录,user下面再创建一个userrpc目录,将刚刚生成的userrpc.pb.go放到userrpc目录中。 在user目录下编写main.go,内容如下:

代码语言:javascript
复制
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)
}

编译

代码语言:javascript
复制
GOOS=linux GOARCH=amd64 go build -o UserRpcService

新建一个目录,把编译好的UserRpcService文件放进去,然后编写一个golang的Dockerfile,内容如下:

代码语言:javascript
复制
FROM golang
WORKDIR /go/src/
COPY . .
EXPOSE 50051
CMD ["/go/src/UserRpcService"]

把这个目录放到宿主机的某个位置,然后进入目录,执行创建image的操作:

代码语言:javascript
复制
docker build .  -t userrpc:v1.0 

运行服务:

代码语言:javascript
复制
docker run  -p 50051:50051 -d userrpc:v1.0

trace服务和这个步骤完全一样,就不复述了。

  1. 开发php服务

进入www/demo目录,把上面生成的rpc客户端代码加入到Laravl项目中,首先把生成的GPBMetadata目录拷贝到www/demo目录,然后把生成的App下面的UserRpc目录拷贝到www/demo/app目录。

打开www/demo目录下的composer.json,在classmap下添加一行:

代码语言:javascript
复制
GPBMetadata

然后执行:

代码语言:javascript
复制
composer dump-autoload

编辑www/demo/routes/web.php文件,添加下面一行:

代码语言:javascript
复制
Route::post('user/login','UserController@login');

在www/demo/config目录下创建constants.php文件,内容如下:

代码语言:javascript
复制
<?php
return [
    "USER_RPC_SERVICE"=>"192.168.32.131:50051",
    "TRACE_RPC_SERVICE"=>"192.168.32.131:50052",
];

在app/Http/Controllers目录下创建UserController.php文件,内容如下:

代码语言:javascript
复制
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Log;
use Config;

class UserController extends Controller
{
        //
        public function login(Request $request){
                $loginname = $request->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端口,来看看是不是可以访问了。希望我没有遗漏什么步骤。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年06月03日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 基本架构
  • 详细步骤
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档