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

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

Then log into the IBM Cloud CLI with

ibmcloud login

Or, if using SSO

ibmcloud login -sso

Next, log into the Cloud Registry with

ibmcloud cr login

Then create a namespace in the registry to store your images

ibmcloud cr namespace-add <NAMESPACE>

And lastly build and push the docker image

docker build --tag registry.ng.bluemix.net/<NAMESPACE>/hello-world .
docker images
docker push registry.ng.bluemix.net/<NAMESPACE>/hello-world

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

ibmcloud cs clusters
ibmcloud cs workers <CLUSTER NAME>

# Deploy Application

First we need to get our Kubernetes cluster configuration with

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

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

Next we can run our image as a deployment with

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

$env:KUBECONFIG="C:\Users\NabeelValley\.bluemix\plugins\container-service\clusters\mycluster\kube-
config-mil01-mycluster.yml"
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

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

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

We can examine our service with

kubectl describe service <DEPLOYMENT NAME>

We can get the public IP of our service with

ibmcloud cs workers <CLUSTER NAME>

We can visit our service/container from the

<PUBLIC IP>:<NODE PORT>

Visiting this via our browser should yield

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

kubectl edit deployment/<DEPLOYMENT NAME>

This will open a file that looks like this

    ...
    spec:
      replicas: 1
      selector:
        matchLabels:
          run: hello-world
      strategy:
        rollingUpdate:
          maxSurge: 1
          maxUnavailable: 1
        type: RollingUpdate
      template:
        metadata:
          creationTimestamp: null
          labels:
            run: hello-world
    ...

From here change the spec.replicas to 10

    ...
    spec:
      replicas: 10
    ...

Then we can rollout our changes with

kubectl rollout status deployment/<DEPLOYMENT NAME>

Once that is done we can view our pods with

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

docker build --tag registry.ng.bluemix.net/<namespace>/hello-world:1 .
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

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

Next, we can edit our config file with

kubectl edit deployment/<DEPLOYMENT NAME>

Or we can edit the deployment with the command line with

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)

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

kubectl rollout status deployment/<DEPLOYMENT NAME>
kubectl get replicasets

If we see that our deployments are not

Lastly we can do a rollout with

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

notepad .\healthcheck.yml

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

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

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

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

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

Then do the same for the Watson Talk image

docker build -t registry.ng.bluemix.net/<namespace>/watson-talk ./watson-talk
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

        spec:
          containers:
            - name: watson
              image: "registry.ng.bluemix.net/<namespace>/watson"
              # change to the path of the watson image you just pushed
              # ex: image: "registry.ng.bluemix.net/<namespace>/watson"
    ...
        spec:
          containers:
            - name: watson-talk
              image: "registry.ng.bluemix.net/<namespace>/watson-talk"
              # change to the path of the watson-talk image you just pushed
              # 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

ibmcloud target --cf
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

ibmcloud cf services

# Bind the Service to out Cluster

We can simply bind the service to our cluster with

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

And verify that it was created with

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

    volumeMounts:
            - mountPath: /opt/service-bind
              name: service-bind-volume
      volumes:
        - name: service-bind-volume
          secret:
            defaultMode: 420
            secretName: binding-tone
            # from the kubectl get secrets command above

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

kubectl create -f watson-deployment.yml

We can verify that the Watson pods were created with

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

kubectl get pods
kubectl get deployments
kubectl get services

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

ibmcloud cs workers <CLUSTER NAME>

We can run a get to our endpoint with a message

 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