Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Azure for Game Developers Part 1: Globally Scalable Game Servers Using Azure Kubernetes Service (AKS) with the Microsoft Game Stack

0.00/5 (No votes)
8 Oct 2021 1  
In this article, we’re going to look at how to set up a simple Node.js application on Azure Kubernetes Service by containerizing and deploying to an Azure Kubernetes Cluster in a scalable way.
Here we focus on setting up a back-end using the Azure Kubernetes Service (AKS).

Microsoft Game Stack is a collection of tools and services, including tools like Microsoft Azure, PlayFab, Xbox Services, and Visual Studio. Game developers of all sizes, from indie studios to AAA teams, can use it to build and launch amazing games. When building games with real-time multiplayer features, we can deploy and run our backend on services like Azure or PlayFab to cost-effectively scale to meet demand. These services also ensure our games aren’t slow or unreliable on launch day, letting players have the best experience and making sure that game critics give the best possible reviews.

In this article, we’re going to look at how to set up a simple Node.js application on Azure Kubernetes Service by containerizing and deploying to an Azure Kubernetes Cluster in a scalable way. Although we are using JavaScript in this example, keep in mind that you can use similar steps to deploy games written in other languages onto Azure Kubernetes Service. And note that if you’re looking to integrate a backend service that automatically handles this for you, PlayFab Multiplayer Servers might be an ideal solution.

Requirements

To follow along with this tutorial, you’ll need an Azure account with a subscription and the following software installed on your computer:

Creating a Super Simple Node.js App

Let’s begin by creating a very basic Node.js server application to use for this example. Keep in mind that the process we’re following to push our app to Azure can be used with any Node.js application.

Create and open a new folder for this project in a terminal or command prompt window, and initialize the project:

npm init

The folder name you choose doesn’t matter, but it should remain consistent while you follow along with the rest of the articles in this series. We can use the default values for the options when initializing the project.

Next, install the webwebweb npm package, which we’ll use to quickly start up a web server:

npm install webwebweb

Create a file named "index.js" inside the project folder, and edit it to have the following code:

JavaScript
const Web = require( "webwebweb" );
Web.APIs[ "/" ] = ( qs, body, opts ) => {
    return "Hello World";
};
Web.Run( 3000 );

This code creates a server running on port 3000 with a simple endpoint at / that returns the string "Hello World."

Now we can edit the scripts section of the "package.json" file to add a start command:

