Containers and Kubernetes on IBM Cloud

Updated: 03 September 2023

Based on this Cognitive Class Learning Path

Prerequisites

Before getting started, you will need a few prerequisites

  • IBM Cloud CLI
    • Kubernetes Plugin
    • Container Registry Plugin
  • Kubernetes CLI
  • Docker 1.9 or later

Kubernetes

Kubernetes is a container orchestrator to provision, manage and scale apps

It allows us to manage app resources, clusters, and infrastructure declaratively

Set Up and Deploy an App

# Push an Image to Registry

Note that the ng.bluemix.net should be replaced with your API endpoint, for example in my case eu-gb.bluemix.net, this is dependant on your Cloud Region

Clone the GitHub Repo and navigate into Lab 1

Terminal window
1
git clone https://github.com/IBM/container-service-getting-started-wt.git
2
cd '.\container-service-getting-started-wt\Lab 1\'

Then log into the IBM Cloud CLI with

Terminal window
1
ibmcloud login

Or, if using SSO

Terminal window
1
ibmcloud login -sso

Next, log into the Cloud Registry with

Terminal window
1
ibmcloud cr login

Then create a namespace in the registry to store your images

Terminal window
1
ibmcloud cr namespace-add <NAMESPACE>

And lastly build and push the docker image

Terminal window
1
docker build --tag registry.ng.bluemix.net/<NAMESPACE>/hello-world .
2
docker images
3
docker push registry.ng.bluemix.net/<NAMESPACE>/hello-world

Lastly we can make sure that our cluster is in a normal, operational state with

Terminal window
1
ibmcloud cs clusters
2
ibmcloud cs workers <CLUSTER NAME>

# Deploy Application

First we need to get our Kubernetes cluster configuration with

Terminal window
1
ibmcloud cs cluster-config <CLUSTER NAME or ID>

Once that has completed we will be faced with an option to set this config file as an environmental variable, we can copy this command and run it from Powershell to set the environmental variable, the resulting command will look something like the following for Windows

Terminal window
1
SET KUBECONFIG=C:\..\..\.bluemix\plugins\container-service\clusters\mycluster\kube-config-mil01-mycluster.yml

Next we can run our image as a deployment with

Terminal window
1
kubectl run hello-world --image=registry.ng.bluemix.net/<namespace>/hello-world

If after running that you are faced with an error which says error: failed to discover supported resources it could be an indicator that the environmental variable did not set, in this case do the following

Terminal window
1
$env:KUBECONFIG="C:\Users\NabeelValley\.bluemix\plugins\container-service\clusters\mycluster\kube-
2
config-mil01-mycluster.yml"
3
kubectl run hello-world --image=registry.ng.bluemix.net/<namespace>/hello-world

This will take some time, to view the status of our deployment we can use

Terminal window
1
kubectl get pods

When the status reads Running we can expose the deployment as a service which is accessed through the IP of the worker nodes, the HelloWorld example in this lab listens at 8080

Terminal window
1
kubectl expose deployment/hello-world --type="NodePort" --port=8080

We can examine our service with

Terminal window
1
kubectl describe service <DEPLOYMENT NAME>

We can get the public IP of our service with

Terminal window
1
ibmcloud cs workers <CLUSTER NAME>

We can visit our service/container from the

Terminal window
1
<PUBLIC IP>:<NODE PORT>

Visiting this via our browser should yield

Terminal window
1
Hello world from hello-world-85794b747c-z8g2s! Your app is up and running in a cluster!

Scale and Update Apps

# Scale Application with Replicas

We can view our deployment configuration file with

Terminal window
1
kubectl edit deployment/<DEPLOYMENT NAME>

This will open a file that looks like this

1
...
2
spec:
3
replicas: 1
4
selector:
5
matchLabels:
6
run: hello-world
7
strategy:
8
rollingUpdate:
9
maxSurge: 1
10
maxUnavailable: 1
11
type: RollingUpdate
12
template:
13
metadata:
14
creationTimestamp: null
15
labels:
16
run: hello-world
17
...

From here change the spec.replicas to 10

1
...
2
spec:
3
replicas: 10
4
...

Then we can rollout our changes with

Terminal window
1
kubectl rollout status deployment/<DEPLOYMENT NAME>

Once that is done we can view our pods with

Terminal window
1
kubectl get pods

Which should list our ten running pods

# Update and Rollback Apps

Kubernetes allows us to rollout app updates easily, and update the images on running pods, as well as rollback if issues are identified

Before we begin, we can get an image with a specific tag (in this case 1) and push it with

Terminal window
1
docker build --tag registry.ng.bluemix.net/<namespace>/hello-world:1 .
2
docker push registry.ng.bluemix.net/<namespace>/hello-world:1

