Deploying microservices to IBM Cloud

duration 1 hour
Git clone to get going right away:
git clone https://github.com/OpenLiberty/guide-cloud-ibm.git
Copy Github clone command

Explore how to deploy microservices to IBM Cloud Kubernetes Service (IKS) and IBM Cloud Private (ICP).

What you’ll learn

You will learn how to deploy two microservices in Open Liberty containers to a Kubernetes cluster on IBM Cloud.

Kubernetes is an open source container orchestrator that automates many tasks involved in deploying, managing, and scaling containerized applications. If you would like to learn more about Kubernetes, check out the Deploying microservices to Kubernetes guide.

There are different cloud-based solutions for running your workloads in a Kubernetes cluster. A cloud-based infrastructure enables you to focus on developing your microservices without worrying about details related to the servers you deploy them to. Using a cloud helps you to easily scale and serve your microservices in a high-availability setup.

IBM Cloud Kubernetes Service (IKS) is part of IBM’s public cloud offerings. It provides a hosted Kubernetes cluster where you can deploy your microservices. You will use it with IBM Cloud Container Registry, a private registry used to store and distribute your container images.

The two microservices you will deploy are called system and inventory. The system microservice returns the JVM system properties of the running container. It also returns the pod’s name in the HTTP header, making replicas easy to distinguish from each other. The inventory microservice adds the properties from the system microservice to the inventory. This demonstrates how communication can be established between pods inside a cluster.

You will use Helm to deploy these microservices to IBM Cloud using Open Liberty Helm charts. Helm is a package manager for Kubernetes. It uses templates to generate Kubernetes yaml files and then deploys and manages them as releases in your cluster.

Prerequisites

Before you begin, the following tools need to be installed:

  • Docker: You need a containerization software for building containers. Kubernetes supports various container types, but you will use Docker in this guide. For installation instructions, refer to the official Docker documentation.

  • kubectl: You need the Kubernetes command-line tool kubectl to interact with your Kubernetes cluster. See the official Install and Set Up kubectl documentation for information about downloading and setting up kubectl on your platform.

  • Helm: You will use the Helm Command Line Interface (CLI) to install Helm’s Tiller to your Kubernetes cluster and to manage releases in your Kubernetes cluster. Download Helm v2.13.1 and see the official Installing Helm documentation for information about setting up helm on your platform.

  • IBM Cloud CLI: You will use the IBM Cloud CLI to interact with IBM Cloud. To install the IBM Cloud CLI for your platform, run one of the following commands:

    MAC

    curl -fsSL https://clis.cloud.ibm.com/install/osx | sh

    LINUX

    curl -fsSL https://clis.cloud.ibm.com/install/linux | sh

    WINDOWS

    Open command prompt as an administrator and run the following command.

    powershell -command "Set-ExecutionPolicy Unrestricted; iex(New-Object Net.WebClient).DownloadString('https://clis.cloud.ibm.com/install/powershell')"
  • IBM Cloud Container Registry plug-in: To install the container registry plug-in, run the following command:

    ibmcloud plugin install container-registry
  • IBM Cloud Kubernetes Service plug-in: To install the Kubernetes registry plug-in, run the following command:

    ibmcloud plugin install kubernetes-service

Getting started

The fastest way to work through this guide is to clone the Git repository and use the projects that are provided inside:

git clone https://github.com/openliberty/guide-cloud-ibm.git
cd guide-cloud-ibm

The start directory contains the starting project that you will build upon.

The finish directory contains the finished project that you will build.

Creating a Kubernetes cluster on IBM Cloud

Before you can deploy your microservices, you must create a Kubernetes cluster on IBM Cloud.

Configuring IBM Cloud CLI

Log in to IBM Cloud by using the ibmcloud command line. When you are prompted to select a region, choose us-south. This allows you to create a free cluster, which is limited to specific regions. Note that if you are using a federated user ID, you will have to use the --sso flag to get a one-time code for single sign-on.

ibmcloud login

Provisioning a cluster

To create a Kubernetes cluster, you need Administrator access to IBM Cloud Kubernetes Service. To confirm that you have Administrator access, navigate to the IBM Cloud Dashboard. Then, navigate to Manage > Access (IAM) > Users > [Your Username] > Access Policies and confirm that Administrator is listed as a policy for all resources in the account or for the Kubernetes service.

Once you have confirmed that you have appropriate permissions, use the following command to provision a cluster.

ibmcloud ks cluster-create --name guide-cluster

This command provisions a free cluster that expires in a month if you do not delete it.

The 'machine-type' flag was not specified. So a free cluster will be created.
Creating cluster...
OK

