Microservice Rainbow Rumpus

1. Introduction

Last Updated: 2021-05-06

Microservice Rainbow Rumpus

Ever been in a snowball fight where you move around and playfully throw snowballs at others? If not, try it someday! But now instead of risking getting physically smacked, you can build a small, network accessible service (a microservice) that will take part in an epic battle against other microservices, throwing rainbows instead of snowballs.

You might be wondering... But how does a microservice "throw" a rainbow at other microservices? A microservice can receive network requests (usually over HTTP) and return responses. There is an "arena manager" that will send your microservice the current state of the arena and then your microservice will respond with a command specifying what to do.

Of course the goal is to win, but along the way you'll learn about building and deploying microservices on Google Cloud.

How It Works

You will build a microservice with any technology you want (or choose from Go, Java, Kotlin, Scala, NodeJS, or Python starters) and then deploy the microservice on Google Cloud. Once deployed, you'll let us know the URL for your microservice and then we will add it to the arena.

The arena contains all of the players for a given battle. The Rainbow Rumpus will have its own arenas. Each player represents a microservice that moves around and throws rainbows at the other players.

About once a second our arena manager will call your microservice, sending the current arena state (where the players are), and your microservice will respond with a command for what to do. In the arena you can move forward, turn left or right, or throw a rainbow. A rainbow will travel up to three spaces in the direction the player is facing. If the rainbow "hits" another player, the thrower gets one point and the hit player loses a point. The arena size is auto-adjusted for the current number of players.

Here is how a past arena looks:

20628e6bd442bd11.png

Example Battle One arena

Revolving Conflicts

In the arena it is possible that multiple players try to perform conflicting actions. For instance, two players might try to move to the same space. In the case of a conflict, the microservice with the quickest response time wins.

Watching the Battle

To see how your microservice is doing in the battle, check out the live arena!

Battle API

In order to work with our arena manager, your microservice will need to implement a specific API to participate in the arena. The arena manager will send the current arena state in an HTTP POST to the URL you provide us, with the following JSON structure:

{
  "_links": {
    "self": {
      "href": "https://YOUR_SERVICE_URL"
    }
  },
  "arena": {
    "dims": [4,3], // width, height
    "state": {
      "https://A_PLAYERS_URL": {
        "x": 0, // zero-based x position, where 0 = left
        "y": 0, // zero-based y position, where 0 = top
        "direction": "N", // N = North, W = West, S = South, E = East
        "wasHit": false,
        "score": 0
      }
      ... // also you and the other players
    }
  }
}

Your HTTP response must be status code 200 (OK) with a response body containing your next move, encoded as a single uppercase character of either:

F <- move Forward
R <- turn Right
L <- turn Left
T <- Throw

That's all there is to it! Let's walk through deploying a microservice on Cloud Run, a Google Cloud service for running microservices and other applications.

2. Login to Google Cloud

To be able to deploy your microservice on Cloud Run you will need to login to Google Cloud. We will apply a credit to your account and you won't need to enter a credit card. It is usually less problematic to use a personal account (e.g. gmail.com) instead of a GSuite account because sometimes GSuite admins prevent their users from using certain Google Cloud features. Also, the web console we will be using should work great with Chrome or Firefox but might have issues in Safari.

3. Deploying Your Microservice

You can build your microservice with any technology and deploy it anywhere as long as it is reachable publicly and conforms to the Battle API. But to make things easy we will help you start from a sample service and deploy it on Cloud Run.

Pick Your Sample To Start With

There are numerous battle microservice samples you can start from:

Kotlin & Spring Boot

Source

Kotlin & Micronaut

Source

Kotlin & Quarkus

Source

Java & Spring Boot

Source

Java & Quarkus

Source

Go

Source

Node.js & Express

Source

Python & Flask

Source

After you decide which sample to start with, click the "Deploy on Cloud Run" button above. This will launch Cloud Shell (a web-based console to a virtual machine in the cloud) where the source will be cloned, then built into a deployable package (a docker container image), which is then uploaded to the Google Container Registry, and then deployed on Cloud Run.

When asked, specify the us-central1 region.

The screenshot below shows Cloud Shell output for microservice build and deployment

d88e40430706a32b.png

Verify the microservice works

In Cloud Shell you can make a request to your newly deployed microservice, replacing YOUR_SERVICE_URL with the URL for your service (which is in Cloud Shell after the "Your application is now live here" line):

