Type oc login (it’ll tell you where to request the oauth token)
Get a token at https://XYZ.com:31344/oauth/token/request
$ oc login --token=sha256~aaa --server=https://XYZ.com:31609
Logged into "https://XYZ.com:31609" as "IAM#xyz@us.ibm.com" using the token provided.
You have access to 63 projects, the list has been suppressed. You can list all projects with 'oc projects'
Using project "default".
Kubernetes: Pod Topology Spread Constraints
Use topology spread constraints to control how Pods are spread across your cluster among failure-domains such as regions, zones, nodes, and other user-defined topology domains. This can help to achieve high availability as well as efficient resource utilization.
Kubernetes: Inter-pod affinity and anti-affinity Inter-pod affinity and anti-affinity allow you to constrain which nodes your Pods can be scheduled on based on the labels of Pods already running on that node, instead of the node labels.
In OpenShift, the kube-scheduler binds a unit of work (Pod) to a Node. The scheduler reads from a scheduling queue the work, retrieves the current state of the cluster, scores the work based on the scheduling rules (from the policy) and the cluster’s state, and prioritizes binding the Pod to a Node.
These nodes are scheduled based on an instantaneous read of the policy and the environment and a best-estimation placement of the Pod on a Node. With best estimate at the time, these clusters are constantly changing shape and context; there is a need to deschedule and schedule the Pod anew.
Descheduler run on a set interval and re-evaluates the scheduled Pod and Node and Policy, setting an eviction if the Pod should be removed based on the Descheduler Policy.
Pod is removed (unbound).
Thankfully, OpenShift has a Descheduler Operator that more easily facilitates the unbinding of a Pod from a Node based on a cluster-wide configuration of the KubeDeschedulerCustomResource. In a single cluster, there is at most one configured KubeDescheduler named cluster (it has to be fixed), and configures one or more Descheduler Profiles.
Spreads pods evenly among nodes based on topology constraints and duplicate replicates on the same node The profile cannot be used with SoftTopologyAndDuplicates.
SoftTopologyAndDuplicates
Spreads pods with prior with soft constraints The profile cannot be used with TopologyAndDuplicates.
LifecycleAndUtilization
Balances pods based on node resource usage This profile cannot be used with DevPreviewLongLifecycle
EvictPodsWithLocalStorage
Enables pods with local storage to be evicted by the descheduler by all other profiles
EvictPodsWithPVC
Prevents pods with PVCs from being evicted by all other profiles
DevPreviewLongLifecycle
Lifecycle management for pods that are ‘long running’ This profile cannot be used with LifecycleAndUtilization
There must be one or more DeschedulerProfile specified, and there cannot be any duplicates entries. There are two possible mode values – Automatic and Predictive. You have to go the Pod to check the output to see what is Predicted or is Completed.
The DeschedulerOperator excludes the openshift-*, kube-system and hypershift namespaces.
2. Create a Pod that indicates it’s available for eviction using the annotation descheduler.alpha.kubernetes.io/evict: “true” and is updated for the proper node name.
4. Get the Pods in the openshift-kube-descheduler-operator
oc get pods -n openshift-kube-descheduler-operator
NAME READY STATUS RESTARTS AGE
descheduler-f479c5669-5ffxl 1/1 Running 0 2m7s
descheduler-operator-85fc6666cb-5dfr7 1/1 Running 0 27h
5. Check the Logs for the descheduler pod
oc -n openshift-kube-descheduler-operator logs descheduler-f479c5669-5ffxl
I0506 19:59:10.298440 1 pod_lifetime.go:110] "Evicted pod because it exceeded its lifetime" pod="minio-operator/console-7bc65f7dd9-q57lr" maxPodLifeTime=60
I0506 19:59:10.298500 1 evictions.go:158] "Evicted pod in dry run mode" pod="default/demopod1" reason="PodLifeTime"
I0506 19:59:10.298532 1 pod_lifetime.go:110] "Evicted pod because it exceeded its lifetime" pod="default/demopod1" maxPodLifeTime=60
I0506 19:59:10.298598 1 toomanyrestarts.go:90] "Processing node" node="master-0.rdr-rhop-.sslip.io"
I0506 19:59:10.299118 1 toomanyrestarts.go:90] "Processing node" node="master-1.rdr-rhop.sslip.io"
I0506 19:59:10.299575 1 toomanyrestarts.go:90] "Processing node" node="master-2.rdr-rhop.sslip.io"
I0506 19:59:10.300385 1 toomanyrestarts.go:90] "Processing node" node="worker-0.rdr-rhop.sslip.io"
I0506 19:59:10.300701 1 toomanyrestarts.go:90] "Processing node" node="worker-1.rdr-rhop.sslip.io"
I0506 19:59:10.301097 1 descheduler.go:287] "Number of evicted pods" totalEvicted=5
This article shows a simple case for the Descheduler and you can see how it ran a dry run and showed it would evict five pods.
A brief Operator training I gave to my team resulted in these notes. Thanks to many others in the reference section.
An Operator codifies the tasks commonly associated with administrating, operating, and supporting an application. The codified tasks are event-driven responses to changes (create-update-delete-time) in the declared state relative to the actual state of an application, using domain knowledge to reconcile the state and report on the status.
Event (Anomaly) Detection and Response (Remediation)
Scheduling and Tuning
Application Specific Management
Continuous Testing and Chaos Monkey
Helm operators wrap helm charts in a simplistic view of the operation pass-through helm verbs, so one can install, uninstall, destroy, and upgrade using an Operator.
There are four actors in the Operator Pattern.
Initiator – The user who creates the Custom Resource
Operator – The Controller that operates on the Operand
Each Operator operates on an Operand using Managed Resources (Kubernetes and OpenShift) to reconcile states. The states are described in a domain specific language (DSL) encapsulated in a Custom Resource to describe the state of the application:
spec – The User communicates to the Operator the desired state (Operator reads)
status – The Operator communicates back to the User (Operator writes)
While not limited to writing spec and status, if we think spec is initiator specified, and if we think status is operator written, then we limit the chances of creating an unintended reconciliation loop.
The DSL is specified as Custom Resource Definition:
$ oc get crd machinehealthchecks.machine.openshift.io -o=yaml
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
spec:
conversion:
strategy: None
group: machine.openshift.io
names:
kind: MachineHealthCheck
listKind: MachineHealthCheckList
plural: machinehealthchecks
shortNames:
- mhc
- mhcs
singular: machinehealthcheck
scope: Namespaced
name: v1beta1
schema:
openAPIV3Schema:
description: 'MachineHealthCheck'
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation'
type: string
kind:
description: 'Kind is a string value representing the REST resource'
type: string
metadata:
type: object
spec:
description: Specification of machine health check policy
properties:
expectedMachines:
description: total number of machines counted by this machine health
check
minimum: 0
type: integer
unhealthyConditions:
description: UnhealthyConditions contains a list of the conditions.
items:
description: UnhealthyCondition represents a Node.
properties:
status:
minLength: 1
type: string
timeout:
description: Expects an unsigned duration string of decimal
numbers each with optional fraction and a unit suffix, eg
"300ms", "1.5h" or "2h45m". Valid time units are "ns", "us"
(or "µs"), "ms", "s", "m", "h".
pattern: ^([0-9]+(\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$
type: string
type:
minLength: 1
type: string
type: object
minItems: 1
type: array
type: object
For example, these operators manage the applications by orchestrating operations based on changes to the CustomResource (DSL):
As a developer, we’re going to follow a common development pattern:
Implement the Operator Logic (Reconcile the operational state)
Bake Container Image
Create or regenerate Custom Resource Definition (CRD)
Create or regenerate Role-based Access Control (RBAC)
Role
RoleBinding
Apply Operator YAML
Note, we’re not necessarily writing business logic, rather operational logic.
There are some best practices we follow:
Develop one operator per application
One CRD per Controller. Created and Fit for Purpose. Less Contention.
No Cross Dependencies.
Use Kubernetes Primitives when Possible
Be Backwards Compatible
Compartmentalize features via multiple controllers
Scale = one controller
Backup = one controller
Use asynchronous metaphors with the synchronous reconciliation loop
Error, then immediate return, backoff and check later
Use concurrency to split the processing / state
Prune Kubernetes Resources when not used
Apps Run when Operators are stopped
Document what the operator does and how it does it
Install in a single command
We use the Operator SDK – one it’s supported by Red Hat and the CNCF.
operator-sdk: Which one? Ansible and Go
Kubernetes is authored in the Go language. Currently, OpenShift uses Go 1.17 and most operators are implemented in Go. The community has built many go-based operators, we have much more support on StackOverflow and a forum.
Go is ideal for concurrency, strong memory management, everything is baked into the executable deliverable – it’s in memory and ready-to-go. There are lots of alternatives to code NodeJS, Rust, Java, C#, Python. The OpenShift Operators are not necessarily built on the Operator SDK.
Summary
We’ve run through a lot of detail on Operators and learned why we should go with Go operators.
I built a demonstration using GoLang, JSON, bcrypt, http client, http server to model an actual IDP. This is a demonstration only; it really helped me setup/understand what’s happening in the RequestHeader.
This document outlines the flow using the haproxy and Apache Httpd already installed on the Bastion server as part of the installation process and a local Go Test IdP to demonstrate the feature.
The rough flow between OpenShift, the User and the Test IdP is:
For those managing OpenShift clusters, the oc tool manages all the OpenShift resources with handy commands for OpenShift and Kubernetes. The OpenShift Client CLI (oc) project is built on top of kubectl adding built-in features to simplify interactions with an OpenShift cluster.
Much like the kubectl, the oc cli tool provides a feature to Extend the OpenShift CLI with plug-ins. The oc plugins feature is a client-side feature to faciliate interactions with extensions commands; found in the current user’s path. There is an ecosystem of plugins through the community and the Krew Plugin List.
k9s is a terminal based UI to interact with your Kubernetes clusters.
sample-cli-plugin which is a simple example to show how to switch namespaces in k8s. I’m not entirely certain that this works with OpenShift.
These plugins have a wide range of support and code. Some of the plugins are based on python, others are based on go and bash.
oc expands the plugin search path pkg/cli/kubectlwrappers/wrappers.go in plugin.ValidPluginFilenamePrefixes = []string{"oc", "kubectl"} so whole new OpenShift specific plugins are supported. The OpenShift team has also released a number of plugins:
oc-mirror manages OpenShift release, operator catalog, helm charts, and associated container images for mirror registries that support OpenShift environments
oc-compliance facilitates using the OpenShift Compliance operator.
Many of these extensions/plugins are installed using krew; krew is a plugin manager for kubectl. Some users create a directory .kube/plugins and install their plugins in that folder. The plugins folder is then added to the user’s path.
Creating your own Extension
Check to see if any plugins exist:
$ oc plugin list
The following compatible plugins are available:
/Users/user/.kube/plugins/oc-test
If none exist, it’ll prompt you that none are found in the path, and you can install from krew.
To quote the Kubernetes website, “The Operator pattern captures how you can write code to automate a task beyond what Kubernetes itself provides.” The following is an compendium to use while Learning Operators.
The defacto SDK to use is the Operator SDK which provides HELM, Ansible and GO scaffolding to support your implementation of the Operator pattern.
The following are education classes on the OperatorSDK
When Running through the CO0201EN intermediate operators course, I did hit the case where I had to create a ClusterRole and ClusterRoleBinding for the ServiceAccount, here is a snippet that might helper others:
Create OpenShift Plugins – You must have a CLI plug-in file that begins with oc- or kubectl-. You create a file and put it in /usr/local/bin/
Details on running Code Ready Containers on Linux – The key hack I learned awas to ssh -i ~/.crc/machines/crc/id_ecdsa core@<any host in the /etc/hosts>
I ran on VirtualBox Ubuntu 20.04 with Guest Additions Installed
Virtual Box Settings for the Machine – 6 CPU, 18G
System > Processor > Enable PAE/NX and Enable Nested VT-X/AMD-V (which is a must for it to work)
Network > Change Adapter Type to virtio-net and Set Promiscuous Mode to Allow VMS
Install openssh-server so you can login remotely
It will not install without a windowing system, so I have the default windowing environment installed.
Note, I still get a failure on startup complaining about a timeout. I waited about 15 minutes post this, and the command oc get nodes –context admin –cluster crc –kubeconfig .crc/cache/crc_libvirt_4.10.3_amd64/kubeconfig now works.
buildah is an intriguing open source tool to build of Open Container Initiative (OCI) container images using a scripted approach versus a traditional Dockerfile. It’s fascinating and I’ve started to use podman and buildah to build my project’s images.
I picked ubi-micro as my startingn point. Per Red Hat, ubi-microis the smallest possible image excludinng the package manager and all of its dependencies which are normally included in a container image. This approach is an alternative to the current release of the IBM FHIR Server image. The following only documents my first stages with Java testing.
On Fedora, install the prerequisites.
# sudo dnf install buildah -y
Last metadata expiration check: 0:23:36 ago on Thu 02 Sep 2021 10:06:55 AM EDT.
Dependencies resolved.
=====================================================================================================================================================================
Package Architecture Version Repository Size
=====================================================================================================================================================================
Installing:
buildah x86_64 1.21.4-5.fc33 updates 7.9 M
Transaction Summary
=====================================================================================================================================================================
Install 1 Package
Total download size: 7.9 M
Installed size: 29 M
Downloading Packages:
buildah-1.21.4-5.fc33.x86_64.rpm 7.2 MB/s | 7.9 MB 00:01
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
Total 6.2 MB/s | 7.9 MB 00:01
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
Preparing : 1/1
Installing : buildah-1.21.4-5.fc33.x86_64 1/1
Running scriptlet: buildah-1.21.4-5.fc33.x86_64 1/1
Verifying : buildah-1.21.4-5.fc33.x86_64 1/1
Installed:
buildah-1.21.4-5.fc33.x86_64
Complete!