Check the current status of your cluster.

ibmcloud ks clusters

Wait until your cluster is in the normal state before proceeding. It will start off in the deploying state.

Name            ID                                 State       Created         Workers   Location   Version        Resource Group Name
guide-cluster   d1229f539ee902ca91g6d187c2dxy5s3   deploying   4 minutes ago   1         Dallas     1.10.11_1536   default

Next, it will transition to the pending state.

Name            ID                                 State       Created         Workers   Location   Version        Resource Group Name
guide-cluster   d1229f539ee902ca91g6d187c2dxy5s3   pending     19 minutes ago   1        Dallas     1.10.11_1536   default

Finally, it will transition to the normal state. It may take a while for IKS to prepare your cluster.

Name            ID                                 State       Created         Workers   Location   Version        Resource Group Name
guide-cluster   d1229f539ee902ca91g6d187c2dxy5s3   normal      4 hours ago     1         Dallas     1.10.11_1536   default

Once your cluster is ready, connect kubectl to the cluster.

LINUX | MAC

eval $(ibmcloud ks cluster-config --export guide-cluster)

WINDOWS

ibmcloud ks cluster-config --export guide-cluster > tmp-set-cluster.cmd
call tmp-set-cluster.cmd
del tmp-set-cluster.cmd

Verify that you’re connected to the cluster by checking the cluster’s nodes.

kubectl get nodes
NAME           STATUS    ROLES     AGE       VERSION
10.70.200.73   Ready     <none>    1h        v1.10.11+IKS

Deploying microservices to IBM Cloud Kubernetes Service (IKS)

In this section, you will learn how to deploy two microservices in Open Liberty containers to a Kubernetes cluster on IBM Cloud. You will build and containerize the system and inventory microservices, push them to a container registry and, then deploy them to your Kubernetes cluster.

Building and containerizing the microservices

The first step of deploying to Kubernetes is to build and containerize your microservices.

The starting Java project, which you can find in the start directory, is a multi-module Maven project. It’s made up of the system and inventory microservices. Each microservice resides in its own directory, start/system and start/inventory. Each of these directories also contains a Dockerfile, which is necessary for building Docker images. If you’re unfamiliar with Dockerfiles, check out the Using Docker containers to develop microservices guide.

If you’re familiar with Maven and Docker, you might be tempted to run a Maven build first and then use the .war file to build a Docker image. We’ve set up the projects such that this process is automated as a part of a single Maven build. It’s created by using the dockerfile-maven plug-in. The plug-in automatically picks up the Dockerfile that is located in the same directory as its POM file and builds a Docker image from it.

WINDOWS

On the Docker Desktop General Setting page, ensure that the option Expose daemon on tcp://localhost:2375 without TLS is enabled. This configuration is required by the dockerfile-maven part of the build.

Navigate to the start directory and run the following command:

mvn package

The package goal automatically starts the dockerfile-maven:build goal. It runs during the package phase. This goal builds a Docker image from the Dockerfile that is located in the same directory as the POM file.

During the build, you’ll see various Docker messages describing what images are being downloaded and built. When the build finishes, run the following command to list all local Docker images:

docker images

Verify that the system:1.0-SNAPSHOT and inventory:1.0-SNAPSHOT images are listed among them, for example:

REPOSITORY                 TAG
system                     1.0-SNAPSHOT
inventory                  1.0-SNAPSHOT
open-liberty               latest

If you don’t see the system:1.0-SNAPSHOT and inventory:1.0-SNAPSHOT images, then check the Maven build log for any potential errors.

Pushing the images to a container registry

Pushing the images to a registry enables the cluster to create pods by using your container images. Since it’s a private repository, only users with access to your IBM Cloud account will have access to these images.

The registry you will use is called IBM Cloud Container Registry. Use the container registry plug-in to create a namespace for your container images. The namespace must be unique within IBM Cloud for the region you selected, so choose something relevant that you’ll remember for the duration of the guide.

ibmcloud cr namespace-add [your-namespace]

Use the plug-in again to log in to the container registry.

ibmcloud cr login

Next, tag your container images with the relevant data about your registry. Remember to replace [your-namespace] with the namespace you created earlier in the guide.

docker tag system:1.0-SNAPSHOT us.icr.io/[your-namespace]/system:1.0-SNAPSHOT
docker tag inventory:1.0-SNAPSHOT us.icr.io/[your-namespace]/inventory:1.0-SNAPSHOT

Finally, push your images to the registry. Remember to replace [your-namespace] with the namespace you created earlier in the guide.

docker push us.icr.io/[your-namespace]/system:1.0-SNAPSHOT
docker push us.icr.io/[your-namespace]/inventory:1.0-SNAPSHOT

