de1ux

gRPC with Typescript and Go (part 1)

11/14/2018

One of the best tools for diagnosing failed Kubernetes deployments is with the log viewer, kubectl logs.

But direct kubectl logs may be restricted to Ops if your organization doesn’t allow engineers access to the Kubernetes cluster.

Or, our end users might not be engineers at all, but still want something to send along with a report.

Either way it’s a convenient excuse to build a webapp that gives anyone with a browser the same functionality as kubectl logs.

Messaging

The gRPC messages the browser will use to request logs from the Go service must be defined:

syntax="proto3";

message GetLogsRequest {
    string podName = 1;
}

message GetLogsResponse {
  repeated string data = 1;
}

service LogService {
  rpc GetLogs(GetLogsRequest) returns (GetLogsResponse);
}

If you don’t already have protoc available in your $PATH, install it from the releases page.

And then install the language-specific plugins

# Install the protobuf plugin for Go
$ go mod init
$ go get -u github.com/golang/protobuf/protoc-gen-go

# Install the protobuf plugin for Typescript
$ npm init
$ npm i --save-dev ts-protoc-gen

Now we can run protoc on the protobuf definitions

# Make a folder for the output
$ mkdir generated
$ protoc \
    --plugin="protoc-gen-ts=node_modules/ts-protoc-gen/bin/protoc-gen-ts" \
    --ts_out="service=true:generated" \
    --go_out="plugins=grpc:generated" \
    service.proto

and see some generated client/server code in the generated folder:

$ ls -ltr generated
total 40
-rw-r--r--  1 nathanevans  staff  1455 Nov 22 21:12 service_pb_service.js
-rw-r--r--  1 nathanevans  staff  2065 Nov 22 21:12 service_pb_service.d.ts
-rw-r--r--  1 nathanevans  staff  1562 Nov 22 21:12 service_pb.d.ts
-rw-r--r--  1 nathanevans  staff  5804 Nov 22 21:12 service.pb.go

Let’s move on to the backend!

Go service

Here’s some code for the backend service, with stubs filled in for the kube-api-server bits.

package main

import (
    "context"
    "log"
    "net/http"

    "github.com/improbable-eng/grpc-web/go/grpcweb"
    api "gitlab.com/de1ux/blog_examples/grpc-with-typescript-and-go/generated"
    "google.golang.org/grpc"
)

type service struct{}

func (service) GetLogs(_ context.Context, request *api.GetLogsRequest) (*api.GetLogsResponse, error) {
    panic("implement me")
}

func main() {
    grpcServer := grpc.NewServer()

    api.RegisterLogServiceServer(grpcServer, &service{})

    wrappedGrpcServer := grpcweb.WrapServer(grpcServer)

    log.Print("Accepting requests...")
    if err := (&http.Server{
        Handler: wrappedGrpcServer,
        Addr:    "0.0.0.0:9999",
    }).ListenAndServe(); err != nil {
        log.Fatal(err)
    }
}

main.go does a few things

Next

In the next part, we’ll write something useful for the GetLogs endpoint and build the frontend.