You are working with multiple clouds. But, you keep changing context and then accidentally applying something. Ooops. If only this could be simpler.

Drop these two bits in your .bashrc. Now you can simply say ‘context foo’ and be in that context with a little bit of colour in your prompt to remind you.

Side node:  the \[$B1\], the \[ is important otherwise bash doesn’t know how ‘wide’ that is and your command-history will go funny for long lines.

context() {
  if [ $# -eq 1 ]
      /usr/bin/kubectl config use-context "$1" 2>/dev/null
  B1="$(tput bold)$(tput setf 2)"
  B0="$(tput sgr0)"
  KUBERNETES_CONTEXT="[$(/usr/bin/kubectl config current-context)]"
  PS1='\u@\h\[$B1\]$KUBERNETES_CONTEXT\[$B0\]:\W\$ '

  # Assumes you have source <(kubectl completion bash) above
  complete -F __kubectl_config_get_contexts context


Github has this feature on a profile page (yours, anyones) which allows you to see their ‘profile’ with respect to reviewing changes, creating issues, commiting things, and sending pull requests.

This is for the open-source public facing repo, so its an indication of how you add value to the open source ecosystem. Here’s mine. What’s yours?

It suggests that I spend more time creating code or sending improvements to other projects, and a bit of time reporting issues in other people’s projects, but no time reviewing code.

I’ve made 378 ‘contributions’ in the trailing year, so about 1 per day. See for yourself.

Years ago there was a really great TV show. Kirk, Spock, McCoy, Scotty. You know the one. Later it was remade with some characters long forgotten. Except 1. Picard. His trademark ‘make it so’ was the hallmark of a great leader. With this one phrase he could turn his attention elsewhere, knowing that it would happen.

This is also the hallmark of a new world order in computing. Declarative vs Imperative. In a ‘declarative’ world I document the desired state, and it is the job of the system to ‘make it so’. In a declarative world you don’t need to worry about ‘how’, and you don’t need to worry about things later breaking… If they change, the system puts it back. Its a control system, like that PID controller you learned years ago.

In an imperative world, you instruct each step. Install that software, configure that port, etc. You are the controller. If something later breaks, you notice and change it.

OK, we are clear on the concept. Now does it work in practice? Mostly. Where it breaks are things that cannot be updated. Let’s take an example. Let’s say I have a horizontally scalable app. Its beautiful, shards of all shapes and sizes are hanging out. Now, in order to maintain consistency, I need a minimum number online. As I scale it up, that number would change, right? It might be 2/3 of the total online number, something like that.

Enter the humble PodDisruptionBudget. Lets say I use this feature, in conjunction with setting the # of replicas in my StatefulSet.

apiVersion: policy/v1beta1
kind: PodDisruptionBudget
    app: COOL
  name: MYAPP
  minAvailable: 2
      app: COOL

What is one to do here when I follow the law of the declarative world. I set the config the way I want, commit to git and… “The PodDisruptionBudget “master” is invalid: spec: Forbidden: updates to poddisruptionbudget spec are forbidden.” O no. I’m now stuck.

Hmm. I cannot ‘make it so’?

Early I wrote about my cool new tool dink. It allows you to, without ssh to your Kubernetes nodes, have access to their ‘docker’ for debugging, inspecting, image verifying etc.

Today we were discussing some debuggering of fluent-bit and i thought, why not make it simple to go see the raw logs that would be fed into your log parser? So I updated it.

Now you can run dink and have immediate access to /var/logs/… just like the cloud log parser does. Or dink -n NODE for a specific node’s.

YMMV, void where prohibited.

So I’ve been working of late with some Java programs. They substitute a ~10KB stack trace for an error message. If you have a typo in the config file you have to fish through that stack trace to find what file, what line, and why (and not because the stack trace has it, its just you can guestimate from the method names what it might be reading). Its beyond infuriating.

And now here’s another. ‘Kustomize’. Like all good Kubernetes things it starts with a ‘K’. Makes it hard to use on KDE I can tell you. Cacophony. The jaws that bite, the claws that catch, the ‘k”s that cough. That sort of thing.

I mean, seriously, how am I supposed to infer what line of what file might be wrong. I have to go find the source code to this program and add some printfs?

How is this progress, we let Yacc+Lex go and replaced it with a core dump?

$ <PACKAGE>/overlays/production$ kustomize build .
panic: interface conversion: interface {} is map[string]interface {}, not []interface {}

goroutine 1 [running]:*imageTransformer).updateContainers(0xc00025cf20, 0xc0004e3710, 0x100b88b, 0xa, 0xc0003a6e08, 0x60000c0003a6301)
	/home/don/go/src/ +0x4fc*imageTransformer).findAndReplaceImage(0xc00025cf20, 0xc0004e3710, 0xc000364df0, 0x4)
	/home/don/go/src/ +0x13e*imageTransformer).findContainers(0xc00025cf20, 0xc0004e3650, 0x100e547, 0xe)
	/home/don/go/src/ +0x1f2*imageTransformer).findAndReplaceImage(0xc00025cf20, 0xc0004e3650, 0xc000364d38, 0x8)
	/home/don/go/src/ +0xe1*imageTransformer).findContainers(0xc00025cf20, 0xc0004e35c0, 0x100e547, 0xe)
	/home/don/go/src/ +0x1f2*imageTransformer).findAndReplaceImage(0xc00025cf20, 0xc0004e35c0, 0xc0003652dc, 0x4)
	/home/don/go/src/ +0xe1*imageTransformer).findContainers(0xc00025cf20, 0xc0004e3560, 0x100e547, 0xe)
	/home/don/go/src/ +0x1f2*imageTransformer).findAndReplaceImage(0xc00025cf20, 0xc0004e3560, 0x0, 0x0)
	/home/don/go/src/ +0xe1*imageTransformer).Transform(0xc00025cf20, 0xc0003eca80, 0x0, 0x0)
	/home/don/go/src/ +0xca*multiTransformer).transform(0xc0003ed620, 0xc0003eca80, 0x0, 0xc0003641f0)
	/home/don/go/src/ +0x6f*multiTransformer).Transform(0xc0003ed620, 0xc0003eca80, 0xc0003eca80, 0xc0004e16c0)
	/home/don/go/src/ +0x75*ResAccumulator).Transform(0xc000030ea0, 0x1136fa0, 0xc0003ed620, 0x0, 0xc0001288f0)
	/home/don/go/src/ +0x3e*KustTarget).AccumulateTarget(0xc000030e40, 0xc00030b540, 0xc00000e728, 0x113a680)
	/home/don/go/src/ +0x3b3*KustTarget).accumulateBases(0xc00019fdd0, 0xc00035adc0, 0x30)
	/home/don/go/src/ +0x4b8*KustTarget).AccumulateTarget(0xc00019fdd0, 0xc000202b00, 0xc0002c60f0, 0x42b522)
	/home/don/go/src/ +0x53*KustTarget).MakeCustomizedResMap(0xc00019fdd0, 0xc00030b400, 0xc00000e728, 0x113a680)
	/home/don/go/src/ +0x2f*Options).RunBuild(0xc00035a100, 0x1136dc0, 0xc00000e018, 0x1157a60, 0x19df818, 0xc00000e728, 0x113a680, 0x19df818, 0x0, 0x0)
	/home/don/go/src/ +0x108, 0xc000210810, 0x1, 0x1, 0x0, 0x0)
	/home/don/go/src/ +0x136*Command).execute(0xc000139b80, 0xc0002107b0, 0x1, 0x1, 0xc000139b80, 0xc0002107b0)
	/home/don/go/src/ +0x473*Command).ExecuteC(0xc000139900, 0xc0001cc280, 0xc0002a0a00, 0xc0002a0f00)
	/home/don/go/src/ +0x2fd*Command).Execute(0xc000139900, 0xc000139900, 0xc00056bf58)
	/home/don/go/src/ +0x2b
	/home/don/go/src/ +0x151