JavaScript
...
  "scripts": {
    "start": "node index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
...

We can test our app by running npm start and opening http://localhost:3000 from a web browser to make sure we see the words "Hello World" on the page.

Creating a Docker Container from the App

Now that we have a Node.js app, we can containerize it and deploy it to Azure.

First, create a new Dockerfile in the folder, which will copy the project files into a /src folder. Install the dependencies, expose port 3000, and then start the project. It should look like this:

FROM node:14-alpine

WORKDIR /src
COPY package*.json ./
RUN npm install --production

COPY . /src
EXPOSE 3000
CMD [ "npm", "start" ]

Next, build the Docker image in your terminal window, passing in the project tag you want to use. For example, we can build an image with the tag "test-app," like this:

docker build -t test-app .

To make sure the image was built, list the images on your machine:

docker images

Next, let’s make sure that the image was built successfully by running it locally on port 3000 and giving it a name to use for the instance:

docker run --name test_app1 -d -p 3000:3000 test-app

To view the list of running images, we can run the following:

docker ps

If it’s running properly, we should be able to open http://localhost:3000 in a web browser again and see "Hello World," just as we did before.

Lastly, stop the app that’s using the name you set to start it:

docker stop test_app1

Setting up an Azure Container Registry

Before deploying to AKS, our container needs to be pushed to Azure in an Azure Container Registry (ACR). Let’s prepare our Azure account with an ACR and push our new Docker image to it.

In the terminal window, log into your Azure account with the login command:

az login

We’ll create a new resource group in our Azure account for this project with a unique name, such as ms-gs-deploy, with a specified region, such as US West. You can use an existing resource group if you’d like, but using a separate resource group for this project will make it easier to delete later if you want to clean up your resources afterward.

az group create -n ms-gs-deploy -l westus

Create a Basic Azure Container Registry by providing the resource group name and a name for the ACR. Note that it must be all lowercase without any special characters.

az acr create --resource-group ms-gs-deploy --name msgsdeployregistry --sku Basic

Once it’s created, log into the ACR instance using the following command:

az acr login --name msgsdeployregistry

Docker images need to be tagged with the login server address before we can push them to the ACR. We can get the address like this:

az acr list --resource-group ms-gs-deploy --query "[].{acrLoginServer:loginServer}" --output table

Now, we can tag our app image using the address. In this example, the address is "msgsdeployregistry.azurecr.io":

docker tag test-app:latest msgsdeployregistry.azurecr.io/test-app:latest

Push the image to the ACR instance like this:

docker push msgsdeployregistry.azurecr.io/test-app:latest

To verify that the image was successfully pushed, we can list the ACR images:

az acr repository list --name msgsdeployregistry --output table

Setting up Azure Kubernetes Service

We’re almost ready — we just need to set up our cluster of servers to host instances of the container. This is the point at which we can scale our backend with more instances to keep up with the player demand. We do this by adding more nodes or even allowing AKS to automatically scale from the load balancer.

We should note that the design of the game’s multiplayer sessions is important in scaling with this method. Horizontally scaling to spin up new game servers works if a game’s multiplayer is designed to handle demand by adding more match-up sessions. This can be different from trying to scale one massive multiplayer world with thousands of players.

To create the cluster, we specify the resource group, attach the Azure Container Registry, and name it. We can set the number of nodes to prepare in the cluster according to the capacity we need, and should generally have at least two nodes for reliability. For this tutorial, though, it will suffice to have just one node. Note that this command may take several minutes to execute, so it’s a great time to grab some coffee or tea.

az aks create --resource-group ms-gs-deploy --name ms-gs-deploy-app --node-count 1 --generate-ssh-keys --attach-acr msgsdeployregistry

After the cluster is created, we need to configure kubectl to connect to it. The kubectl tool should be installed for you automatically with the Azure CLI — but if it’s not, you can run the command az aks install-cli to get it.

az aks get-credentials --resource-group ms-gs-deploy --name ms-gs-deploy-app

Make sure that it’s been configured properly by listing the nodes from the cluster:

kubectl get nodes

Deploying to the AKS Cluster

All that’s left is to deploy our app.

Kubernetes deployment is orchestrated using a YAML manifest file that contains the settings and instructions.

Here’s an example of a basic manifest file you can use as a template:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: test-app
  template:
    metadata:
      labels:
        app: test-app
    spec:
      containers:
        - name: test-app
          image: msgsdeployregistry.azurecr.io/test-app:latest
          ports:
          - containerPort: 3000
---
apiVersion: v1
kind: Service
metadata:
  name: test-app
spec:
  type: LoadBalancer
  ports:
  - port: 3000
  selector:
    app: test-app

Save this to your project folder as "test-app.yaml" (or a similar filename), and be sure to replace the app name and image tag to match yours.

Lastly, to deploy the app, you can run the apply command:

kubectl apply -f test-app.yaml

With our app deployed and running, we can now connect to it on the cloud. Let’s get the external IP address of the load balancer like this and then open it on a web browser:

kubectl get service test-app --watch

What’s Next

Congratulations! You’ve successfully containerized and deployed a Node.js app to Azure that is ready to scale to as many nodes as you need. Now that we’ve learned how to globally scale game server backend code hosted on Azure, wouldn’t it be great to automate these steps with a real game server example?

Join us for the next part in this series to learn how to automate your development and deployment process with a real, fully functional multiplayer game server using GitHub Actions.

Optional: Cleaning up

If you’re done after this demo and would like to stop here, use the following command to delete your resources on Azure to avoid any unexpected server costs:

az group delete --name ms-gs-deploy --yes --no-wait

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here