Originally published on strongloop.com
Part 5: Deploying our Application to Kubernetes on IBM Cloud
In This Episode
Now that our project has basic features that allow us to create our own characters and log in, it's time to deploy it to cloud! So, we will first run our project in Docker and then push it to Kubernetes cluster on IBM Cloud.
Docker images are lightweight, portable, and self-sufficient. Once you create a Docker image, you can run it almost everywhere. On the other hand, Kubernetes will handle those high level concepts such as storage, network and scale-up.
You can check here for the code from this episode.
In this series, I’m going to help you learn LoopBack 4 and how to use it to easily build your own API and web project. We’ll create a new project I’ve been thinking about: an online web text-based adventure game. In this game, you can create your own account to build characters, fight monsters and find treasures. You will be able to control your character to take a variety of actions: attacking enemies, casting spells, and getting loot. This game also allows multiple players to log in and play with their friends.
Previously on Building an Online Game With LoopBack 4
In last episode, we covered how to combine your self-defined authorization strategies and services with
@loopback/authentication and how to apply it to your API.
Here are the previous episodes:
- Part 1: Building a Simple LoopBack Project With MongoDB
- Part 2: Generating Universally Unique ID and Managing Models Relationships
- Part 3: Customizing APIs in Controller
- Part 4: User Authentication and Role-Based Access Control
You don't have to fully understand those concepts before we start. I will show you how to use them step by step.
The Illustrated Children's Guide to Kubernetes is a wonderful video on YouTube that can give you a clear idea of what is Kubernetes.
Deploying to Kubernetes on IBM Cloud is a tutorial on the official LoopBack 4 website. Because our project is a bit different and uses MongoDB, we need to set up MongoDB on cloud and connect our project to it.
Adding Docker Feature
In Episode 1, we disabled Docker when we created our project. Now we need to manually add the Docker feature.
In your project root, create a file called
# Check out https://hub.docker.com/_/node to select a new base image
# Set to a non-root built-in user `node`
# Create app directory (with user `node`)
RUN mkdir -p /home/node/app
# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available (npm@5+)
COPY --chown=node package*.json ./
RUN npm install
# Bundle app source code
COPY --chown=node . .
RUN npm run build
# Bind to all network interfaces so that it can be mapped to the host OS
ENV HOST=0.0.0.0 PORT=3000
CMD [ "node", "." ]
Then create a file called
.dockerignore are two Docker-related files that are provided by LoopBack 4. We will use them to create a Docker image.
package.json, add two lines under
scripts. Those are the commands to build and run Docker image.
"docker:build": "docker build -t firstgame .",
"docker:run": "docker run -p 3000:3000 -d firstgame",
Building Docker Image
Install Docker if you haven't already.
Run this command to create Docker image.
npm run docker:build
If it succeeds, you will see:
Successfully built 0b2c1ff52a2e
Successfully tagged firstgame:latest
Run this command to show all images:
docker image ls
You should see two images like this:
REPOSITORY TAG IMAGE ID CREATED SIZE
firstgame latest 0b2c1ff52a2e 44 seconds ago 430MB
node 10-slim a41b78200d6f 6 days ago 148MB
Now, our image is ready to run. Run this command to create a container. A container is a running instance of an image.
npm run docker:run
Run this command to show all running containers.
You will see:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
88cc8acfbeea firstgame "node ." 5 minutes ago Up 5 minutes 0.0.0.0:3000->3000/tcp friendly_archimedes
Because we didn't specify container's name, Docker randomly assigned one for it.
Run this command to see the log output of your container. Replace
<container id> with your container id. In my case, it is
docker logs <container id>
You should see something like this:
Server is running at http://127.0.0.1:3000
Now, you should be able to open the API explorer: http://127.0.0.1:3000/explorer/
If everything is fine, run this command to stop the image.
docker stop <container id>
We are now ready to push our Docker image to cloud.
Pushing Docker image to IBM Cloud.
Run this command to login IBM Cloud.
If you are using a federated IBM ID, use this command instead:
ibmcloud login -sso
If you logged in successfully, you will see something like:
API endpoint: https://cloud.ibm.com
Account: IBM (114e44f826b74008a2afbf099e6b3561)
Resource group: Default
CF API endpoint:
Log in to IBM Cloud Container Registry. This is where we store our Docker image.
ibmcloud cr login
If this succeeds, you will see something like:
Logging in to 'us.icr.io'...
Logged in to 'us.icr.io'.
This is the container registry region you logged into.
After we log in, let's create a new namespace for our project.
ibmcloud cr namespace-add my-lb4-namespace
You can run
ibmcloud cr namespace-list to show all of your namespaces.
Run this command to tag the local docker image with the IBM Cloud container registry.
docker tag <image_name>:<tag> <container_registry_region>/<my_namespace>/<new_image_repo>:<new_tag>
In my case, this command will look like this:
docker tag firstgame:latest us.icr.io/my-lb4-namespace/firstgame-repo:1.0
Then push the local image to the container registry.
docker push us.icr.io/my-lb4-namespace/firstgame-repo:1.0
You will see something like this:
The push refers to repository [us.icr.io/my-lb4-namespace/firstgame-repo]
637a53e1e6ed: Pushing [==============================> ] 144.1MB/236.6MB
When it is done, run the following command to show images on your container registry.
ibmcloud cr image-list
You should see this:
REPOSITORY TAG DIGEST NAMESPACE CREATED SIZE SECURITY STATUS
us.icr.io/my-lb4-namespace/firstgame-repo 1.0 3c853b97ffec my-lb4-namespace 1 hour ago 144 MB No Issues
SECURITY STATUS shows
No Issues. If you get issues here, you may want to check Managing image security with Vulnerability Advisor for more related information.
Lastly, run this command to build Docker image on the container registry. Don't forget the
. at the end.
ibmcloud cr build -t us.icr.io/my-lb4-namespace/firstgame-repo:1.0 .
Creating Kubernetes Cluster
If you don't have a Kubernetes Cluster yet, login to your IBM Cloud in browser and go to https://cloud.ibm.com/kubernetes/catalog/cluster/create to create a free cluster. It may take a while.
When it is done, run this command to point to Kubernetes cluster. My cluster name is
ibmcloud cs cluster-config <Cluster Name>
You will see something like this. Copy and run the last line.
The configuration for firstgame-cluster was downloaded successfully.
Export environment variables to start using Kubernetes.
Run this command to verify your cluster.
kubectl get nodes
You should see something like this.
NAME STATUS ROLES AGE VERSION
10.47.84.60 Ready <none> 5d v1.13.6+IKS
Now your cluster is ready to use.
Setting up MongoDB and Deploying our Project to Kubernetes
Because our project is using MongoDB, we need to set up a MongoDB container and our project container in one Kubernetes pod. A Kubernetes pod is a group of one or more containers. Containers in the same pod will share storage and network.
Let's first create a file called
first-game.yaml in our project root. We will use this
yaml file to specify containers and pod. Check here for more information about Kubernetes
- name: fg
- containerPort: 3000
- name: db
- containerPort: 27017
As you can see, we have two containers.
fg is for our project.
db is for MongoDB. They will be running in the same pod so they can share network and talk to each other.
Run this command to use the
yaml file to create containers and pod:
kubectl create -f first-game.yaml
You will see something like this.
deployment.extensions "firstgame" deleted
wenbo:firstgame wenbo$ kubectl create -f first-game.yaml
deployment.extensions "firstgame" created
Run this command to verify our pod is running:
kubectl get pods
If succeeds, you will see this. The
2/2 means there are two containers running in this pod.
NAME READY STATUS RESTARTS AGE
firstgame-85ccbd5496-6nmvt 2/2 Running 0 1m
Now our application is running on Kubernetes. The next step is to expose it to the public.
kubectl expose deployment firstgame --type=NodePort --port=3000 --name=firstgame-service --target-port=3000
You should see this.
service "firstgame-service" exposed
Run this command to get NodePort for this service.
kubectl describe service firstgame-service
You should see:
Port: <unset> 3000/TCP
NodePort: <unset> 30776/TCP
Session Affinity: None
External Traffic Policy: Cluster
In my case, the NodePort is
The last thing we need is the IP address of our cluster.
ibmcloud ks workers firstgame-cluster
You will get something like this:
ID Public IP Private IP Machine Type State Status Zone Version
kube-bkrq1svd0l5j9p3147ng-mycluster-default-000000e0 18.104.22.168 10.76.216.103 free normal Ready hou02 1.13.8_1529
My cluster IP address is
Now we should be able to access to our application via http://22.214.171.124:30776
Applying This to Your Own Project
In this episode, we covered how to deploy our project with Docker and Kubernetes on IBM Cloud. Once you create a Docker image, you can run it almost everywhere. You can also push your own project image to other cloud like AWS, Azure, and Google Cloud. It should be very easy.
Next time, we will create a simply front-end UI for our project and do a quick demo.
In the meantime, learn more about LoopBack in past blogs.