Part 1: Introduction
For several years, I have wanted to learn more about IBM Cloud. Last week, I was at a Google Presentation (I was one of the speakers) on Google Cloud Run, and IBM Cloud Kubernetes was demonstrated. That caught me unprepared. Today, I decided to do something about that and learn Kubernetes on IBM Cloud. I plan to record my technical journey on getting started with IBM Cloud. Like most things I tackle, I allocate about two hours, three or more days per week for either seven or thirty days. Work often gets in the way of that schedule but I try to stay on track and focussed.
Part 2: My thoughts on IBM Cloud
I am writing this after spending a solid week studying IBM Cloud and having completed five IBM training courses.
IBM Cloud is clearly targeting the enterprise. They have some very interesting services such as IBM Watson. They have a much heavier focus on enterprise connectivity than even AWS. The Red Hat acquisition makes them a major player. IBM’s focus on Kubernetes and serverless is very good.
In my opinion, the cloud race has just begun and the top players, AWS, Azure, Google, IBM, and Alibaba, will continue to advance hybrid and multi-cloud into ways we are just imagining today.
I plan to continue learning each IBM Cloud service. My interest is mostly Multi-Cloud interoperability – use the best services from each cloud together. Watch for some future articles on integrating Stackdriver, IBM Watson, VPN networking and IBM App ID with Google Cloud.
Part 3: Daily Study
- Day #1 – July 17, 2019 – Signing up. IBM Cloud Essentials course – Lab #1
- Day #2 – July 18, 2019 – IBM Cloud Essentials course – Lab #2, #3 and Final Exam
- Day #3 – July 19, 2019 – IBM Container & Kubernetes Essentials with IBM Cloud course
- Day #4 – July 20, 2019 – Getting started with Microservices with Istio and IBM Cloud Kubernetes Service course
- Day #5 – July 21, 2019 – Apply end to end security to a cloud application course
- Day #6 – July 26, 2019 – PHP Web application on a LAMP Stack course
Day #1 – July 17, 2019
Signing up for IBM Cloud
Go to IBM Cloud and create an account. No credit card required. Without a credit card, you are somewhat limited, but I found how to get a reasonable amount of credit to fix that.
Finding training courses and introductory account credits
A quick Google search turned up this resource for training with the added benefit of $1,200 in IBM Cloud credits:
There are some very interesting courses on this site. Everything from Python programming, to AI, IBM Watson, Big Data, Hadoop and what I wanted to learn, IBM Cloud Kubernetes. I don’t know the quality of the courses yet, but I will in a few hours.
This site is very focussed on IBM Cloud and Red Hat Linux, but a lot of the courses will apply no matter what platform you use (cloud or desktop/laptop).
Selecting my first IBM Cloud Course
There are a lot of courses to select from. I chose “IBM Cloud Essentials” CL0101EN link.
Note to IBM: why did you choose such awful, long, and complicated URLs? Hint, use a URL shortener and redirects.
Installing the IBM Cloud CLI
The first step in this course is to set up the prerequisites. The first step is the IBM Cloud CLI. That did not go so well as it immediately displayed an error, but kept going.
Note to IBM: Quality check your fundamental/critical programs. Having an installer fail on Windows is not reassuring.
Note: To install the IBM Cloud CLI manually or update in the future: link.
IBM Error Message to investigate:
Command that I ran in a Powershell Administrator prompt:
[Net.ServicePointManager]::SecurityProtocol = "Tls12"; iex(New-Object Net.WebClient).DownloadString('https://ibm.biz/idt-win-installer')
Command output (first part that shows the error):
[main] --==[ IBM Cloud Developer Tools - Installer for Windows, v1.2.2 ]==-- [install] Starting Installation/Update... C:\Program Files\IBM\Cloud\bin\bx.exe : The term 'C:\Program Files\IBM\Cloud\bin\bx.exe' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again. At line:1 char:1 + C:\"Program Files"\IBM\Cloud\bin\bx.exe plugin list + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : ObjectNotFound: (C:\Program Files\IBM\Cloud\bin\bx.exe:String) , CommandNotFoundExcept ion + FullyQualifiedErrorId : CommandNotFoundException
As I investigated this error, I realized that the program (bx.exe) is part of the installation. This means that the installer depends on itself to install. I restarted Powershell and the second installation attempt worked without error.
CLI Login to IBM Cloud
IBM’s method reminds me of Google Cloud’s method:
ibmcloud login. Very easy, just enter my IBM Cloud login and password. Then I was prompted to select a region (only six are listed). I chose
The command then printed the following output (edited for security):
API endpoint: https://cloud.ibm.com Region: us-east User: firstname.lastname@example.org Account: John's Account (1234ab1234ab1234ab1234ab1234abea) Resource group: Default CF API endpoint: Org: Space: Tip: If you are managing Cloud Foundry applications and services - Use 'ibmcloud target --cf' to target Cloud Foundry org/space interactively, or use 'ibmcloud target --cf-api ENDPOINT -o ORG -s SPACE' to target the org/space. - Use 'ibmcloud cf' if you want to run the Cloud Foundry CLI with current IBM Cloud CLI context.
I chose to skip the Eclipse requirements for now. Here is the link just in case I need to come back and install them: link
What IBM Bluemix Offers
- Compute – Offerings spanning from bare metal to serverless programming.
- Hybrid – Delivered across public, dedicated, and on-premises deployment models.
- Global – Available in over 26 IBM Cloud data centers around the globe.
- Services – Offers over 130 composable services across Watson, data, mobile, IoT and DevOps.
- Open – Built on open standards and architecture like Cloud Foundry, Docker and OpenWhisk.
Flexible Compute Options
- Bare Metal – Maximum performance and control.
- Virtual Server or VMware – Leverage existing languages and tools.
- Containers – Maximum portability.
- Cloud Foundry – Open Paas environment
- OpenWhisk – Maximum speed with server-less apps.
First Test Deployment
I followed the directions in the course “IBM Cloud Essentials” Lab 1. I selected a Go application. This worked very well. I am impressed. However, there are two downloads in the documentation. Neither match the deployed example.
I then tried one of the downloads to do everything with the CLI. This was a problem. Nothing worked according to the step-by-step instructions in the readme.
- I tried
ibmcloud cf push. That reported the error
No org targeted, use 'cf.exe target -o ORG' to target an org.
- I tried
cf target -o myorg. That reported the error
'cf' is not recognized as an internal or external command, operable program or batch file.
- I then review the ibmcloud command-line options and found the command
ibmcloud account org-create myorg. That worked.
- Note: I figured out that cf.exe exists. It is in the directory
C:\Program Files\IBM\Cloud\bin\cfcliwhich was not installed in the
PATHas part of the IBM Cloud CLI setup.
Summary of this lab and today’s progress
IBM Cloud Foundry is very interesting. From what I can discover, Cloud Foundry is an open source product/platform. Cloud Foundry is container based, which I like. Cloud Foundry is as simple to use as Google App Engine and Google Cloud Run. Pivotal Cloud Foundry (link), might be a similar product to IBM Cloud Foundry. I don’t know Cloud Foundry enough to compare features, performance, security or DevOps.
The Cognitive Class AI course that I am watching is good but is out of date with the current IBM Cloud Console. We can expect this as everything is advancing quickly. However, the IBM Cloud documentation and CLI needs some quality assurance. The CLI recommends the wrong command (cf.exe) and the example page that I deployed from has the wrong source code (twice). This does not lend to real confidence when you are learning a new cloud provider. If I was a raw beginner, the problems that I ran into would have stopped me from accomplishing anything or caused endless delays and frustrations.
Day #2 – July 18, 2019
I added a credit card to my account and this morning I received several emails regarding my account being upgraded. IBM tries to be “hip” in their emails which is nice, but it is very clear to me that IBM is targeting corporate/enterprise customers so this type of email is strange.
The third email had a $200.00 credit and a link to apply the credit. However, when it rains it pours. The link informed me that I am not the account owner. I am the only person on the account. The error message said “Only the account owner can upgrade from a Lite account to a Premium account. If you’re ready, send an email to the account owner requesting an upgrade.” Now how do I send myself an email using the IBM Cloud Console? Nope, no link or menu entry could be found.
So, I opened a support case with IBM. IBM Cloud Support Case CS0384287. Opened at 7/18/19 11:26 AM PST. Still waiting for resolution. This was resolved a week later.
Note to IBM: Have one of your product manager go thru the process of creating a new account and remove all the roadblocks that just lead to customer frustration.
Note to IBM: Your email with the $200.00 credit is confusing. Your email states: “But just like the plant someone gave you as a housewarming gift, (which you promptly forgot to water because you were busy, ok?) this won’t last long. 30 days to be exact.”
Does that mean that I have 30 days to apply the credit to my account or the credit will expire in 30 days?
IBM Cloud Essentials course Lab #1 – Create an app from an application starter
I decide to repeat Lab #1 today. Yesterday I created a Cloud Foundry Go application. Today I will repeat with a PHP application.
Wow, nothing in their documentation works for PHP either.
In step 2 “Run the app locally”, the documentation shows to execute this command:
php composer.phar install
That command returns this error:
Loading composer repositories with package information Installing dependencies (including require-dev) from lock file [ErrorException] "continue" targeting switch is equivalent to "break". Did you mean to use "continue 2"? install [--prefer-source] [--prefer-dist] [--dry-run] [--dev] [--no-dev] [--no-custom-installers] [--no-autoloader] [--no-scripts] [--no-progress] [--no-suggest] [-v|vv|vvv|--verbose] [-o|--optimize-autoloader] [-a|--classmap-authoritative] [--apcu-autoloader] [--ignore-platform-reqs] [--] [<packages>]...
So I tried:
php composer.phar self-update
That returned the error:
Updating to version 1.8.6 (stable channel). Downloading: 100% [RuntimeException] SHA384 is not supported by your openssl extension, could not verify the phar file integrity self-update [-r|--rollback] [--clean-backups] [--no-progress] [--update-keys] [--stable] [--preview] [--snapshot] [--] [<version>]
I then executed these commands to update composer:
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" php composer-setup.php
php composer.phar install works.
However, the documentation is missing the command to actually run the sample application:
php -S localhost:8000
I then went on to use the CLI to deploy. Again the documentation did not work. After a bit of research, I figured out that I need to use this command first (changed for my security):
ibmcloud target -r us-south --cf -o email@example.com -s dev
Then I ran the deployment command:
ibmcloud cf push
I must say, I sure do love Google Cloud Run in comparison. However, to be fair to IBM, most times, frustration is caused by a lack of knowledge. I do not know how to recognize small problems with IBM Cloud or how to fix them. That comes with focus and hard work. Experience solves these issues. I will push on and get that knowledge and experience with IBM Cloud.
The correct steps to deploy the sample Cloud Foundry PHP application:
ibmcloud login ibmcloud target -r us-south --cf -o firstname.lastname@example.org -s dev ibmcloud cf push
Document link for Adding orgs and spaces. This is the document that helped me figure out the second command above.
Summary of Lab #1:
- I had problems with installing the PHP application requirements. This was caused by an out of date composer on my system. This is not IBM’s fault. However, some tips or notes about version requirements would be helpful.
- Since the IBM PHP and Go samples were developed the CLI has changed. The documentation does not match what you need to do in the CLI. The sample documentation mentions nothing about organizations and spaces. This caused me grief and frustration trying to get a simple example to work as intended by IBM.
- I am taking a beginner level course on IBM Cloud essentials. Covering these issues about organizations and spaces should have been covered before we went into a lab or the lab should have explained them.
- I recommend some real quality assurance where IBM uses newbies to do the labs and monitors their progress and problems. Then fix the documentation to be both correct and helpful. The goal is to learn IBM Cloud and not to be a bug-finder.
- In hindsight, I am glad that I ran into these problems. I learned more than I expected.
IBM Cloud Essentials course Lab #2 – create an app using continuous delivery
Three important items that are related to my previous lab: Region, Organization, Space. When you first create an account, the region is your email address. The space is “dev”. You can select a region.
This lab is very cool and I am not aware of any other cloud vendor that has this ability: One-click deployment that sets up an entire CI/CD pipeline.
However, this lab did not work either. This lab failed in the “Deploy Stage” under the “Jobs / Deploy” section. At the bottom of the logs is this section:
Creating app nodejs-cloudant-20190718223239271... Mapping routes... Binding services... Unexpected Response Response code: 409 CC code: 60016 CC error code: CF-AsyncServiceInstanceOperationInProgress Description: An operation for service instance sample-nodejs-cloudant-cloudantNoSQLDB is in progress. FAILED Finished: FAILED
HTTP Error 409 Conflict means “Conflict response status code indicates a request conflict with the current state of the server. Conflicts are most likely to occur in response to a PUT request.”
I then clicked on the “Redeploy” button. This passed. I don’t know why. Perhaps the Cloudant NoSQL database took too long to configure.
This lab did not go into making changes to GitHub and redeploying. This is a lab that I plan to learn a lot more from.
I went back to lab #1 and redeployed the Cloud Foundry Go application. I then used Google Cloud Shell and Let’s Encrypt to create an SSL certificate so that I could:
- Create a custom domain name:
go-test2.ibm.jhanley.dev. I use Google Cloud DNS for my DNS services.
- Create an SSL certificate for the wildcard domain
I plan to write a separate article on creating the SSL certificate. I have a very simple method that uses Google Cloud Shell to create SSL certificates for any domain that I control.
IBM Cloud Essentials course Lab #3 – use the IBM Cloud CLI to manage an app
The video shows the
bx command line tool. In testing the same commands work with the
ibmcloud command line tool. For now I am assuming that the
bx tool is deprecated to the
- ibmcloud login
- ibmcloud app list
- ibmcloud app show <app-name>
- ibmcloud app push
ibmcloud app push nodejs-jh-0718719 -c "node app.js" -m 128M --no-manifest --no-start
-c "node app.js"is the command to start the application.
-m 128Mallocates 128M memory to the application.
--no-manifesttells the CLI to ignore the manifest file in the current directory, which allows you to find the service that was just created to the app.
--no-starttells IBM Cloud not to automatically start the applications after upload.
- ibmcloud app start <app-name>
- ibmcloud app stop <app-name>
- ibmcloud app delete <app-name>
- ibmcloud app logs <app-name>
- ibmcloud services
- This command printed an error:
'services' is not a registered command. See 'ibmcloud help'.
- The command
ibmcloud service listseems to be the correct command.
- This command printed an error:
- ibmcloud service create <name-of-service> <service-plan> <service-instance-name>
service create cloudantNoSQLDB Lite myCloudantDB
- ibmcloud service delete
- ibmcloud service bind
ibmcloud service bind nodejs-jh-0718719 myCloudantDB.
- ibmcloud service offerings
IBM Cloud Essentials course – Final exam
I completed the final exam for this course. The exam is easy, but pay attention to all the IBM specific product and service details.
After you complete the exam with an 80% score, you receive two items. A badge and a certificate. I completed the exam with only one wrong answer for a score of 93%.
How much do you know after completing the IBM Cloud Essentials course? Not much. The only service that I really worked with was Cloud Foundry and only at a high level. I don’t understand the details. I can deploy a service in Node.js, Go and PHP, create a custom domain name and add an SSL certificate. I can also work with a dozen or so CLI commands. This is really basic stuff, but IBM Cloud is no longer an unknown to me. I will look forward to learning about IAM, security, networking and then finally start working with IBM Kubernetes.
Day #3 – July 19, 2019
IBM Container & Kubernetes Essentials with IBM Cloud course
Install required software
- Install the CLI – already completed. Link to the information page: link.
- Install the IBM Cloud Kubernetes Service plug-in
- ibmcloud plugin install container-service -r Bluemix
- ibmcloud plugin list
- Install the IBM Cloud Container Registry plug-in
- ibmcloud plugin install container-registry -r Bluemix
- ibmcloud plugin list
- Install the Kubernetes CLI (kubectl) – already installed, but I might have a problem here. I have two different versions installed on my system. One from Docker and the other from Google Cloud. I might need to set up custom paths for IBM Cloud.
- I installed the latest version of kubectl from here and put into a custom location.
Provision a cluster
IBM has a “Free cluster with 1 worker node to explore the capabilities.” link. This does require a credit card on file. This is a great deal for learning Kubernetes. In my case, I know Kubernetes very well but only on Google Cloud. I want to know Kubernetes on all the cloud platforms.
On the IBM Cloud Console, Kubernetes section for this cluster is the message:
- Expires in a month:
- Be sure to back up your data, your cluster will be deleted in a month. To access the full capabilities of the service, try out a standard cluster.
The IBM Kubernetes version deployed is
1.13.8_1529. The worker nodes are at
My Google GKE is
1.13.7-gke.8. IBM is just a little bit newer than Google. It looks like the worker nodes are also
Note: the setup of IBM Kubernetes appears to take a lot longer than Google. Later I will benchmark this.
IBM Kubernetes Setup:
- Download the kubeconfig files for the cluster:
- ibmcloud ks cluster-config –cluster mycluster
- Set the KUBECONFIG environment variable.
- SET KUBECONFIG=C:\Users\ibm\.bluemix\plugins\container-service\clusters\mycluster\kube-config-hou02-mycluster.yml
Test IBM Kubernetes Configuration:
kubectl get nodes NAME STATUS ROLES AGE VERSION 10.76.216.113 Ready <none> 46m v1.13.7+IKS
IBM recommends creating a registry while waiting for the cluster: link.
- Choose a name for your first namespace and create that namespace. Use this namespace for the rest of the Quick Start.
- ibmcloud cr namespace-add development
- Log your local Docker daemon into the IBM Cloud Container Registry.
- ibmcloud cr login
- Pull a test image from Docker Hub.
- docker pull hello-world
- Choose a repository and tag by which you can identify the image. Use the same repository and tag for the rest of this Quick Start.
- docker tag hello-world us.icr.io/development/hello-world:latest
- Push the image.
- docker push us.icr.io/development/hello-world:latest
- Verify that your image is in your private registry.
- ibmcloud cr image-list
The output from
ibmcloud cr image-list:
REPOSITORY TAG DIGEST NAMESPACE CREATED SIZE SECURITY STATUS us.icr.io/development/hello-world latest 92c7f9c92844 development 6 months ago 977 B Unsupported OS OK
Kubernetes Resource Model
- Config maps: holds configuration data for pods to consume
- Daemon sets: ensures that each node in the cluster runs this pod
- Deployments: defines a desired state of a deployment object
- Events: provides life cycle events on pods and other deployment objects
- Endpoints: allows an inbound connections to reach the cluster services
- Ingress: a collection of rules that allows inbound connections to reach the cluster services
- Jobs: creates one or more pods and when they complete successfully, the job is marked as completed
- Node: a worker machine in Kubernetes
- Namespaces: multiple virtual clusters backed by the same physical cluster
- Pods: the smallest deployable units of computing that can be created and managed in Kubernetes
- Persistent volumes: provides an API for users and administrators to abstract details about how storage is provided from how it is consumed
- Replica sets: ensures that a specified number of pod replicas are running at any given time
- Secrets: holds sensitive information, such as passwords, OAuth tokens, and SSH keys
- Service accounts: provides an identity for processes that run in a pod
- Services: an abstraction that defines a logical set of pods and a policy by which to access them, sometimes called a microservice
- Stateful sets: the workload API object that manages stateful applications
- kubectl (create|get|apply|delete) -f myResource.yaml
Kubernetes app deployment workflow
- The user deploys a new app by using the kubectl CLI. Kubectl sends the request to the API server.
- The API server receives the request and stores it in the data store (etcd). After the request is written to the data store, the API server is done with the request.
- Watchers detect the resource changes and send notifications to the Controller to act on those changes.
- The Controller detects the new app and creates new pods to match the desired number of instances. Any changes to the stored model will be used to create or delete pods.
- The Scheduler assigns new pods to a node based on specific criteria. The Scheduler decides on whether to run pods on specific nodes in the cluster. The Scheduler modifies the model with the node information.
- A Kubelet on a node detects a pod with an assignment to itself and deploys the requested containers through the container runtime, for example, Docker. Each node watches the storage to see what pods it is assigned to run. The node takes necessary actions on the resources assigned to it such as to create or delete pods.
- Kubeproxy manages network traffic for the pods, including service discovery and load balancing. Kubeproxy is responsible for communication between pods that want to interact.
Lab #1: Set up and deploy your first app
GitHub repository associated with this course. Go to Lab 1.
Summary of the commands used in this lab (plus a few extras that I should memorize):
Working Container Images:
- ibmcloud login
- ibmcloud cr login
- ibmcloud cr namespace-add <my_namespace>
- ibmcloud cr namespace-list
- docker build –tag registry.ng.bluemix.net/<my_namespace>/hello-world .
- This command is wrong and causes the deployed pod to fail. Use this command instead:
- docker build –tag us.icr.io/<my_namespace>/hello-world .
- docker images
- docker push registry.ng.bluemix.net/<namespace>/hello-world
- This command is wrong and causes the deployed pod to fail. Use this command instead:
- docker push us.icr.io/<my_namespace>/hello-world
- ibmcloud cr image-list
- ibmcloud plugin update –all
Working with Kubernetes Clusters:
- ibmcloud cs clusters
- ibmcloud cs workers <yourclustername>
- ibmcloud cs cluster-config <cluster_name_or_ID>
- export KUBECONFIG=/Users/<user_name>/.bluemix/plugins/container-service/clusters/pr_firm_cluster/kube-config-prod-par02-pr_firm_cluster.yml
- ibmcloud cs cluster-service-bind mycluster default tone – tone is the name of the IBM Watson service that I deployed in Lab 3.
Deploying to Kubernetes:
- kubectl run hello-world –image=us.icr.io/<namespace>/hello-world
- kubectl get pods
- kubectl scale –replicas=1 deployment hello-world
- kubectl expose deployment/hello-world –type=”NodePort” –port=8080
- ibmcloud cs workers <name-of-cluster>
- kubectl get secrets
- kubectl exec -it <node-name> — sh
- apk add curl – install additional programs connected to the container.
After deploying the Hello World example and using the Public IP address returned by
ibmcloud cs workers and the NodePort returned by
kubectl describe service hello-world :
curl -i http://188.8.131.52:31677/ HTTP/1.1 200 OK X-Powered-By: Express Content-Type: text/html; charset=utf-8 Content-Length: 98 ETag: W/"62-RCI85xMNtsGe2NuZrFaH9MjImDQ" Date: Fri, 19 Jul 2019 22:43:28 GMT Connection: keep-alive Hello IBM Cloud world from hello-world-67f69cf97c-pblq6! Your app is up and running in a cluster!
Normally, I would not use NodePort to access a deployment. However, IBM Cloud does not allow you to use a Load Balancer for a free Kubernetes cluster. Once I am comfortable in IBM Cloud, I will deploy a normal pay-for-use cluster.
For comparison, I will deploy the same Hello World example in Google Cloud on my Kubernetes cluster.
- gcloud container images list
- gcloud builds submit –tag gcr.io/development/ibm-hello-world .
- kubectl run -bm-hello-world –image=gcr.io/development/ibm-hello-world
- kubectl expose deployment ibm-hello-world –type=”NodePort” –port=8080
- kubectl exec -it <node-name> — sh
Note: I keep ignoring this error, time to start using the correct command options:
kubectl run –generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run –generator=run-pod/v1 or kubectl create instead.
What does the Kubernetes scheduler do?
What is the purpose of Kubernetes availability checks?
Day #4 – July 20, 2019
Getting started with Microservices with Istio and IBM Cloud Kubernetes Service course
I spent the who day on this course. Very good technical introduction to Istio. There were no lab assignments, just a lot of reading and test-taking. I completed the course and took the final exam.
Day #5 – July 21, 2019
Apply end to end security to a cloud application course
This course is very interesting. I did not make any notes during this course, but I recommend this one.
Day #6– July 26, 2019
PHP Web application on a LAMP Stack course
I did not make any notes during this course. I did purchase a domain name (jhanley.us) in IBM Cloud to practice setting up a custom domain name in IBM Cloud.