Deploying the microservices

Helm is a package manager for Kubernetes. It allows you to create a package called a chart. You can install a chart on your cluster as a release and then manage the release using Helm.

Set up role-based access control (RBAC) to give Helm’s Tiller server admin access to your cluster. Deploy the service account and cluster role binding that is required for the Tiller.

kubectl apply -f https://raw.githubusercontent.com/IBM-Cloud/kube-samples/master/rbac/serviceaccount-tiller.yaml
serviceaccount/tiller created
clusterrolebinding.rbac.authorization.k8s.io/tiller created

Next, install Tiller to your cluster. Specify that the Tiller should run under the service account that was created in the previous step.

helm init --service-account tiller

After the command completes, you will see output similar to the following.

$HELM_HOME has been configured at /Users/OpenLiberty/.helm.

Tiller (the Helm server-side component) has been installed into your Kubernetes Cluster.

Please note: by default, Tiller is deployed with an insecure 'allow unauthenticated users' policy.
To prevent this, run `helm init` with the --tiller-tls-verify flag.
For more information on securing your installation see: https://docs.helm.sh/using_helm/#securing-your-helm-installation
Happy Helming!

All pods run under a service account. By default, your pod runs under the default service account for your namespace. Helm’s Tiller server is running under the tiller service account. The tiller service account is bound to the cluster role cluster-admin. This role grants access to all resources in your cluster. Therefore, the Tiller server has access to all of your cluster’s resources.

Add the ibm-charts repository to your local list of Helm repositories. Adding the repository allows you to use the ibm-open-liberty chart.

helm repo add ibm-charts https://raw.githubusercontent.com/IBM/charts/master/repo/stable/

Use Helm to deploy the system microservice. Remember to replace [your-namespace] with the namespace you created earlier in the guide.

LINUX | MAC

helm install --name system-app \
    --set image.repository=us.icr.io/[your-namespace]/system \
    --set image.tag=1.0-SNAPSHOT \
    --set image.pullSecret=default-us-icr-io \
    --set service.name=system-service \
    --set service.port=9080 \
    --set service.targetPort=9080 \
    --set ssl.enabled=false \
    ibm-charts/ibm-open-liberty

WINDOWS

helm install --name system-app ^
    --set image.repository=us.icr.io/[your-namespace]/system ^
    --set image.tag=1.0-SNAPSHOT ^
    --set image.pullSecret=default-us-icr-io ^
    --set service.name=system-service ^
    --set service.port=9080 ^
    --set service.targetPort=9080 ^
    --set ssl.enabled=false ^
    ibm-charts/ibm-open-liberty

Use Helm to deploy the inventory microservice. Remember to replace [your-namespace] with the namespace you created earlier in the guide.

LINUX | MAC

helm install --name inventory-app \
    --set image.repository=us.icr.io/[your-namespace]/inventory \
    --set image.tag=1.0-SNAPSHOT \
    --set image.pullSecret=default-us-icr-io \
    --set service.name=inventory-service \
    --set service.port=9080 \
    --set service.targetPort=9080 \
    --set ssl.enabled=false \
    ibm-charts/ibm-open-liberty

WINDOWS

helm install --name inventory-app ^
    --set image.repository=us.icr.io/[your-namespace]/inventory ^
    --set image.tag=1.0-SNAPSHOT ^
    --set image.pullSecret=default-us-icr-io ^
    --set service.name=inventory-service ^
    --set service.port=9080 ^
    --set service.targetPort=9080 ^
    --set ssl.enabled=false ^
    ibm-charts/ibm-open-liberty

After you run helm install, an output is displayed providing instructions on how to access your deployed microservices. Ignore these instructions for now, you will learn how to access your microservices in the next section.

The --name flag specifies the release name, which must be unique. This is the name that Helm uses to identify this specific deployment of your chart. The following table gives an overview for each of the parameters specified using --set.

Parameter

Description

image.repository

The name of your Docker image including registry/repository prefix

image.tag

The tag for your Docker image

image.pullSecret

The image pull secret, since the container registry is private

service.name

The name of the service

service.port

The port exposed by the service

service.targetPort

The port exposed by the pod

ssl.enabled

Specify if SSL is enabled

Finding the microservice’s IP address and ports

The service used to expose our deployments has a type of NodePort. This means you can access these services from outside of your cluster via a specific port. In this case, since nodePort is not specified, the ports are randomized so you must obtain the ports before making requests to the services. You must also obtain the public IP address of our cluster. Note that there are other ways to expose your services such as using a LoadBalancer service type or using an Ingress. In production, you would most likely use an Ingress.