curl -d '{
  "_links": {
    "self": {
      "href": "https://foo.com"
    }
  },
  "arena": {
    "dims": [4,3],
    "state": {
      "https://foo.com": {
        "x": 0,
        "y": 0,
        "direction": "N",
        "wasHit": false,
        "score": 0
      }
    }
  }
}' -H "Content-Type: application/json" -X POST -w "\n" \
  https://YOUR_SERVICE_URL

You should see the response string of either F, L, R, or T.

4. Request Inclusion in the Arena

To join the Rainbow Rumpus you will need to join an arena. Open rainbowrumpus.dev click join on an arena where you will provide your microservice URL.

5. Make & Deploy Changes

Before you can make changes you need to setup some information in Cloud Shell about the GCP project and the sample you used. First list your GCP projects:

gcloud projects list

You likely only have one project. Copy the PROJECT_ID from the first column and paste it into the following command (replacing YOUR_PROJECT_ID with your actual Project ID), in order to set an environment variable that we will use in later commands:

export PROJECT_ID=YOUR_PROJECT_ID

Now set another environment variable for the sample you used so in later commands we can specify the correct directory and service name:

# Copy and paste ONLY ONE of these
export SAMPLE=kotlin-micronaut
export SAMPLE=kotlin-quarkus
export SAMPLE=kotlin-springboot
export SAMPLE=java-quarkus
export SAMPLE=java-springboot
export SAMPLE=go
export SAMPLE=nodejs
export SAMPLE=python

Now, you can edit the source for your microservice from within Cloud Shell. To open the Cloud Shell web-based editor, run this command:

cloudshell edit cloudbowl-microservice-game/samples/$SAMPLE/README.md

You will then see further instructions for making changes.

f910c9ef7b51c406.png

Cloud Shell with the editor with the sample project open

After saving your changes, start the application in Cloud Shell using the command from the README.md file but first make sure you are in the correct sample directory in Cloud Shell:

cd cloudbowl-microservice-game/samples/$SAMPLE

Once the application is running, open a new Cloud Shell tab and test the service using curl:

curl -d '{
  "_links": {
    "self": {
      "href": "https://foo.com"
    }
  },
  "arena": {
    "dims": [4,3],
    "state": {
      "https://foo.com": {
        "x": 0,
        "y": 0,
        "direction": "N",
        "wasHit": false,
        "score": 0
      }
    }
  }
}' -H "Content-Type: application/json" -X POST -w "\n" \
  http://localhost:8080

When you are ready to deploy your changes, build your project in Cloud Shell using the pack command. This command uses Buildpacks to detect the project type, compile it, and create the deployable artifact (a docker container image).

# Make sure you are in a Cloud Shell tab where you set the PROJECT_ID
# and SAMPLE env vars. Otherwise, set them again.
pack build gcr.io/$PROJECT_ID/$SAMPLE \
  --path ~/cloudbowl-microservice-game/samples/$SAMPLE \
  --builder gcr.io/buildpacks/builder

Now that your container image has been created, use the docker command (in Cloud Shell) to push the container image to the Google Container Registry so that it can then be accessed by Cloud Run:

docker push gcr.io/$PROJECT_ID/$SAMPLE

Now deploy the new version on Cloud Run:

gcloud run deploy $SAMPLE \
          --project=$PROJECT_ID \
          --platform=managed \
          --region=us-central1 \
          --image=gcr.io/$PROJECT_ID/$SAMPLE \
          --allow-unauthenticated

Now the arena will use your new version!

6. Develop Locally (Optional)

You can work on your project locally using your own IDE by following these steps:

  1. [In Cloud Shell] Zip up the sample:
# Make sure the SAMPLE env var is still set. If not, re-set it.
cd ~/cloudbowl-microservice-game/samples
zip -r cloudbowl-sample.zip $SAMPLE
  1. [In Cloud Shell] Download the zip file to your machine:
cloudshell download-file cloudbowl-sample.zip
  1. [On your machine] Unzip the file and then make & test your changes
  2. [On your machine] Install the gcloud CLI
  3. [On your machine] Login to Google Cloud:
gcloud auth login
  1. [On your machine] Set the environment variables PROJECT_ID, and SAMPLE to the same values as in Cloud Shell.
  2. [On your machine] Use Cloud Build to build the container (from the root project directory):
gcloud alpha builds submit . \
  --pack=image=gcr.io/$PROJECT_ID/$SAMPLE \
  --project=$PROJECT_ID
  1. [On your machine] Deploy the new container:
