Kubernetes: using the Downward API to access pod/container metadata

The Kubernetes Downward API allows a pod to get access to metadata about itself and the cluster without creating a tight coupling to the Kubernetes API.  For example, information such as pod name, labels, annotations, IP address, node, and cpu/memory limits can be made available inside the pod. In this article, I’ll show how to Kubernetes: using the Downward API to access pod/container metadata

GCP: pulling an image from the Container Registry of another project

In a previous article I discussed the advantages to keeping container images in the private Google Container Registry of a project.  And if you have a GKE cluster in the exact same project, then image pulls happen seamlessly without any additional configuration required. However, if the GKE cluster is in a different project than the GCP: pulling an image from the Container Registry of another project

GCP: pushing GKE images into gcr.io to avoid pull rate limits

Docker hub now enforces pull rate limits (since November 2020).  And unfortunately, this limit is often reached at critical moments such as upgrades or infrastructure events when bulk pod recreation is happening. One way to avoid this problem is to place your images into an alternate image registry.  This could mean a lot of work GCP: pushing GKE images into gcr.io to avoid pull rate limits

Kubernetes: detecting the installed version of nginx ingress

If you need to determine the version of the nginx ingress controller deployed, then you can invoke the ingress controller binary with the ‘–version’ flag. But this binary is located in the ingress-nginx-controller pod, so do a ‘kubectl exec’ like below. # show all running nginx ingress pods kubectl get pods -n $ingress_ns -l app.kubernetes.io/name=ingress-nginx Kubernetes: detecting the installed version of nginx ingress

Kubernetes: testing pod communication directly from istio sidecar proxy

Once you introduce an istio sidecar proxy into your deployment, it becomes another point at which you might need to troubleshoot network connectivity to the primary container. Assuming you have deployed a pod with an app label “helloworld” in the default namespace listening on port 5000, you can use a command like the following to Kubernetes: testing pod communication directly from istio sidecar proxy

Kubernetes: istio Gateway in a different namespace than VirtualService

If your istio ingress Gateway is in a different namespace than your VirtualService, then you need to make sure you prefix the gateway reference with that namespace. For example, if your istio ingress Gateway is in the ‘default’ namespace, yet your Deployment, Service, and VirtualService are in the namespace ‘helloworld’. apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: Kubernetes: istio Gateway in a different namespace than VirtualService

Docker: determining container responsible for largest overlay directories

Whether you are running a docker daemon on a development host or a GKE worker node using Docker as the container engine, it is important to understand the amount of disk storage being utilized by the containers. If you navigate into the ‘/var/lib/docker/overlay2’ directory, you will  see cryptic hashed ids representing the containers layers instead Docker: determining container responsible for largest overlay directories

Ansible: pulling values from nested dictionaries when path might not exist

It is typically straightforward to resolve Ansible errors where a simple variable used within an action is not defined.  However, when dealing with nested dictionary variables in your Ansible tasks, it can become more complex because not only can the leaf be missing, but also any of the parent container paths. For example, the nested Ansible: pulling values from nested dictionaries when path might not exist

Ansible: action only executed if tag set, avoiding ‘all’ behavior

Even if the actions in your playbook/role are tagged to separate their logic, this ability to selectively execute will not operate properly when called without any tags because then you will fallback to the special ‘all‘ behavior. Consider a playbook with the following actions. tasks: – debug: msg=”when tag ‘run'” tags: run – debug: msg=”when Ansible: action only executed if tag set, avoiding ‘all’ behavior

Ansible: creating SAN certificates with a custom root CA

Ansible has support for generating self-signed certificates as well as certificates using a custom root CA (certificate authority).  This is possible using the community.crypto collection. I’ve put this into a role named ansible-role-cert-with-ca available on github, and it can be used from a playbook like below: vars: # custom CA, leaving undefined will create self-signed Ansible: creating SAN certificates with a custom root CA

Ubuntu: loading a key into ssh-agent at login with a user-level systemd service

By default, if an SSH key file is dropped into your personal ‘~/.ssh’ directory that matches a set of standard names, then it will automatically be used as an identity when logging into a remote site (id_rsa, id_dsa, id_ecsda, id_ed25519, or identity). For example, this makes it simple to comply with Github’s requirement to use Ubuntu: loading a key into ssh-agent at login with a user-level systemd service

Bash: performing multiple substitutions with a single sed invocation

Instead of stringing together sed multiple times in a pipeline, it is also possible to make multiple substitutions with a single invocation of sed. Consider the following example which replaces the word ‘hello’ as well as ‘quick’ in the paragraph: $ sed “s/hello/goodbye/g; s/quick/slow/g” <<EOF hello, world! hello, universe! the quick brown fox EOF goodbye, Bash: performing multiple substitutions with a single sed invocation

Ansible: generating content for all template files using with_fileglob

There are scenarios where instead of being explicit about each file name when generating templates from a role, you may want to take all the suffixed files in the ‘templates’ directory and dump their generated content into a destination directory. As a quick example, if you are in a role and want every script in Ansible: generating content for all template files using with_fileglob

