Skip to content

Commit

Permalink
Endpoints gRPC samples (#330)
Browse files Browse the repository at this point in the history
* First draft of Endpoints gRPC sample

* Tweak README + package.json
  • Loading branch information
Ace Nassri authored Mar 31, 2017
1 parent a5ab629 commit 77327fd
Show file tree
Hide file tree
Showing 11 changed files with 482 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ coverage/
dump.rdb
logs/
*.iml
*.pb
.idea/
.nyc_output
4 changes: 4 additions & 0 deletions endpoints/getting-started-grpc/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*.md
*.yaml
node_modules/
test/
15 changes: 15 additions & 0 deletions endpoints/getting-started-grpc/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# The Google App Engine Flexible Environment base Docker image can
# also be used on Google Container Engine, or any other Docker host.
# This image is based on Debian Jessie and includes nodejs and npm
# installed from nodejs.org. The source is located in
# https://github.com/GoogleCloudPlatform/nodejs-docker
FROM gcr.io/google_appengine/nodejs

ADD . /app
WORKDIR /app

RUN npm install
ENTRYPOINT []

EXPOSE 50051
CMD ["npm", "start"]
122 changes: 122 additions & 0 deletions endpoints/getting-started-grpc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# Google Cloud Endpoints sample for Node.js

This sample demonstrates how to use Google Cloud Endpoints with Node.js.

For a complete walkthrough showing how to run this sample in different
environments, see the [Google Cloud Endpoints Quickstarts](https://cloud.google.com/endpoints/docs/quickstarts).

## Running locally

### Start a local server
```
$ node server.js -p 50051
```

### Run the client
```
$ node client.js -h localhost:50051
```

## Running on Google Cloud Platform
### Setup
Make sure you have [gcloud](https://cloud.google.com/sdk/gcloud/) and [Node.js](https://nodejs.org/) installed.

To update `gcloud`, use the `gcloud components update` command.

### Deploying to Endpoints
1. Install [protoc](https://github.com/google/protobuf/#protocol-compiler-installation).

1. Compile the proto file using protoc.
```
$ protoc --include_imports --include_source_info protos/helloworld.proto --descriptor_set_out out.pb
```

1. In `api_config.yaml`, replace `MY_PROJECT_ID` with your Project ID.

1. Deploy your service's configuration to Endpoints. Take note of your service's config ID and name once the deployment completes.
```
$ gcloud service-management deploy out.pb api_config.yaml
...
Service Configuration [SERVICE_CONFIG_ID] uploaded for service [SERVICE_NAME]
```

1. Build a Docker image for later use using the following command. Make sure to replace `[YOUR_PROJECT_ID]` with your Project ID.
```
$ gcloud container builds submit --tag gcr.io/[YOUR_PROJECT_ID]/endpoints-example:1.0 .
```

### Running your service
#### Compute Engine
1. [Create](https://console.cloud.google.com/compute/instancesAdd) a Compute Engine instance. Be sure to check **Allow HTTP traffic** and **Allow HTTPS traffic** when creating the instance.

1. Once your instance is created, take note of its IP address.

Note: this IP address is _ephemeral_ by default, and may change unexpectedly. If you plan to use this instance in the future, [reserve a static IP address](https://cloud.google.com/compute/docs/configure-ip-addresses#reserve_new_static) instead.

1. SSH into your instance, and install Docker.
```
$ sudo apt-get update
$ sudo apt-get install docker.io
```

1. Using the SSH connection to your instance, initialize the required Docker images in the order specified below. Replace `[YOUR_GCLOUD_PROJECT]`, `[YOUR_SERVICE_NAME]` and `[YOUR_SERVICE_CONFIG_ID]` with your GCloud Project ID, your service's name and your service's config ID respectively.
```
$ sudo docker run -d --name=helloworld gcr.io/[YOUR_GCLOUD_PROJECT]/endpoints-example:1.0
```

```
$ sudo docker run --detach --name=esp \
-p 80:9000 \
--link=helloworld:helloworld \
gcr.io/endpoints-release/endpoints-runtime:1 \
-s [YOUR_SERVICE_NAME] \
-v [YOUR_SERVICE_CONFIG_ID] \
-P 9000 \
-a grpc://helloworld:50051
```

1. On your local machine, use the client to test your Endpoints deployment. Replace `[YOUR_INSTANCE_IP_ADDRESS]` with your instance's external IP address, and `[YOUR_API_KEY]` with a [valid Google Cloud Platform API key](https://support.google.com/cloud/answer/6158862?hl=en).
```
$ node client.js -h [YOUR_INSTANCE_IP_ADDRESS]:80 -k [YOUR_API_KEY]
```

#### Container Engine
1. If you haven't already, install `kubectl`.
```
$ gcloud components install kubectl
```

1. [Create](https://console.cloud.google.com/kubernetes/add) a container cluster with the default settings. Remember the cluster's name and zone, as you will need these later.


1. Configure `kubectl` to have access to the cluster. Replace `[YOUR_CLUSTER_NAME]` and `[YOUR_CLUSTER_ZONE]` with your cluster's name and zone respectively.
```
$ gcloud container clusters get-credentials [YOUR_CLUSTER_NAME] --zone [YOUR_CLUSTER_ZONE]
```

1. Edit the `container_engine.yaml` file, and replace `GCLOUD_PROJECT`, `SERVICE_NAME`, and `SERVICE_CONFIG` with your Project ID and your Endpoints service's name and config ID respectively.

1. Add a [Kubernetes service](https://kubernetes.io/docs/user-guide/services/) to the cluster you created. Note that Kubernetes services should not be confused with [Endpoints services](https://cloud.google.com/endpoints/docs/grpc).
```
$ kubectl create -f container-engine.yaml
```

1. Get the external IP of your service. This may take a few minutes to be provisioned.
```
$ kubectl get service
```

1. Use the client to test your Endpoints deployment. Replace `[YOUR_CLUSTER_IP_ADDRESS]` with your service's external IP address, and `[YOUR_API_KEY]` with a [valid Google Cloud Platform API key](https://support.google.com/cloud/answer/6158862?hl=en).
```
$ node client.js -h [YOUR_CLUSTER_IP_ADDRESS]:80 -k [YOUR_API_KEY]
```

## Cleanup
If you do not intend to use the resources you created for this tutorial in the future, delete your [VM instances](https://console.cloud.google.com/compute/instances) and/or [container clusters](https://console.cloud.google.com/kubernetes/list) to prevent additional charges.

## Troubleshooting
If you're having issues with this tutorial, here are some things to try:
- [Check](https://console.cloud.google.com/logs/viewer) your VM instance's/cluster's logs
- Make sure your Compute Engine instance's [firewall](https://console.cloud.google.com/networking/firewalls/list) permits TCP access to port 80

If those suggestions don't solve your problem, please [let us know](https://github.com/GoogleCloudPlatform/nodejs-docs-samples/issues) or [submit a PR](https://github.com/GoogleCloudPlatform/nodejs-docs-samples/pulls).
36 changes: 36 additions & 0 deletions endpoints/getting-started-grpc/api_config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Copyright 2017 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

#
# An example API configuration.
#
# Below, replace MY_PROJECT_ID with your Google Cloud Project ID.
#

# The configuration schema is defined by service.proto file
# https://github.com/googleapis/googleapis/blob/master/google/api/service.proto
type: google.api.Service
config_version: 3

#
# Name of the service configuration.
#
name: hellogrpc.endpoints.MY_PROJECT_ID.cloud.goog

#
# API title to appear in the user interface (Google Cloud Console).
#
title: Hello gRPC API
apis:
- name: helloworld.Greeter
75 changes: 75 additions & 0 deletions endpoints/getting-started-grpc/client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright 2017, Google, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

'use strict';

function makeGrpcRequest (API_KEY, HOST, GREETEE) {
// Uncomment these lines to set their values
// const API_KEY = 'YOUR_API_KEY';
// const HOST = 'localhost:50051'; // The IP address of your endpoints host
// const GREETEE = 'world';

// Import required libraries
const grpc = require('grpc');
const path = require('path');

// Load protobuf spec for an example API
const PROTO_PATH = path.join(__dirname, '/protos/helloworld.proto');
const protoObj = grpc.load(PROTO_PATH).helloworld;

// Create a client for the protobuf spec
const client = new protoObj.Greeter(HOST, grpc.credentials.createInsecure());

// Build gRPC request
const metadata = new grpc.Metadata();
metadata.add('x-api-key', API_KEY);

// Execute gRPC request
client.sayHello({ name: GREETEE }, metadata, (err, response) => {
if (err) {
console.error(err);
}

if (response) {
console.log(response.message);
}
});
}

// The command-line program
const argv = require('yargs')
.usage('Usage: node $0 -k YOUR_API_KEY [-h YOUR_ENDPOINTS_HOST] [-g GREETEE_NAME]')
.option('apiKey', {
alias: 'k',
type: 'string',
global: true,
default: ''
})
.option('host', {
alias: 'h',
type: 'string',
default: 'localhost:50051',
global: true
})
.option('greetee', {
alias: 'g',
type: 'string',
default: 'world',
global: true
})
.wrap(120)
.epilogue(`For more information, see https://cloud.google.com/endpoints/docs`)
.argv;

makeGrpcRequest(argv.apiKey, argv.host, argv.greetee);
54 changes: 54 additions & 0 deletions endpoints/getting-started-grpc/container-engine.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Copyright 2017 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

apiVersion: v1
kind: Service
metadata:
name: grpc-hello
spec:
ports:
- port: 80
targetPort: 9000
protocol: TCP
name: http
selector:
app: grpc-hello
type: LoadBalancer
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: grpc-hello
spec:
replicas: 1
template:
metadata:
labels:
app: grpc-hello
spec:
containers:
- name: esp
image: gcr.io/endpoints-release/endpoints-runtime:1
args: [
"-P", "9000",
"-a", "grpc://127.0.0.1:50051",
"-s", "SERVICE_NAME",
"-v", "SERVICE_CONFIG_ID",
]
ports:
- containerPort: 9000
- name: node-grpc-hello
image: gcr.io/GCLOUD_PROJECT/endpoints-example:1.0
ports:
- containerPort: 50051
20 changes: 20 additions & 0 deletions endpoints/getting-started-grpc/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "appengine-endpoints",
"description": "Endpoints Node.js gRPC sample for Google App Engine",
"version": "0.0.1",
"private": true,
"license": "Apache Version 2.0",
"author": "Google Inc.",
"engines": {
"node": ">=4.3.2"
},
"scripts": {
"start": "node server.js",
"system-test": "ava system-test/*.test.js --timeout=30s"
},
"dependencies": {
"body-parser": "1.16.0",
"express": "4.14.1",
"grpc": "^1.1.2"
}
}
53 changes: 53 additions & 0 deletions endpoints/getting-started-grpc/protos/helloworld.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

syntax = "proto3";

option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";

package helloworld;

// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
string name = 1;
}

// The response message containing the greetings
message HelloReply {
string message = 1;
}
Loading

0 comments on commit 77327fd

Please sign in to comment.