2019.07.05

Developing with Java gRPC, Docker and IntelliJ

Pocket

こんにちは、次世代システム研究室のN.M.です。

If you haven’t already heard, the nice folks at Google have open sourced their framework for creating internal APIs, it’s called gRPC. gRPC is based on RPC and uses Google’s protobuf data exchange format by default. You define your API in a .proto file, which the gRPC framework uses to generate code and stubs in your target programming language. In this I will talk about setting up a development environment for Java gRPC. To test our setup we will use one of the three supplied example applications, routeguide. IntelliJ will be used as the IDE. We will use Docker to run the gRPC server. I used a MacBook Pro for this, but most of the steps should be transferable to Windows.

Install protoc

$ brew install protobuf

Or use the binaries found at https://github.com/protocolbuffers/protobuf/releases, click on assets for the desired version and download the zip  distribution file for your platform. See the README for details on how to install, but it should be as easy as unziping and copying the enclosed protoc binary into a location on your path.

Install Java gRPC

From git:

$ git clone git@github.com:grpc/grpc-java.git

Build Docker for Java gRPC

This Dockerfile sets up a gRPC capable linux container.

FROM openjdk:10

ENV PROTOBUF_VERSION=3.8.0

RUN curl -LO https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-x86_64.zip && \
        unzip protoc-${PROTOBUF_VERSION}-linux-x86_64.zip -d /usr

ENV JAVA_OPTS=-agentlib:jdwp=transport=dt_socket,server=y,address=*:8000,suspend=n

# runs application
 CMD ["tail", "-f", "/dev/null"]

  You can see that first we will use the OpenJDK version 10 as our base machine. We then install Google Protocol Buffers version 3.8.0. We then define JAVA_OPTS that will later allow us to remote debug the gRPC server running on this docker machine. Save the above as Dockerfile, in a convenient location, I suggest under grpc-java/examples, since we will be doing most of our work around here. cd to the same folder as your Dockerfile and build your Docker image.

$ docker build -t grpc-java:latest .
Sending build context to Docker daemon 18.24MB
Step 1/5 : FROM openjdk:10
---> b11e88dd885d
Step 2/5 : ENV PROTOBUF_VERSION=3.8.0
---> Using cache
---> 138ec8eb8c08
Step 3/5 : RUN curl -LO https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-x86_64.zip && unzip protoc-${PROTOBUF_VERSION}-linux-x86_64.zip -d /usr
---> Using cache
---> 4aa5913d2e91
Step 4/5 : ENV JAVA_OPTS=-agentlib:jdwp=transport=dt_socket,server=y,address=*:8000,suspend=n
---> Using cache
---> db03b5daf8f9
Step 5/5 : CMD ["tail", "-f", "/dev/null"]
---> Using cache
---> 1cd3468bed45
Successfully built 1cd3468bed45
Successfully tagged grpc-java:latest

Run the gRPC Docker Container

$ docker run -d --name grpc -v /<FULL PATH>/grpc-java/examples:/var/grpc-java -p 8980:8980 -p 8000:8000 grpc-java:latest 98823ee7dc062a0dcef3ef453c4302dc9270014bc71262613a0bf419092bdaa2


The above command maps our host directory /<FULL PATH>/grpc-java/examples to a directory in the docker machine, /var/grpc-java.

It also maps the host port 8980 to the docker port 8980 and the host port 8000 to the docker port 8000. So the client can run on the host and access to 8980 and our debugger can run on the host and access 8000.

Login to the docker machine

$ docker exec -it 98823ee7dc062a /bin/bash
root@98823ee7dc06:/#

start the server

root@98823ee7dc06:/# cd /var/grpc-java/build/install/examples/bin
root@98823ee7dc06:/var/grpc-java/build/install/examples/bin# ./route-guide-server
Listening for transport dt_socket at address: 8000
Jul 02, 2019 11:20:35 AM io.grpc.examples.routeguide.RouteGuideServer start
INFO: Server started, listening on 8980

  From the output above we can see that the server is started and listening on port 8980 for connections from the client, and also that the JVM is listening to port 8000 for remote debugging.

Developing

If you look at the the build.gradle file you will see that this project uses the idea plugin, so we can get the project ready to open for IntelliJ using the command below:

$ ./gradlew idea
Starting a Gradle Daemon (subsequent builds will be faster)
> Task :idea
Generated IDEA project at file:///<FULL PATH>/grpc-java/examples/examples.ipr
BUILD SUCCESSFUL in 55s
4 actionable tasks: 4 executed

This command allows us to simply open the IntelliJ project at /<FULL PATH>/grpc-java/examples/.

Running the Client

$ ./build/install/examples/bin/route-guide-client
Jul 03, 2019 2:26:49 PM io.grpc.examples.routeguide.RouteGuideClient info
INFO: *** GetFeature: lat=409,146,138 lon=-746,188,906
Jul 03, 2019 2:26:49 PM io.grpc.examples.routeguide.RouteGuideClient info
INFO: Found feature called "Berkshire Valley Management Area Trail, Jefferson, NJ, USA" at 40.915, -74.619
Jul 03, 2019 2:26:49 PM io.grpc.examples.routeguide.RouteGuideClient info
INFO: *** GetFeature: lat=0 lon=0
Jul 03, 2019 2:26:49 PM io.grpc.examples.routeguide.RouteGuideClient info
INFO: Found no feature at 0, 0
Jul 03, 2019 2:26:49 PM io.grpc.examples.routeguide.RouteGuideClient info
INFO: *** ListFeatures: lowLat=400,000,000 lowLon=-750,000,000 hiLat=420,000,000 hiLon=-730,000,000
Jul 03, 2019 2:26:49 PM io.grpc.examples.routeguide.RouteGuideClient info
INFO: Result #1: name: "Patriots Path, Mendham, NJ 07945, USA"
location {
latitude: 407838351
longitude: -746143763
}
Jul 03, 2019 2:26:49 PM io.grpc.examples.routeguide.RouteGuideClient info
INFO: Result #2: name: "101 New Jersey 10, Whippany, NJ 07981, USA"
location {
latitude: 408122808
longitude: -743999179
}
...

 

The client makes queries to the gRPC server

Debugging

Go to Run/Edit Configurations in Intellij to set-up a remote debugger to connect to our gRCP server. Input name, leave the default value of Host as localhost, and set Port to 8000, which is the debug port specified in our Dockerfile above. Click OK and you can now select the debugger by the name you chose. Go to Run/Debug to see a list of configured debuggers and select the debugger. Now you may set breakpoints in the server in a class such as RouteGuideServer and step through the server code using the debugger. This is educational for the example code and invaluable for when you actually develop your own gRPC API.   Note that you may also debug the client in the same way, by creating an environment variable similar to the one defined in the Dockerfile above. Be sure to use a different port for debugging your client and then configure a client debugger to access that port in the manner described above.

Summary

We have seen how to set up a development environment for the routeguide example from the grpc-java git repo code. There are two other examples in this framework, helloworld and hello streaming, both of these should be able to be run and debugged in the same way described here. Of course, if you’ve managed to read this far, you  should be able to set up a development environment for your own Java gRPC project! Hopefully you have seen how easy it is to get a development environment for Java gRPC using Docker for the server and IntelliJ for our IDE.   次世代システム研究室では、グループ全体のインテグレーションを支援してくれるアーキテクトを募集しています。インフラ設計、構築経験者の方、次世代システム研究室にご興味を持って頂ける方がいらっしゃいましたら、ぜひ募集職種一覧からご応募をお願いします。




皆さんのご応募をお待ちしています。