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:
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:
...
"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