How software development has changed in my life

I didn’t notice myself getting older; it snuck up on me in many ways. Similar to watching children grow up, it’s a slow and subtle process.

However, unlike observing children grow, my return to light development work was quite shocking. Like many others, I started with BASIC on MS DOS, then moved on to Perl, briefly entertained the idea of becoming a C++ and Java developer (a quick glance at my profile will reveal how well that worked out for me), and eventually settled into the gentle scripting of a sysadmin. But throughout my journey, I did acquire one trait: I became lazy.

Trigger Warning for Developers: Prepare for Criminal Inefficiency that may cause an aneurysm.

In the past, when I used to develop, I would spend time setting up my Very Special* brand laptop with the necessary Perl modules. I would build virtual machines to replicate production environments and data services. And then, due to several misplaced semicolons, I would find myself mashing the save button 50 times an hour. When started using containers, I quickly retooled my workflows to be more container-based. It was great to have every module and customization be immutable and packaged. But now, every time I mashed that save button, I had to go through the following steps:

  1. Check in my code to github.
  2. Download the code on my docker host (don’t ask me why).
  3. Build and upload the image to dockerhub.
  4. Update my deployment to incorporate the new image (in a testing environment, of course!).
  5. Only to realize that I missed the Python equivalent of a semi-colon (which, I suppose, is a space).

The above process was maddening. However, I learned two crucial things when I attended a developer user group hosted by DevZero:

  1. VS Code has an SSH plugin
  2. There are tools available for Kubernetes service insertion.

Remote Development with VS Code

Remote Development with VS Code became a game-changer for me. I had a Linux host with all the necessary tools (kubectl, pxctl, etc.) installed and ready. I had been using this host for Kubernetes administration, but when all you have is VI (which, I must add, would make my father roll over in his grave, by which I mean his nice rambler in the country, as I type this), any complex change can be daunting.

For more information on using VS Code with SSH, refer to: https://code.visualstudio.com/docs/remote/ssh. However, after installing the plugin, you can follow these steps by pressing F1:

  • Remote-SSH: Add New SSH host
  • Remote-SSH: Connect to SSH host

Once the connection is complete, you will be able to navigate your remote server from the file browser, use git remotely, and use the remote terminal.

Of course, since many programs require a web browser for testing, remote-ssh also facilitates port tunneling through the SSH connection (similar to the “-L” option in SSH for experienced users). Whenever a program sets up a new port on my remote machine, a prompt appears, enabling me to forward the port and access it from my local laptop.

This only addresses the initial aspect of my problem. The subsequent issue is that I have a tendency to excessively press the save button while attempting to achieve proper spacing in Python (or nowadays, when I ask ChatGPT to write a Python script for me). Additionally, the program I was working on required a connection to MongoDB, which was running in my Kubernetes cluster. I could run Mongo locally, but it wouldn’t have a copy of my production data.

Telepresence – and other tools like it

Once again, I am fairly sure DevZero told me about this tool (or at least the concept) Telepresence.

Telepresence establishes a connection to a Kubernetes cluster, enabling connections to Kubernetes services and service insertion, which permits other Kubernetes objects to interact with my local program. This significantly simplifies the process of debugging.

kubectl config use-context MyStagingCluster
telepresence helm install
telepresence connect

And my Flask app has tested a connection to MongoDB successfully! To summarize:

  • I did the above from my laptop (which ONLY has VSCode installed).
  • I was connected to a Linux server in my house with all of the development tools I used
  • My Linux server ran the code and was connected to an Azure AKS staging cluster that was running a copy of my production application.
  • I then connected to my Flask application from my web browser on my laptop, which was connected to the Linux server with a dynamic SSH tunnel, which then connected to the MongoDB instance running in Azure.

Working with multiple clusters

So for a while, I have had a very backward way of accessing multiple clusters: I would set the kubeconfig environment variable, or change the default file. If I had bothered to learn the first thing about contexts, I could have avoided the confusion of keeping track of multiple files.

When a cluster is created, we often get a basic config file to access the cluster. I had often looked at these as a black box of access. Here is an example below from my rancher cluster:

apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: REDACTED
    server: https://rke1:6443
  name: default
contexts:
- context:
    cluster: default
    user: default
  name: default
current-context: default
kind: Config
preferences: {}
users:
- name: default
  user:
    client-certificate-data: REDACTED
    client-key-data: REDACTED

Thanks to the official documentation (RTFM folks) I think it has finally clicked. We have lists of 3 different object types in the above config:
– Cluster: the connection to the cluster (contains a CA and endpoint)
– User: Identified with the client cert data and key data
– Context: Ties the above together (also namespaces if we want)

Contexts allow me to have multiple configurations and switch between them using the kubectl config use-context command. My goal is to have a connection to both my openshift cluster, and my rancher cluster. So I combined (and renamed some elements) the configuration:

apiVersion: v1
clusters:
- cluster:
    insecure-skip-tls-verify: true
    server: https://api.oc1.lab.local:6443
  name: api-oc1-lab-local:6443
- cluster:
    certificate-authority-data: REDACTED
    server: https://rke1:6443
  name: rancher
contexts:
- context:
    cluster: api-oc1-lab-local:6443
    namespace: default
    user: kube:admin/api-oc1-lab-local:6443
  name: default/api-oc1-lab-local:6443/kube:admin
- context:
    cluster: rancher
    user: rancherdefault
  name: rancher
current-context: rancher
kind: Config
preferences: {}
users:
- name: kube:admin/api-oc1-lab-local:6443
  user:
    token: REDACTED
- name: rancherdefault
  user:
    client-certificate-data: REDACTED
    client-key-data: REDACTED

If we understand a little YAML, we can easily combine the files. Now it is simple to switch between my clusters:

kubectl config get-contexts
CURRENT   NAME                                        CLUSTER                  AUTHINFO                            NAMESPACE
          default/api-oc1-lab-local:6443/kube:admin   api-oc1-lab-local:6443   kube:admin/api-oc1-lab-local:6443   default
*         rancher                                     rancher                  rancherdefault
kubectl config use-context default/api-oc1-lab-local:6443/kube:admin
Switched to context "default/api-oc1-lab-local:6443/kube:admin".