Thereafter we can make a change to our code and build the new docker image and push those to the cloud registry with a tag 2

Terminal window
1
docker build --tag registry.ng.bluemix.net/<namespace>/hello-world:2 .
2
docker push registry.ng.bluemix.net/<namespace>/hello-world:2

Next, we can edit our config file with

Terminal window
1
kubectl edit deployment/<DEPLOYMENT NAME>

Or we can edit the deployment with the command line with

Terminal window
1
kubectl set image deployment/hello-world hello-world=registry.ng.bluemix.net/<NAMESPACE>/hello-world:2

If you see the following error on the Kubernetes Dashboard it may mean that you are using an incorrect registry endpoint in the last command, it is important to ensure that the registry endpoint is correct (as mentioned previously, in this case eu-gb and not ng)

Terminal window
1
Failed to pull image "registry.ng.bluemix.net/nabeellab1/hello-world:2": rpc error: code = Unknown desc = Error response from daemon: Get https://registry.ng.bluemix.net/v2/nabeellab1/hello-world/manifests/2: unauthorized: authentication required

Once we have updated our deployment configuration we can rollout our changes and check the status with one of the following commands

Terminal window
1
kubectl rollout status deployment/<DEPLOYMENT NAME>
2
kubectl get replicasets

If we see that our deployments are not

Lastly we can do a rollout with

Terminal window
1
kubectl rollout undo deployment/<DEPLOYMENT NAME>

# Check Application Health

We can check app health periodically by using the healthcheck.yml file, we can open this file with from our Lab 2 directory

1
notepad .\healthcheck.yml

We can edit this file as needed, by updating our image repository in this spec at

1
...
2
spec:
3
containers:
4
- name: hw-demo-container
5
image: "registry.ng.bluemix.net/<NAMESPACE>/hello-world:2"
6
...

Then, while still in the Lab 2 directory, push this update with

1
kubectl apply -f .\healthcheck.yml

Deploy an App with Watson Services

# Deploy the Watson App

Navigate to the Lab 3 Directory and build and push the Watson image to the Registry

1
docker build -t registry.ng.bluemix.net/<NAMESPACE>/watson ./watson
2
docker push registry.ng.bluemix.net/<NAMESPACE>/watson

Then do the same for the Watson Talk image

1
docker build -t registry.ng.bluemix.net/<namespace>/watson-talk ./watson-talk
2
docker push registry.ng.bluemix.net/<namespace>/watson-talk

Next, in the watson-deployment.yml file, update the registry information in the spec.containers for the two containers

1
spec:
2
containers:
3
- name: watson
4
image: "registry.ng.bluemix.net/<namespace>/watson"
5
# change to the path of the watson image you just pushed
6
# ex: image: "registry.ng.bluemix.net/<namespace>/watson"
7
...
8
spec:
9
containers:
10
- name: watson-talk
11
image: "registry.ng.bluemix.net/<namespace>/watson-talk"
12
# change to the path of the watson-talk image you just pushed
13
# ex: image: "registry.ng.bluemix.net/<namespace>/watson-talk"

# Create Instance of Watson Service from CLI

We can create an instance of the Watson Tone Analyzer Service with

1
ibmcloud target --cf
2
ibmcloud cf create-service tone_analyzer standard tone

Where

  • tone_analyzer is the service type
  • standard is the plan
  • tone is the service name

We can view that our service was created with

1
ibmcloud cf services

# Bind the Service to out Cluster

We can simply bind the service to our cluster with

1
ibmcloud cs cluster-service-bind <CLUSTER NAME> default <SERVICE NAME>

And verify that it was created with

1
kubectl get secrets

# Create Pods and Services

We can expose the secret to our pod so the service can be used by creating a secret data store as part of our deployment config, this is done already in the watson-deployment.yml file

1
volumeMounts:
2
- mountPath: /opt/service-bind
3
name: service-bind-volume
4
volumes:
5
- name: service-bind-volume
6
secret:
7
defaultMode: 420
8
secretName: binding-tone
9
# from the kubectl get secrets command above

Then we can build the app in the Lab 3 directory with

Terminal window
1
kubectl create -f watson-deployment.yml

We can verify that the Watson pods were created with

Terminal window
1
kubectl get pods

# Run the App and Service

We can explore the new objects we have created from the Kubernetes Dashboard or with the following commands

Terminal window
1
kubectl get pods
2
kubectl get deployments
3
kubectl get services

We can once again view our app by getting the public IP for the worker note with

Terminal window
1
ibmcloud cs workers <CLUSTER NAME>

We can run a get to our endpoint with a message

1
http://<PUBLIC IP>:30080/analyze/"Today is a beautiful day"

if we get a JSON output then we know the service and applications are running