First, find the current context of your cluster.

kubectl config current-context

Take note of the context shown in the command’s output.

guide-cluster

Then, substitute the context into the following command to get the public IP address of your cluster.

ibmcloud ks workers [current-context]

Take note of the Public IP in the command’s output. This will be the hostname you substitute into commands later in this guide.

OK
ID                            Public IP       Private IP     Machine Type    State    Status   Zone    Version
kube-hou02-pad15e5f9-w1       172.173.65.24   10.77.198.71   free            normal   Ready    hou02   1.10.11_1538*

Get the node port of the system microservice.

kubectl get service system-service -o jsonpath="{.spec.ports[0].nodePort}{'\n'}"

Get the node port of the inventory microservice.

kubectl get service inventory-service -o jsonpath="{.spec.ports[0].nodePort}{'\n'}"

Take note of the IP address and ports. They are required to make the HTTP requests.

Making requests to the microservices

To make a request to the system and inventory microservices, curl or visit the following URLs to access your microservices, substituting the appropriate hostname and node ports:

  • http://[hostname]:[system-node-port]/system/properties

  • http://[hostname]:[inventory-node-port]/inventory/systems/system-service

The first URL returns system properties and the name of the pod in an HTTP header called X-Pod-Name. To view the header, you can use the -I option in the curl when making a request to http://[hostname]:[system-node-port]/system/properties. The second URL adds properties from system-service to the inventory.

Testing microservices that are running on IBM Cloud

A few tests are included for you to test the basic functionality of the microservices. If a test failure occurs, then you might have introduced a bug into the code. To run the tests, wait for all pods to be in the ready state before proceeding further. The default properties that are defined in the pom.xml are:

PropertyDescription

cluster.ip

IP or hostname for your cluster

system.kube.service

Name of the Kubernetes Service wrapping the system pods, system-service by default.

system.node.port

The NodePort of the Kubernetes Service system-service, 31000 by default.

inventory.node.port

The NodePort of the Kubernetes Service inventory-service, 32000 by default.

Use the following command to run the integration tests against your cluster. Substitute [hostname], [system-node-port] and [inventory-node-port] with the appropriate values.

mvn verify -Ddockerfile.skip=true -Dcluster.ip=[hostname] -Dsystem.node.port=[system-node-port] -Dinventory.node.port=[inventory-node-port]

The dockerfile.skip parameter is set to true in order to skip building a new container image.

If the tests pass, you’ll see an output similar to the following for each service respectively:

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running it.io.openliberty.guides.system.SystemEndpointTest
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.673 sec - in it.io.openliberty.guides.system.SystemEndpointTest

Results:

Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running it.io.openliberty.guides.inventory.InventoryEndpointTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.222 sec - in it.io.openliberty.guides.inventory.InventoryEndpointTest

Results:

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

Deploying new version of system microservice

Optionally, you might want to make changes to your microservice and learn how to redeploy the updated version of your microservice. In this section, you will bump the version of the system microservice to 2.0-SNAPSHOT and redeploy the new version of the microservice. You can redeploy a microservice using Helm to upgrade the release.

The tag for the container image is dependent on the version specified in the pom.xml file. Use the following Maven command to bump the version of the microservice to 2.0-SNAPSHOT.

mvn versions:set -DnewVersion=2.0-SNAPSHOT

Use Maven to repackage your microservice and build the new version of the container image.

mvn package

Since you built a new image, it will have to be pushed to the repository again.

Tag your container image with the relevant data about your registry.

docker tag system:2.0-SNAPSHOT us.icr.io/[your-namespace]/system:2.0-SNAPSHOT

Push your image to the registry.

docker push us.icr.io/[your-namespace]/system:2.0-SNAPSHOT

Use Helm to redeploy the system microservice.

LINUX | MAC

helm upgrade \
    --set image.repository=us.icr.io/[your-namespace]/system \
    --set image.tag=2.0-SNAPSHOT \
    --set image.pullSecret=default-us-icr-io \
    --set service.name=system-service \
    --set service.port=9080 \
    --set service.targetPort=9080 \
    --set ssl.enabled=false \
    system-app ibm-charts/ibm-open-liberty

WINDOWS

helm upgrade ^
    --set image.repository=us.icr.io/[your-namespace]/system ^
    --set image.tag=2.0-SNAPSHOT ^
    --set image.pullSecret=default-us-icr-io ^
    --set service.name=system-service ^
    --set service.port=9080 ^
    --set service.targetPort=9080 ^
    --set ssl.enabled=false ^
    system-app ibm-charts/ibm-open-liberty

Use the following command to find the name of the pod that is running the system microservice.

