使用Connect-Go+Docker来建立服务器开发环境

这篇文章是 Cocone Advent Calendar 2023 中的第9篇。

首先

最近由于各种情况,开始使用connect-go。
这次我们想要简化使用方法,并使用Docker进行protocol buffer编译,以便能够立即开始开发。为此,我们总结了所需的步骤。
※假设您可以使用golang和Docker来进行操作。

关于connect-go

这是一个能够以gRPC互换方式、更轻巧更智能地使用的HTTP API库。本次我们使用golang,但它也在不同的环境中进行了兼容,如web、kotlin、swift、node等等。它支持Unary RPC、Client Streaming RPC、Server Streaming RPC和Bidirectional Streaming RPC,虽然本次不详细介绍,但也可以使用各种拦截器。

即使系统已经在gRPC上构建,也相对容易地进行切换。如果在“计划在应用上发布,但也考虑在Web上发布”的情况下,由于可以直接在一份代码中进行适配,跨平台已经成为当今的事实标准,非常有吸引力。

还有一点要提及的是,最近也有关于客户端(Unity)支持HTTP/2的讨论,所以在这方面也有考虑切换的余地。

 

目录结构

.
├─ protos
|  └─ echo.proto
├─ server
│  └─ main.go
├─ buf.gen.yaml
├─ docker-compose.yaml
├─ Dockerfile.proto
└─ generate-proto.sh

原型

syntax = "proto3";

package pb;
option go_package = ".;pb";

service EchoService {
    rpc Echo(EchoRequest) returns (EchoResponse) {}
}
  
message EchoRequest { string msg = 1; }

message EchoResponse { string msg = 1; }

准备构建容器用于proto。

接下来,我们将建立一个能够构建proto的环境。

docker-compose.yaml 文件

为了方便地管理这次的组合,我使用了docker-compose。它所做的事情很简单,只是挂载所需的文件并启动构建脚本。

version: "3.7"

services:
  proto_builder_connect_go:
    build:
      context: ./
      dockerfile: ./Dockerfile.proto
    volumes:
      - ./protos:/builder/protos
      - ./server/gen/pb:/builder/gen
    command: bash generate-proto.sh

Dockerfile

下面是Dockerfile。安装了连接go所需的各种模块。

FROM golang:1.20.10-bullseye

WORKDIR /builder

RUN apt update && apt install -y unzip rsync clang-format vim

COPY ./generate-proto.sh ./
COPY ./buf.gen.yaml ./

RUN go install github.com/bufbuild/buf/cmd/buf@latest
RUN go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest
RUN go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
RUN go install github.com/bufbuild/connect-go/cmd/protoc-gen-connect-go@latest

ENV PATH $PATH:/root/.local/bin/:/go/bin/

buf.gen.yaml

这是构建配置。如果您可以参考链接获得更多详细信息,但是样本将输出到 server/gen/pb 作为产物。

version: v1
managed:
  enabled: true
  go_package_prefix:
    default: server/gen/pb
plugins:
  - name: go
    out: gen
    opt: paths=source_relative
  - name: connect-go
    out: gen
    opt: paths=source_relative

 

生成-原型.sh

最后是构建脚本。通过调用 buf generate,我们可以从创建的 proto 文件中生成可用于 golang 的代码。

#!/bin/bash

set -e -o pipefail

PROTO_DIR='/builder/protos'
OUT_TMP='/builder/gen'

buf generate --template buf.gen.yaml protos
exit 0

执行

docker-compose -f docker-compose.yaml up

当执行完成后,将在 server/gen/pb 目录下生成以下文件。现在已准备就绪,我们将试试在实际的Golang中使用。

    • echo.pb.go

 

    pbconnect/echo.pbconnect.go

准备golang方面的工作

# モジュール初期化
cd server
go mod init server

# 必要なパッケージを取得
go get google.golang.org/protobuf
go get github.com/bufbuild/connect-go
go get github.com/bufbuild/connect-grpcreflect-go
go get golang.org/x/net

# メインファイル作成
touch main.go

这是服务器的实施。

package main

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"server/gen/pb"
	"server/gen/pb/pbconnect"

	"github.com/bufbuild/connect-go"
	grpcreflect "github.com/bufbuild/connect-grpcreflect-go"
	"golang.org/x/net/http2"
	"golang.org/x/net/http2/h2c"
)

func main() {
	log.Println("setup server")
	// EchoServiceの作成
	echoService := EchoService{}

	// サービス登録
	mux := http.NewServeMux()
	handle := mux.Handle
	handle(pbconnect.NewEchoServiceHandler(echoService))

	// テスト用にリフレクションサービスを利用
	reflector := grpcreflect.NewStaticReflector(
		pbconnect.EchoServiceName,
	)
	handle(grpcreflect.NewHandlerV1(reflector))

	// サーバー起動
	log.Println("start server")
	if err := http.ListenAndServe(
		":8090",
		h2c.NewHandler(mux, &http2.Server{}),
	); err != nil {
		log.Fatal(err)
	}
}

// EchoService: EchoServiceの実装
type EchoService struct{}

// Echo: 送られてきたメッセージをそのまま返す
func (s EchoService) Echo(ctx context.Context, req *connect.Request[pb.EchoRequest]) (*connect.Response[pb.EchoResponse], error) {
	log.Println("EchoService.Echo:", req.Msg.Message)
	return connect.NewResponse(&pb.EchoResponse{
		Message: fmt.Sprintf("%s from server", req.Msg.Message),
	}), nil
}

实际上尝试调用一下

启动服务器,并尝试使用grpcurl或curl访问。

cd server
go run main.go

>2023/12/06 09:42:44 setup server
>2023/12/06 09:42:44 start server
# curl
curl --header "Content-Type: application/json" --data '{"message": "hello"}' http://localhost:8080/pb.EchoService/Echo
>{"message":"hello from server"}

# grpccurl
grpcurl -plaintext -d '{"message": "hello"}' localhost:8080 pb.EchoService/Echo
>{
>  "message": "hello from server"
>}

最终

在Unity的gRPC支持问题出现时,Cysharp发表了可以在Unity中使用HTTP/2的YetAnotherHttpHandler,并出现了将客户端从gRPC切换到HTTP/2的场景。

在这种情况下,提前创造一个更顺利的情况是非常重要的,我认为这种积累将导致更好的开发环境和更好的服务,所以如果您目前使用gRPC,不妨考虑转换为这个机会。
在这种情况下,提前创造一个更顺利的情况是非常重要的,我认为这种积累将导致更好的开发环境和更好的服务,因此,如果您目前使用gRPC,不妨考虑这个机会进行切换。

 

广告
将在 10 秒后关闭
bannerAds