Kubernetes: Updating an existing ConfigMap using kubectl replace

Creating a ConfigMap using ‘kubectl create configmap’ is a straightforward operation.   However, there is not a corresponding ‘kubectl apply’ that can easily update that ConfigMap. As an example, here are the commands for the creation of a simple ConfigMap using a file named “ConfigMap-test1.yaml“. $ cat ConfigMap-test1.yaml test1: foo: bar # create and then show Kubernetes: Updating an existing ConfigMap using kubectl replace

Python: Setting the preferred Python version on Bionic 18 and Focal 20

Even though Python2 reached EOL in January 2020, there are still lagging applications and modules that force its continued use on certain systems.  If that is your situation, you need the ability to force preference to Python3 unless a program explicitly invokes Python2. If you are using Ubuntu Focal 20, then you have an easy Python: Setting the preferred Python version on Bionic 18 and Focal 20

Ubuntu: using ldapsearch to query against a secure Windows Domain Controller

Using ldapsearch to query against the insecure port of a Windows Domain Controller is straightforward.  However, it can be challenging to get all the pieces in place for a production environment where the secure port must be used and the root CA certificate is typically not from a public CA. Assuming the standard insecure port Ubuntu: using ldapsearch to query against a secure Windows Domain Controller

Bash: using multiple values from an input pipeline to construct and execute a command

If you have multiple values coming through the Bash input pipeline, it can be difficult to process these into a complex, formatted set of arguments unless you use intermediate temporary files. But one way to neatly put together a complex set of arguments from an input pipeline with multiple values is to use awk printf Bash: using multiple values from an input pipeline to construct and execute a command

Python: exploring the use of startswith against a list: tuple, regex, list comprehension, lambda

As with any programming language, Python has a multitude of ways to accomplish the same task.  In this article, I will explore the idea of taking a string and checking if it ‘startswith’ any of the strings from a predetermined list. As context for the example code, RFC1918 sets out several IPv4 ranges that can Python: exploring the use of startswith against a list: tuple, regex, list comprehension, lambda

Ubuntu: Extending capacity of an LVM volume group using an existing or new disk

It is common for a virtualized Guest OS base image to have a generic storage capacity.  This capacity can easily be exceeded by production scenarios, performance testing, logging, or even the general cruft of running a machine 24×7. If your VM is using Logical Volume Management (LVM), adding space can be done by following a Ubuntu: Extending capacity of an LVM volume group using an existing or new disk

Terraform: Using non-authoritative resources to avoid IAM membership dependency web

One of the most challenging aspects of using Terraform is dealing with external changes and sprawl of dependent objects that may originate outside your control.  Terraform wants to be a system of record and have everything documented in its state as resource/data, however keeping your state in sync when other groups may be doing automation Terraform: Using non-authoritative resources to avoid IAM membership dependency web

GCP: Analyzing members of IAM role using gcloud filtering and jq

Although  the GCP console provides a nice interface for displaying which user/service account is in which IAM security role (IAM & Admin > IAM), it can be difficult to analyze using gcloud get-iam-policy because of the inner array of ‘members’ returned. However, if you use the flattening ability of gcloud, it becomes much easier to GCP: Analyzing members of IAM role using gcloud filtering and jq

KVM: creating and reverting libvirt external snapshots

Update July 2021: I have seen errors with external snapshots of volumes on versions of QEMU/KVM/libvirt from Ubuntu 20 Focal.  Adding note on using internal snapshot on volume backed by qcow2.   Internal snapshots created on QEMU copy-on-write (qcow2) disks are the most commonly used snapshot when using libvirt.  It is easy to see why; KVM: creating and reverting libvirt external snapshots

Bash: grep with LookBehind and LookAhead to isolate desired text

grep has support for Perl compatible regular expressions (PCRE) by using the -P flag, and this provides a number of useful features.  In this article, I’ll show how LookBehind and LookAhead regular expression support can provide enhanced parsing abilities to your shell scripts. For example, consider an xml file “test.xml” with the contents: <root> <path>/my/data</path> Bash: grep with LookBehind and LookAhead to isolate desired text

Ansible: regex capture groups with lineinfile to preserve yaml indentation

One of the features of the ‘lineinfile‘ regexp parameter is the ability to use regular expression capture groups in the line output.  That allows you to extract values on a found line when constructing the output line. Specifically, that can mean pulling information such as hostname/port, file path, or preserving the yaml indentation of an Ansible: regex capture groups with lineinfile to preserve yaml indentation

Ansible: lineinfile with regex to robustly populate key/value pairs in config file

If your Ansible automation includes modifying an existing configuration file (versus managing your own fully templatized version of the config), then you will need to account for variations in that existing file when using ‘lineinfile‘ for key/value pairs. A naive lineinfile replacement will not find commented-out keys and might not even find valid keys that Ansible: lineinfile with regex to robustly populate key/value pairs in config file