kubectl get pods
NAME                                        READY     STATUS    RESTARTS   AGE
inventory-app-ibm-open-l-5c586b9cfc-h5zmg   1/1       Running   0          23s
system-app-ibm-open-libe-84976bccfb-r22lj   1/1       Running   0          2m15sm

Observe that in this case the system microservice is running in the pod called system-app-ibm-open-libe-84976bccfb-r22lj. Substitute the name of your pod into the following command to see more details about the pod.

kubectl describe pod [pod-name]

View the events at the bottom of the command’s output. Observe that the pod is using the new container image system:2.0-SNAPSHOT.

Events:
  Type     Reason     Age                From                   Message
  ----     ------     ----               ----                   -------
  Normal   Scheduled  47s                default-scheduler      Successfully assigned default/system-app-ibm-open-libe-84976bccfb-r22lj 172.173.65.24
  Normal   Pulling    47s                kubelet, 172.173.65.24  pulling image "registry.ng.bluemix.net/[your-namespace/system:2.0-SNAPSHOT"
  Normal   Pulled     40s                kubelet, 172.173.65.24  Successfully pulled image "registry.ng.bluemix.net/[your-namespace]/system:2.0-SNAPSHOT"
  Normal   Created    40s                kubelet, 172.173.65.24  Created container
  Normal   Started    39s                kubelet, 172.173.65.24  Started container

Tearing down the environment

When you no longer need your deployed microservices, you can delete them with the following Helm commands:

helm delete --purge system-app
helm delete --purge inventory-app

Uninstall Tiller from your cluster by running the following Helm command.

helm reset

Log out of your container registry.

docker logout us.icr.io

Remove your IKS cluster.

ibmcloud ks cluster-rm guide-cluster

Log out of the ibmcloud command line tool.

ibmcloud logout

Deploying to IBM Cloud Private

Some situations may require you to manage your own infrastructure, such as if you want to deploy on-premises. If this describes your needs, then private clouds may be a more suitable solution for you.

A private cloud is a good option for developers who want to run their microservices on an infrastructure that they control. While the operations team will still need to maintain this infrastructure, a private cloud saves developers from having to worry about infrastructure. Kubernetes acts as an abstraction of the infrastructure so the developers can request what they need and it is the responsibility of the infrastructure’s maintainers to provide the necessary resources.

IBM Cloud Private (ICP) is an on-premises Kubernetes platform from IBM. Deploying microservices to ICP is similar to deploying to IKS. The main differences are in the setup process, and in how you tag your container images.

To obtain an ICP instance, see the IBM Cloud Private website. To set up your local environment, go to the ICP Dashboard. Navigate to the Command Line Tools > Cloud Private CLI page and follow the instructions to set up each CLI tool. Unlike IKS, you do not need to run helm init or deploy the cluster role binding and service account to your cluster. This is because ICP has Helm’s Tiller set up out of the box. To connect your local command line tools to the ICP instance, use cloudctl login.

When you tag a container image, you must tag the image with the registry as a prefix to your image name. This prefix is how Docker knows which registry to push your images to. For example, assume your ICP instance’s container registry is mycluster.icp:8500. To tag your image, you must prefix the image name with the registry and namespace. Let’s say you want to push your image to a repository in the default namespace, then you would tag your system microservice’s image mycluster.icp:8500/default/system. This tag specifies mycluster.icp:8500 as the container registry to push to and default as the namespace your image’s repository will reside in.

When you deploy the microservices to ICP by using Helm, it is important to add the --tls flag to all Helm commands. This flag is required because Helm’s Tiller in ICP has TLS enabled to always verify client certificates. In addition, if you are trying to access the image from the namespace that hosts it, you do not need an imagePullSecret and the --set image.pullSecret=default-us-icr-io flag can be removed from the helm install and helm upgrade commands. If you require an imagePullSecret, update the --set image.pullSecret=default-us-icr-io flag with your imagePullSecret.

You can learn more about deploying microservices to ICP by following an interactive guided demo.

Great work! You’re done!

You have just deployed two microservices to IBM Cloud. You have learned to use Helm to install your microservices on a Kubernetes cluster using the Open Liberty helm chart.

Guide Attribution

Deploying microservices to IBM Cloud by Open Liberty is licensed under CC BY-ND 4.0

Copied to clipboard
Copy code block

Nice work! Where to next?

What did you think of this guide?

Extreme Dislike Dislike Like Extreme Like

What could make this guide better?

Raise an issue to share feedback

Create a pull request to contribute to this guide

Need help?

Ask a question on Stack Overflow

Like Open Liberty? Star our repo on GitHub.

Star