This tutorial shows you how to use Memorystore for Redis to build an ASP.NET-based leaderboard application running on Google Kubernetes Engine (GKE), and then post and retrieve scores using a separate JavaScript-based sample game. This document is intended for game developers who want to operate their own leaderboards in the cloud.
Introduction
Leaderboards are a common feature in multiplayer games. A leaderboard shows player rankings in real time, which helps encourage players to be more engaged in the game. To capture player actions and rank the score in real time, an in-memory database like Redis is a great choice.
The following diagram shows the infrastructure of the leaderboard:
In Google Cloud, the leaderboard consists of a GKE cluster inside a VPC network, and a separate Memorystore for Redis instance.
The following diagram shows the application architecture for this tutorial. Clients use the leaderboard API to interact with the scores that are maintained in a Memorystore for Redis instance running in Google Cloud.
Methods of the leaderboard API
The API for the leaderboard application includes the following methods:
PostScore(string playerName, double score)
. This method posts a score to the leaderboard for the specified player.RetrieveScores(string centerKey, int offset, int numScores)
. This method downloads a set of scores. If you pass a player ID as the value forcenterKey
, the method returns the scores that are above and below those of the specified player. If you don't pass a value forcenterKey
, the method returns the top N absolute scores, where N is the value you pass innumScores
. For example, to get the top 10 scores, callRetrieveScores('', 0, 10)
. To get 5 scores above and below a player's score, callRetrieveScores('player1', -5, 10)
.
The code repository for the example includes a mock game and a proof-of-concept leaderboard implementation. During this tutorial, you deploy the game and leaderboard and validate that the leaderboard API works correctly and can be accessed over the internet.
Objectives
- Create a Memorystore for Redis instance.
- Create a headless service with an endpoint that directs requests to this instance.
- Deploy the leaderboard application to GKE.
- Verify leaderboard functionality using the deployed application that makes API calls.
Costs
This tutorial uses the following billable components of Google Cloud:
To generate a cost estimate based on your projected usage,
use the pricing calculator.
Before you begin
- Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Cloud project. Learn how to check if billing is enabled on a project.
-
Enable the Memorystore for Redis and Google Kubernetes Engine APIs.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Cloud project. Learn how to check if billing is enabled on a project.
-
Enable the Memorystore for Redis and Google Kubernetes Engine APIs.
Preparing your environment
In this tutorial, you run commands in Cloud Shell. Cloud Shell gives you access to the command line in Google Cloud, and includes the Google Cloud CLI and other tools that you need for Google Cloud development. Cloud Shell can take several minutes to initialize.
Open Cloud Shell:
Set the default Compute Engine zone to the zone where you're going to create your Google Cloud resources. In this tutorial, you use the
us-central1-a
zone in theus-central1
region.export REGION=us-central1 export ZONE=us-central1-a gcloud config set compute/zone $ZONE
Clone the GitHub repository that contains the sample code:
git clone https://github.com/GoogleCloudPlatform/memstore-gaming-leaderboard.git
Go to the cloned directory:
cd memstore-gaming-leaderboard
Using a text editor, open the
leaderboardapp/k8s/appdeploy.yaml
file and change the[YOUR_PROJECT_ID]
placeholder to your Google Cloud project ID.
Creating a Memorystore for Redis instance
For this tutorial, you create a Basic Tier instance of Memorystore for Redis, which is appropriate for testing and the scope of this tutorial. For a production deployment, we recommend that you deploy a Standard Tier instance, which provides a 99.9% SLA with automatic failover to ensure that your instance is highly available. For details on Standard Tier instances, see high availability for Memorystore for Redis.
In Cloud Shell, create a 1 GB Memorystore for Redis instance:
gcloud redis instances create cm-redis --size=1 \ --tier=basic \ --region=$REGION \ --zone=$ZONE
This command might take a few minutes to complete.
Building the application container images
For this tutorial, you deploy a simple leaderboard application using GKE. Because Unity and C# are popular in gaming, the application tier uses C# and the ASP.NET framework.
To deploy the leaderboard API to a GKE cluster, you need to first upload it to a registry like Container Registry.
- Open the
README.md
file in the GitHub project that you cloned. - Follow the instructions for creating a Docker image and uploading it to Container Registry.
You'll use this image to deploy the leaderboard application after you create the cluster in the next section.
Creating or reusing a GKE cluster
Before you deploy the leaderboard application, you must create a
GKE cluster with
alias IP ranges enabled.
If you already have a GKE cluster (using alias IP ranges),
you can use that cluster for this tutorial. If you use an existing cluster, you
must perform an
additional step to configure the kubectl
command-line tool with credentials
for that cluster.
If you want to create a cluster, create one named
leaderboard
that has two nodes:gcloud container clusters create leaderboard --num-nodes=2 --enable-ip-alias
This command can take a few minutes to complete.
After waiting for the cluster to start, verify that it's running:
gcloud container clusters list
The cluster is running when you see an entry that has the name
leaderboard
whose status isRUNNING
.
Configure credentials for an existing cluster
If you're using an existing GKE cluster for this tutorial, configure the
kubeconfig
file with the credentials for that cluster. For name-of-existing-cluster, use the name of your cluster.gcloud container clusters get-credentials name-of-existing-cluster
Mapping the Memorystore for Redis instance to a Kubernetes service
When the Memorystore for Redis instance is ready, you make a service inside the GKE cluster so that the application tier can connect.
Verify that the Memorystore for Redis instance is running:
gcloud redis instances list --region=$REGION
You see output like the following:
INSTANCE_NAME VERSION REGION TIER SIZE_GB HOST PORT NETWORK RESERVED_IP STATUS CREATE_TIME cm-redis REDIS_4_0 us-central1 STANDARD 1 10.0.0.3 6379 default 10.0.0.0/29 READY 2019-05-10T04:37:45
The instance is running when the
STATUS
column showsREADY
. If theHOST
field is empty, the instance has not completed the startup process. Wait a moment and run theredis instances list
command again.Store the IP address of the instance in an environment variable:
export REDIS_IP=$(gcloud redis instances list --filter="name:cm-redis" --format="value(HOST)" \ --region=$REGION)
Create the Kubernetes service for Redis:
kubectl apply -f k8s/redis_headless_service.yaml
This service doesn't have a Pod selector, because you want it to point at an IP address that's outside of the Kubernetes cluster.
Create an endpoint that defines the Redis IP address that you retrieved earlier:
sed "s|REDIS_IP|${REDIS_IP}|g" k8s/redis_endpoint.yaml | kubectl apply -f -
Verify that the service and endpoint were created correctly:
kubectl get services/redis endpoints/redis
If everything is working correctly, you see output like the following, with an entry for the Redis service and the Redis endpoint:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/redis ClusterIP 10.59.241.103 none 6379/TCP 5m NAME ENDPOINTS AGE endpoints/redis 10.0.0.3:6379 4m
For more information about Kubernetes services and endpoints, see Kubernetes best practices: mapping external services on the Google Cloud blog.
Deploying the leaderboard app and service to Kubernetes
The Redis instance is now reachable from an application that's deployed in the GKE cluster. Therefore, you're ready to deploy the leaderboard app.
- Follow the instructions in the
README.md
file included in the root of the GitHub repo that you cloned earlier.
Validating the deployment
The mock game application provided, written in JavaScript, can be used to make calls to the leaderboard API. The following code snippet shows how the mock game posts scores after the player finishes playing:
In addition, the app makes an API call to retrieve the leaderboard scores—either the top scores or scores centered around the player's name, like this:
To access the sample application, follow these steps:
Get the IP address of the mock game by running the following command:
kubectl get ingress
The output is similar to the following:
NAME HOSTS ADDRESS PORTS AGE memstore-gaming-ingress * 34.102.192.4 80 43s
Browse to the following URL, where ip_address_for_gke is the address for the mock game:
http://ip_address_for_gke.
This sample is simple, but it's adequate for demonstrating basic API usage.
When you post or retrieve scores directly from a game client app that's running
on a user device or machine, the sample calls the leaderboard API at the public
IP address assigned to its Kubernetes Load Balancer object. For this sample
application, both the leaderboard API and the JavaScript client are hosted at
the same IP address that you get using the kubectl get ingress
command shown
earlier.
How the methods are implemented
The leaderboard application, written in C#, uses the
StackExchange.Redis
library for communicating with Redis. The code snippets that follow show how
PostScore
and RetrieveScores
are implemented using Redis and the
StackExchange.Redis
library.
The following code snippet shows the PostScore
method:
The following code snippet shows the RetrieveScores
method:
Additions to the sample game
The leaderboard API follows REST conventions and is provided only as an example. When you run a production game leaderboard, we recommend integrating an authentication flow so that only scores that are from validated users can be posted.
Currently, Memorystore for Redis doesn't provide persistence for player scores. Therefore, if the app experiences an issue, you could lose the leaderboard information. If your game requires a persistent leaderboard, you should back up the leaderboard scores periodically in a persistent database.
Clean up
To avoid incurring charges to your Google Cloud account for the resources used in this tutorial, delete the project.
Delete the project
- In the Google Cloud console, go to the Manage resources page.
- In the project list, select the project that you want to delete, and then click Delete.
- In the dialog, type the project ID, and then click Shut down to delete the project.
What's next
- Review key Memorystore for Redis concepts.
- Learn more about leaderboard concepts with the Google Play Games Services documentation.