I have been getting more familiar with Kubernetes in the past few months and have uncovered some interesting capabilities that I had no idea existed when I started, which have come in handy in helping me solve some interesting and unique problems. I’m sure there are many more tricks I haven’t found, so please feel free to let me know of other tricks you may know of.
Semi related; if you haven’t already checked it out, I wrote a post awhile ago about some of the useful kubectl tricks I have discovered. The CLI has improved since then so I’m sure there are more and better tricks now but it is still a good starting point for new users or folks that are just looking for more ideas of how to use kubectl. Again, let me know of any other useful tricks and I will add them.
The Kubernetes community has somewhat of a love hate relationship with the documentation, although that relationship has been getting much better over time and continues to improve. Almost all of the stuff I have discovered is scattered around the documentation, the main issue is that it a little difficult to find unless you know what you’re looking for. There is so much information packed into these docs and so many features that are tucked away that aren’t obvious to newcomers. The docs have been getting better and better but there are still a few gaps in examples and general use cases that are missing. Often the “why” of using various features is still sometimes lacking.
Another point I’d like to quickly cover is the API reference documentation. When you are looking for some feature or functionality and the main documentation site fails, this is the place to go look as it has everything that is available in Kubernetes. Unfortunately the API reference is also currently a challenge to use and is not user friendly (especially for newcomers), so if you do end up looking through the API you will have to spend some time to get familiar with things, but it is definitely worth reading through to learn about capabilities you might not otherwise find.
For now, the best advice I have for working with the docs and testing functionality is trial and error. Katacoda is an amazing resource for playing around with Kubernetes functionality, so definitely check that out if you haven’t yet.
Leader election built on Kubernetes is really neat because it buys you a quick and dirty way to do some pretty complicated tasks. Usually, implementing leader election requires extra software like ZooKeeper, etcd, Consul or some other distributed key/value store for keeping track of consensus, but it is built into Kubernetes, so you don’t have much extra work to get it working.
Leader election piggy backs off the same etcd Kubernetes uses as well as Kubernetes annotations, which give users a robust way to do distributed tasks without having to recreate the wheel for doing complicated leader elections.
Basically, you can deploy the leader-elector as a sidecar with any app you deploy. Then, any container in the pod that’s interested in who is the master can can check by visiting the http endpoint (localhost:4044 by default) and they will get back some json with the current leader.
This is a beta feature currently (as of 1.13) so is enabled now by default. This one is interesting because it allows you to share a PID between containers. Unfortunately the docs don’t really tell you why this feature is useful.
Basically, if you add
shareProcessNamespace: true to your pod spec, you turn on the ability to share a PID across containers. This allows you to do things like changing a configuration in one container, sending a SIGHUP, and then reloading that configuration in another container.
For example, running a sidecars that controls configuration files or for reaping orphaned zombie processes.
apiVersion: v1 kind: Pod metadata: name: nginx spec: shareProcessNamespace: true containers: - name: nginx image: nginx - name: shell image: busybox securityContext: capabilities: add: - SYS_PTRACE stdin: true tty: true
Custom termination messages can be useful when debugging tricky situations.
You can actually customize pod terminations by using the
terminationMessagePolicy which can control how terminations get outputted. For example, by using
FallbackToLogsOnError you can tell Kubernetes to use container log output if the termination message is empty and the container exited with error.
Likewise, you can specify the
terminationMessagePath spec to customize the path to a log file for specifying successes and failures when a pod terminates.
apiVersion: v1 kind: Pod metadata: name: msg-path-demo spec: containers: - name: msg-path-demo-container image: debian terminationMessagePath: "/tmp/my-log"
Lifecycle hooks are really useful for doing things either after a container has started (such as joining a cluster) or for running commands/code for cleanup when a container is stopped (such as leaving a cluster).
Below is a straight forward example taken from the docs that writes a message after a pod starts and sends a quit signal to nginx when the pod is destroyed.
apiVersion: v1 kind: Pod metadata: name: lifecycle-demo spec: containers: - name: lifecycle-demo-container image: nginx lifecycle: postStart: exec: command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"] preStop: exec: command: ["/usr/sbin/nginx","-s","quit"]
This one is probably more known, but I still think it is useful enough to add to the list. The downward API basically allows you to grab all sorts of useful metadata information about containers, including host names and IP addresses. The downward API can also be used to retrieve information about resources for pods.
The simplest example to show off the downward API is to use it to configure a pod to use the hostname of the node as an environment variable.
apiVersion: v1 kind: Pod spec: containers: - name: test-container image: k8s.gcr.io/busybox command: [ "sh", "-c"] args: - while true; do echo -en '\n'; printenv MY_NODE_NAME sleep 10; done; env: - name: MY_NODE_NAME valueFrom: fieldRef: fieldPath: spec.nodeName
This is a useful trick when you want to add a layer on top of a Docker container but don’t necessarily want to build either a custom image or update an existing image. By injecting the script as a configmap directly into the container you can augment a Docker image to do basically any extra work you need it to do.
The only caveat is that in Kubernetes, configmaps are by default not set to be executable.
In order to make your script work inside of Kubernetes you will simply need to add
defaultMode: 0744 to your configmap volume spec. Then simply mount the config as volume like you normally would and then you should be able to run you script as a normal command.
- name: wrapper
- name: wrapper
This one is also pretty well known but often forgotten. Using commands a health checks is a nice way to check that things are working. For example, if you are doing complicated DNS things and want to check if DNS has updated you can use dig. Or if your app updates a file when it becomes healthy, you can run a command to check for this.
Host aliases in Kubernetes offer a simple way to easily update the /etc/hosts file of a container. This can be useful for example if a localhost name needs to be mapped to some DNS name that isn’t handled by the DNS server.
apiVersion: v1 kind: Pod metadata: name: hostaliases-pod spec: restartPolicy: Never hostAliases: - ip: "127.0.0.1" hostnames: - "foo.local" - "bar.local" containers: - name: cat-hosts image: busybox command: - cat args: - "/etc/hosts"
As mentioned, these are just a few gems that I have uncovered, I’m sure there are a lot of other neat tricks out there. As I get more experience using Kubernetes I will be sure to update this list. Please let me know if there are things that should be on here that I missed or don’t know about.