diff --git a/examples/cpp-simple/README.md b/examples/cpp-simple/README.md index c9032ce5c0..40c69d8afa 100644 --- a/examples/cpp-simple/README.md +++ b/examples/cpp-simple/README.md @@ -5,7 +5,7 @@ This is a very simple "server" that doesn't do much other than show how the SDK It will - Setup the Agones SDK - Call `SDK::Ready()` to register that it is ready with Agones. -- Every 10 seconds, write a log saying "Hi! I'm a Game Server" +- Every 10 seconds, write a log showing how long it has been running for - After 60 seconds, call `SDK::Shutdown()` to shut the server down. To learn how to deploy this example service to GKE, please see the tutorial [Build and Run a Simple Gameserver (C++)](https://agones.dev/site/docs/tutorials/simple-gameserver-cpp/). diff --git a/examples/nodejs-simple/Dockerfile b/examples/nodejs-simple/Dockerfile new file mode 100644 index 0000000000..bdf6be9657 --- /dev/null +++ b/examples/nodejs-simple/Dockerfile @@ -0,0 +1,29 @@ +# Copyright 2019 Google LLC All Rights Reserved. +# +# 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. + +FROM debian:stretch +RUN useradd -m server +RUN apt-get update && apt-get install -y curl && apt-get clean +RUN curl -sL https://deb.nodesource.com/setup_11.x | bash - && \ + apt-get install -y nodejs + +WORKDIR /home/server + +COPY ./sdks/nodejs sdks/nodejs +COPY ./examples/nodejs-simple examples/nodejs-simple +RUN cd examples/nodejs-simple && \ + npm install + +USER server +ENTRYPOINT cd /home/server/examples/nodejs-simple && npm start \ No newline at end of file diff --git a/examples/nodejs-simple/Makefile b/examples/nodejs-simple/Makefile new file mode 100644 index 0000000000..a223c38d66 --- /dev/null +++ b/examples/nodejs-simple/Makefile @@ -0,0 +1,46 @@ +# Copyright 2019 Google LLC All Rights Reserved. +# +# 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. + +# +# Makefile for building the world's simplest node.js game server +# + +# __ __ _ _ _ +# \ \ / /_ _ _ __(_) __ _| |__ | | ___ ___ +# \ \ / / _` | '__| |/ _` | '_ \| |/ _ \ __| +# \ V / (_| | | | | (_| | |_) | | __\__ \ +# \_/ \__,_|_| |_|\__,_|_.__/|_|\___|___/ +# + +REPOSITORY = gcr.io/agones-images + +# Directory that this Makefile is in. +mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST))) +project_path := $(dir $(mkfile_path)) +server_tag = $(REPOSITORY)/nodejs-simple-server:0.1 +root_path = $(realpath $(project_path)/../..) + +# _____ _ +# |_ _|_ _ _ __ __ _ ___| |_ ___ +# | |/ _` | '__/ _` |/ _ \ __/ __| +# | | (_| | | | (_| | __/ |_\__ \ +# |_|\__,_|_| \__, |\___|\__|___/ +# |___/ + +# build the cpp-simple binary +build: + cd $(root_path) && docker build -f $(project_path)/Dockerfile --tag=$(server_tag) . + +run: + docker run --network=host $(server_tag) \ No newline at end of file diff --git a/examples/nodejs-simple/README.md b/examples/nodejs-simple/README.md index 4ad39c1ee4..a4a48a2949 100644 --- a/examples/nodejs-simple/README.md +++ b/examples/nodejs-simple/README.md @@ -1,4 +1,109 @@ -### Instructions -`npm install` - install dependencies - -`npm start` - start the self-running example +# Simple node.js Example + +This is a very simple "server" that doesn't do much other than show how the SDK works in node.js. + +It will +- Setup the Agones SDK +- Call `sdk.ready()` to register that it is ready with Agones. +- Every 10 seconds, write a log showing how long it has been running for +- After 60 seconds, call `sdk.shutdown()` to shut the server down. + +To learn how to deploy this example service to GKE, please see the tutorial [Build and Run a Simple Gameserver (node.js)](https://agones.dev/site/docs/tutorials/simple-gameserver-nodejs/). + +## Building + +If you want to modify the source code and/or build an updated container image, run `make build` from this directory. +This will run the `docker build` command with the correct context. + +This example uses a Docker container to host the SDK and example it inside a container so that no special build +tools need to be installed on your system. + +## Testing locally with Docker + +If you want to run the example locally, you need to start an instance of the SDK-server. To run an SDK-server for +120 seconds, run +```bash +$ cd ../../build; make run-sdk-conformance-local TIMEOUT=120 TESTS=ready,watch,health,gameserver +``` + +In a separate terminal, while the SDK-server is still running, build and start a container with the example gameserver: +```bash +$ make build +$ make run +``` + +You will see the output like the following: +``` +docker run --network=host gcr.io/agones-images/nodejs-simple-server:0.1 + +> @ start /home/server/examples/nodejs-simple +> node src/index.js + +node.js Game Server has started! +Setting a label +(node:18) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead. +Setting an annotation +GameServer Update: + name: local + state: Ready +GameServer Update: + name: local + state: Ready +Marking server as ready... +...marked Ready +Health ping sent +Health ping sent +Health ping sent +Health ping sent +Health ping sent +Running for 10 seconds! +Health ping sent +Health ping sent +Health ping sent +Health ping sent +Running for 20 seconds! +Health ping sent +Health ping sent +Health ping sent +Health ping sent +Health ping sent +Running for 30 seconds! +Health ping sent +Health ping sent +Health ping sent +Health ping sent +Health ping sent +Running for 40 seconds! +Health ping sent +Health ping sent +Health ping sent +Health ping sent +Health ping sent +Running for 50 seconds! +Health ping sent +Health ping sent +Health ping sent +Health ping sent +Health ping sent +Shutting down after 60 seconds... +...marked for Shutdown +Running for 60 seconds! +Health ping sent +Health ping sent +Health ping sent +Health ping sent +Health ping sent +Running for 70 seconds! +Health ping sent +Health ping sent +Health ping sent +Health ping sent +Health ping sent +Running for 80 seconds! +Health ping sent +Health ping sent +Health ping sent +Health ping sent +Health ping sent +Running for 90 seconds! +``` diff --git a/examples/nodejs-simple/gameserver.yaml b/examples/nodejs-simple/gameserver.yaml new file mode 100644 index 0000000000..468e71f10a --- /dev/null +++ b/examples/nodejs-simple/gameserver.yaml @@ -0,0 +1,31 @@ +# Copyright 2017 Google LLC All Rights Reserved. +# +# 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: "agones.dev/v1" +kind: GameServer +metadata: + # generate a unique name + # will need to be created with `kubectl create` + generateName: nodejs-simple- +spec: + ports: + - name: default + portPolicy: Dynamic + containerPort: 7654 + template: + spec: + containers: + - name: nodejs-simple + image: gcr.io/agones-images/nodejs-simple-server:0.1 + imagePullPolicy: Always diff --git a/examples/nodejs-simple/package-lock.json b/examples/nodejs-simple/package-lock.json new file mode 100644 index 0000000000..4e784bb9b6 --- /dev/null +++ b/examples/nodejs-simple/package-lock.json @@ -0,0 +1,13 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "agones": { + "version": "file:../../sdks/nodejs", + "requires": { + "google-protobuf": "3.7.0-rc.2", + "grpc": "1.18.0" + } + } + } +} diff --git a/examples/nodejs-simple/src/index.js b/examples/nodejs-simple/src/index.js index 0874f6c27a..f1c8a9528a 100644 --- a/examples/nodejs-simple/src/index.js +++ b/examples/nodejs-simple/src/index.js @@ -1,46 +1,61 @@ -// Copyright 2019 Google LLC All Rights Reserved. -// -// 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. - -const AgonesSDK = require('agones'); - -const agonesSDK = new AgonesSDK(); - -const connect = async function() { - agonesSDK.watchGameServer((result) => { - console.log('watch', result); - }); - - try { - await agonesSDK.ready(); - await agonesSDK.setLabel("label", "labelValue"); - await agonesSDK.setAnnotation("annotation", "annotationValue"); - const result = await agonesSDK.getGameServer(); - console.log('gameServer', result); - setTimeout(() => { - console.log('send health ping'); - agonesSDK.health(); - }, 2000); - setTimeout(() => { - console.log('send shutdown request'); - agonesSDK.shutdown(); - }, 4000); - setTimeout(() => { - agonesSDK.close(); - }, 6000); - } catch (error) { - console.error(error); - } -}; - -connect(); +// Copyright 2019 Google LLC All Rights Reserved. +// +// 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. + +const AgonesSDK = require('agones'); + +const agonesSDK = new AgonesSDK(); + +const connect = async function() { + agonesSDK.watchGameServer((result) => { + console.log("GameServer Update:\n\tname:", result.objectMeta.name, "\n\tstate:", result.status.state); + }); + setInterval(() => { + agonesSDK.health(); + console.log('Health ping sent'); + }, 20000); + + try { + console.log('node.js Game Server has started!'); + + console.log('Setting a label'); + await agonesSDK.setLabel("test-label", "test-value"); + console.log('Setting an annotation'); + await agonesSDK.setAnnotation("test-annotation", "test value"); + + console.log('Marking server as ready...'); + await agonesSDK.ready(); + console.log('...marked Ready'); + + var count = 0; + setInterval(() => { + count = count + 10; + console.log('Running for', count, 'seconds!'); + }, 10000); + setTimeout(() => { + console.log('Shutting down after 60 seconds...'); + agonesSDK.shutdown(); + console.log('...marked for Shutdown'); + }, 60000); + setTimeout(() => { + agonesSDK.close(); + }, 90000); + setTimeout(() => { + process.exit(0); + }, 100000); + } catch (error) { + console.error(error); + } +}; + +connect(); diff --git a/sdks/nodejs/package-lock.json b/sdks/nodejs/package-lock.json index 236bbd8b63..a92707b48e 100644 --- a/sdks/nodejs/package-lock.json +++ b/sdks/nodejs/package-lock.json @@ -160,7 +160,6 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, "requires": { "sprintf-js": "~1.0.2" } @@ -452,8 +451,7 @@ "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" }, "esquery": { "version": "1.0.1", @@ -1157,10 +1155,9 @@ "dev": true }, "js-yaml": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.1.tgz", - "integrity": "sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA==", - "dev": true, + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -2527,8 +2524,7 @@ "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, "string-width": { "version": "2.1.1", diff --git a/sdks/nodejs/package.json b/sdks/nodejs/package.json index fdbf623ed7..f9175ea0e1 100644 --- a/sdks/nodejs/package.json +++ b/sdks/nodejs/package.json @@ -5,7 +5,8 @@ }, "dependencies": { "google-protobuf": "3.7.0-rc.2", - "grpc": "1.18.0" + "grpc": "1.18.0", + "js-yaml": ">=3.13.1" }, "description": "SDK for Agones", "devDependencies": { diff --git a/site/content/en/docs/Tutorials/simple-gameserver-cpp.md b/site/content/en/docs/Tutorials/simple-gameserver-cpp.md index c48430a879..77a8c04fc0 100644 --- a/site/content/en/docs/Tutorials/simple-gameserver-cpp.md +++ b/site/content/en/docs/Tutorials/simple-gameserver-cpp.md @@ -43,7 +43,7 @@ is going to exit. You can follow along with the lifecycle of the gameserver by running ```bash -$ kubectl logs ${GAMESERVER_NAME} cpp-simple +$ kubectl logs ${GAMESERVER_NAME} cpp-simple -f ``` which should produce output similar to @@ -195,7 +195,7 @@ $ GAMESERVER_NAME=$(kubectl get gs -o go-template --template '{{range .items}}{{ Again, follow along with the lifecycle of the gameserver by running ```bash -$ kubectl logs ${GAMESERVER_NAME} cpp-simple +$ kubectl logs ${GAMESERVER_NAME} cpp-simple -f ``` which should produce output similar to diff --git a/site/content/en/docs/Tutorials/simple-gameserver-nodejs.md b/site/content/en/docs/Tutorials/simple-gameserver-nodejs.md new file mode 100644 index 0000000000..b84f09fe14 --- /dev/null +++ b/site/content/en/docs/Tutorials/simple-gameserver-nodejs.md @@ -0,0 +1,257 @@ +--- +title: "Tutorial Build and Run a Simple Gameserver (node.js)" +linkTitle: "Build and Run a Simple Gameserver (node.js)" +date: 2019-07-25T17:34:37Z +publishDate: 2019-08-01T10:00:00Z +description: > + This tutorial describes how to use the Agones node.js SDK in a simple node.js gameserver. +--- + +## Objectives +- Run a simple gameserver +- Understand how the simple gameserver uses the Agones node.js SDK +- Build a customized version of the simple gameserver +- Run your customized simple gameserver + +## Prerequisites +1. [Docker](https://www.docker.com/get-started/) +2. Agones installed on GKE +3. kubectl properly configured +4. A local copy of the [Agones repository](https://github.com/googleforgames/agones/tree/{{< release-branch >}}) +5. A repository for Docker images, such as [Docker Hub](https://hub.docker.com/) or [GC Container Registry](https://cloud.google.com/container-registry/) + +To install on GKE, follow the install instructions (if you haven't already) at +[Setting up a Google Kubernetes Engine (GKE) cluster]({{< relref "../Installation/_index.md#setting-up-a-google-kubernetes-engine-gke-cluster" >}}). +Also complete the "Installing Agones" instructions on the same page. + +While not required, you may wish to review the [Create a Game Server]({{< relref "../Getting Started/create-gameserver.md" >}}), +[Create a Game Server Fleet]({{< relref "../Getting Started/create-fleet.md" >}}), and/or [Edit a Game Server]({{< relref "../Getting Started/edit-first-gameserver-go.md" >}}) quickstarts. + +### 1. Run the simple gameserver + +First, run the pre-built version of the simple gameserver and take note of the name that was created: + +```bash +$ kubectl create -f https://raw.githubusercontent.com/googleforgames/agones/{{< release-branch >}}/examples/nodejs-simple/gameserver.yaml +$ GAMESERVER_NAME=$(kubectl get gs -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}') +``` + +The game server sets up the Agones SDK, calls `sdk.ready()` to inform Agones that it is ready to serve traffic, +prints a message every 10 seconds, and then calls `sdk.shutdown()` after a minute indicate that the gameserver +is going to exit. + +You can follow along with the lifecycle of the gameserver by running + +```bash +$ kubectl logs ${GAMESERVER_NAME} nodejs-simple -f +``` + +which should produce output similar to +``` +> @ start /home/server/examples/nodejs-simple +> node src/index.js + +node.js Game Server has started! +Setting a label +(node:20) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead. +Setting an annotation +Marking server as ready... +...marked Ready +GameServer Update: + name: nodejs-simple-9bw4g + state: Scheduled +GameServer Update: + name: nodejs-simple-9bw4g + state: RequestReady +GameServer Update: + name: nodejs-simple-9bw4g + state: RequestReady +GameServer Update: + name: nodejs-simple-9bw4g + state: Ready +Health ping sent +Health ping sent +Health ping sent +Health ping sent +Health ping sent +Running for 10 seconds! +Health ping sent +Health ping sent +Health ping sent +Health ping sent +Running for 20 seconds! +Health ping sent +Health ping sent +Health ping sent +Health ping sent +Health ping sent +GameServer Update: + name: nodejs-simple-9bw4g + state: Ready +Running for 30 seconds! +Health ping sent +Health ping sent +Health ping sent +Health ping sent +Health ping sent +Running for 40 seconds! +Health ping sent +Health ping sent +Health ping sent +Health ping sent +Health ping sent +Running for 50 seconds! +Health ping sent +Health ping sent +Health ping sent +Health ping sent +Health ping sent +GameServer Update: + name: nodejs-simple-9bw4g + state: Ready +Running for 60 seconds! +Shutting down after 60 seconds... +...marked for Shutdown +GameServer Update: + name: nodejs-simple-9bw4g + state: Shutdown +Health ping sent +GameServer Update: + name: nodejs-simple-9bw4g + state: Shutdown +Health ping sent +Health ping sent +Health ping sent +Health ping sent +Running for 70 seconds! +Health ping sent +Health ping sent +Health ping sent +Health ping sent +Health ping sent +Running for 80 seconds! +Health ping sent +Health ping sent +Health ping sent +Health ping sent +Health ping sent +Running for 90 seconds! +``` + +If everything goes as expected, the gameserver will exit automatically after about a minute. + +In some cases, the gameserver goes into an unhealthy state, in which case it will be restarted indefinitely. +If this happens, you can manually remove it by running +```bash +$ kubectl delete gs ${GAMESERVER_NAME} +``` + +### 2. Build a simple gameserver + +Change directories to your local agones/examples/nodejs-simple directory. To experiment with the SDK, open up +`src/index.js` in your favorite editor and change the interval at which the gameserver calls `sdk.health()` from +2 seconds to 20 seconds by modifying the lines in the health ping handler to be + +``` +setInterval(() => { + agonesSDK.health(); + console.log('Health ping sent'); +}, 20000); +``` + +Next build a new docker image by running +```bash +$ cd examples/nodejs-simple +$ REPOSITORY= # e.g. gcr.io/agones-images +$ make build REPOSITORY=${REPOSITORY} +``` + +Once the container has been built, push it to your repository +```bash +$ docker push ${REPOSITORY}/nodejs-simple-server:0.1 +``` + +### 3. Run the customized gameserver + +Now it is time to deploy your newly created gameserver container into your Agones cluster. + +First, you need to edit `examples/nodejs-simple/gameserver.yaml` to point to your new image: + +``` +containers: +- name: nodejs-simple + image: $(REPOSITORY)/nodejs-simple-server:0.1 + imagePullPolicy: Always +``` + +Then, deploy your gameserver + +```bash +$ kubectl create -f gameserver.yaml +$ GAMESERVER_NAME=$(kubectl get gs -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}') +``` + +Again, follow along with the lifecycle of the gameserver by running + +```bash +$ kubectl logs ${GAMESERVER_NAME} nodejs-simple -f +``` + +which should produce output similar to +``` +> @ start /home/server/examples/nodejs-simple +> node src/index.js + +node.js Game Server has started! +Setting a label +(node:20) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead. +Setting an annotation +Marking server as ready... +...marked Ready +GameServer Update: + name: nodejs-simple-qkpqn + state: Scheduled +GameServer Update: + name: nodejs-simple-qkpqn + state: Scheduled +GameServer Update: + name: nodejs-simple-qkpqn + state: RequestReady +GameServer Update: + name: nodejs-simple-qkpqn + state: Ready +Running for 10 seconds! +GameServer Update: + name: nodejs-simple-qkpqn + state: Unhealthy +Health ping sent +Running for 20 seconds! +GameServer Update: + name: nodejs-simple-qkpqn + state: Unhealthy +Running for 30 seconds! +Health ping sent +Running for 40 seconds! +Running for 50 seconds! +GameServer Update: + name: nodejs-simple-qkpqn + state: Unhealthy +Health ping sent +Shutting down after 60 seconds... +...marked for Shutdown +Running for 60 seconds! +Running for 70 seconds! +Health ping sent +Running for 80 seconds! +GameServer Update: + name: nodejs-simple-qkpqn + state: Unhealthy +Running for 90 seconds! +``` + +with the slower healthcheck interval, the gameserver gets automatically marked an `Unhealthy` by Agones. + +To finish, clean up the gameserver by manually removing it +```bash +$ kubectl delete gs ${GAMESERVER_NAME} +```