社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
本文的目的是grpc简单例子,在centos7上的docker上运行单一的grpc服务。
样例项目结构:
一个grpc项目,proto里存放了不同的proto服务文件,比如hello服务的hello目录,里面是hello.proto
grpc下的hello文件夹是服务实现的server端文件夹,以及测试使用的client文件夹
hello.proto文件代码
syntax = "proto3";
package hello;
option go_package ="hello";
service Hello{
rpc SayHello(HelloRequest)returns(HelloResponse){}
}
message HelloRequest{
string name=1;
}
message HelloResponse{
string message =1;
}
server的main.go
package main
import (
"fmt"
"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/grpclog"
"net"
pb "proto/hello"
)
const (
Address = ":50052" //这里不能使用127.0.0.1:50052,因为要放到docker里会导致只能在docker里面才能访问服务
)
//定义helloService并实现约定的接口
type helloService struct{}
var HelloService = helloService{}
//SayHello 实现Hello服务接口
func (h helloService) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloResponse, error) {
resp := new(pb.HelloResponse)
resp.Message = fmt.Sprintf("Hello %s", in.Name)
return resp, nil
}
func main() {
listen, err := net.Listen("tcp", Address)
if err != nil {
grpclog.Fatalf("Failed to listen:%v", err)
}
s := grpc.NewServer()
pb.RegisterHelloServer(s, HelloService)
grpclog.Println("Listen on " + Address)
s.Serve(listen)
}
server的go.mod文件,其中require项是运行main.go程序时自动生成的
module server
go 1.15
replace proto/hello => /root/grpc/proto/hello
require (
golang.org/x/net v0.0.0-20201224014010-6772e930b67b // indirect
google.golang.org/grpc v1.34.0 // indirect
proto/hello v0.0.0-00010101000000-000000000000 // indirect
)
server 的Dockerfile
FROM alpine
ADD main /main
EXPOSE 50052
ENTRYPOINT [ "/main" ]
server的Makefile
GOPATH:=$(shell go env GOPATH)
.PHONY: init
init:
go get -u github.com/golang/protobuf/proto
go get -u github.com/golang/protobuf/protoc-gen-go
go get github.com/micro/micro/v3/cmd/protoc-gen-micro
.PHONY: proto
proto:
protoc --proto_path=. --micro_out=. --go_out=:. proto/userlogin.proto
.PHONY: build
build:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o main *.go
.PHONY: test
test:
go test -v ./... -cover
.PHONY: docker
docker:
docker build . -t main:latest
client的main.go
package main
import (
pb "proto/hello"
"context"
"fmt"
"google.golang.org/grpc"
"google.golang.org/grpc/grpclog"
"sync"
)
const (
Address = "127.0.0.1:50052"
)
//定义helloService并实现约定的接口
type helloService struct{}
var HelloService = helloService{}
func main() {
conn, err := grpc.Dial(Address, grpc.WithInsecure())
if err != nil {
grpclog.Fatalln(err)
}
defer conn.Close()
var wg sync.WaitGroup
wg.Add(100)
for i := 0; i < 100; i++ {
go func(i int) {
c := pb.NewHelloClient(conn)
str := fmt.Sprintf("gRpc,%v", i)
req := &pb.HelloRequest{Name: str}
res, err := c.SayHello(context.Background(), req)
if err != nil {
grpclog.Fatalln(err)
}
fmt.Println(res.Message)
wg.Done()
}(i)
}
wg.Wait()
fmt.Println("main exit")
}
client的go.mod
module client
replace proto/hello => /root/grpc/proto/hello
go 1.15
require (
golang.org/x/net v0.0.0-20201224014010-6772e930b67b // indirect
google.golang.org/grpc v1.34.0
proto/hello v0.0.0-00010101000000-000000000000
)
测试:
在server里执行
make build
./main
在client里直接运行go run main.go
正常运行服务
生成hello服务的docker 镜像,在server里执行make docker
查看镜像docker image ls
运行镜像
docker run --name hello -p 50052:50052 -d main:latest
查看正在运行中的容器
docker ps
[root@localhost server]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
27b50bbe33d6 main:latest "/main" About a minute ago Up About a minute 0.0.0.0:50052->50052/tcp hello
[root@localhost server]#
进入容器查看信息
docker exec -it hello /bin/sh
容器正常监听所有地址的50052端口
本地查看50052端口是哪个程序?是docker
再次运行client的main.go验证服务是否正常
正常运行服务.
如果监听写成127.0.0.1:50052会出现什么错误?
[root@localhost client]# go run main.go
FATAL: 2021/01/10 15:42:28 rpc error: code = Unavailable desc = connection closed
exit status 1
进入docker的容器查看信息
[root@localhost client]# docker exec -it hello /bin/sh
/ # netstat -tulpn
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:50052 0.0.0.0:* LISTEN 1/main
/ #
可以看到docker里监听的只是本地ip,所以出现上面连接失败信息。
下一集,使用k8s管理运行hello服务的docker.
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!