gcloud run deploy $SAMPLE \
  --project=$PROJECT_ID \
  --platform=managed \
  --region=us-central1 \
  --image=gcr.io/$PROJECT_ID/$SAMPLE \
  --allow-unauthenticated

7. Continuous Delivery

Setup SCM

Setup GitHub so you can collaborate with your team on your microservice:

  1. Login to GitHub
  2. Create a new repo
  3. If you are working on your local machine you can either use the git command line interface (CLI) or the GitHub Desktop GUI application (Windows or Mac). If you are using Cloud Shell, you'll have to use the git CLI. To get your microservice's code on GitHub, follow either the CLI or GitHub Desktop instructions.

Push your code with the git CLI

  1. Follow the git over https with a personal access token instructions
  2. Choose "repo" scope
  3. Setup git:
git config --global credential.helper \
  'cache --timeout=172800'
git config --global push.default current
git config --global user.email "YOUR@EMAIL"
git config --global user.name "YOUR NAME"
  1. Set env vars for the GitHub org and repo (https://github.com/ORG/REPO)
export GITHUB_ORG=YOUR_GITHUB_ORG
export GITHUB_REPO=YOUR_GITHUB_REPO
  1. Push your code to the new repo
# Make sure the SAMPLE env var is still set. If not, re-set it.
cd ~/cloudbowl-microservice-game/samples/$SAMPLE
git init
git add .
git commit -m init
git remote add origin https://github.com/$GITHUB_ORG/$GITHUB_REPO.git
git branch -M main

# This will now ask for your GitHub username & password
# for the password use the personal access token
git push -u origin main
  1. After making any changes you can commit and push the changes to GitHub:
git add .
git status
git diff --staged
git commit -am "my changes"
git push

Push your code with GitHub desktop

  1. Download your code using the instructions from the previous "Develop Locally" lab
  2. Install GitHub Desktop, launch it, and login
  3. Clone your newly created repo

cf7f38c7c86a91cd.png

  1. Open your file explorer and copy your project into the new repo
  2. Commit your changes

5f3c1552e30ad7c5.png

  1. Publish your main branch to GitHub

Setup Cloud Run Continuous Deployment

With your SCM setup on GitHub you can now setup Continuous Delivery so that every time new commits are pushed to the main branch, Cloud Build will automatically build and deploy the changes. You can also add Continuous Integration which runs your tests before deploying, but that step has been left as an exercise for you since the out-of-the-box samples do not contain any tests.

  1. In the Cloud console, go to your Cloud Run service
  2. Click the "SET UP CONTINUOUS DEPLOYMENT" button
  3. Authenticate with GitHub and select your microserivce's repository

a3b5692f178869bc.png

  1. Select your GitHub repo and set the branch to: ^main$

338f1c00f33d2f65.png

  1. Set the Build Type to use Buildpacks
  2. Click Save to setup Continuous Deployment.

8. Observability

Things break. Observability gives us the ability to know when that happens and diagnose why. Metrics show us data about the health and usage of our service. Logs shows us the manually instrumented information emitted from our service. Alerts allow us to be notified when something goes wrong. Let's explore each of those further.

Metrics

  1. Find your service in the list of Cloud Run services
  2. Click on your service's name to visit it's metric dashboard

8491b8ec6bc5b4db.png

  1. Click on a metric's menu, then select "View in Metrics Explorer"
  2. You can now change resource metrics, filters, grouping, and other options. For instance, you can view mean service latencies for all services:

f0d666d8f4221d45.png

Logs

STDOUT output from services is sent to the Google Cloud Logging system. You can access a basic log view from the Cloud Run service admin page, like:

40058a82c9299cff.png

In the Cloud Run logs you can filter by severity and filter the logs. For more flexibility click: 186fdb0e6d39a6ca.png

Alerts

  1. Create a heathcheck URL for your service.
  2. For Spring Boot, just add the following dependency:
org.springframework.boot:spring-boot-starter-actuator
  1. Create or update the src/main/resources/application.properties and disable the diskspace check:
management.health.diskspace.enabled=false
  1. Create an uptime alert, specifying your protocol, hostname, and path. For Spring Boot the path is: /actuator/health
  2. Test the alert

6948d13b263bf573.png

  1. Create the alert

9. Congratulations

Congratulations, you've successfully built and deployed a microservice that can battle with other microservices! Good luck!

Reference Docs