The problem

kubectl has a decent mechanism for querying kubernetes objects by label but sometimes you will need to get pods, services, or anything else by querying their annotation.

Some dudes asked for annotation query support here but it is not planned at the moment:

You cannot query annotations in Kubernetes, and this will not change in the foreseeable future.

To achieve that, you will find on the internet a way to achieve that with jsonpath. Here is an example taken from Fabian Lee’s blog:

# service that has annotation, regardless of value
kubectl get service -A -o jsonpath='{.items[?(@.metadata.annotations.prometheus\.io/scrape)].metadata.name}'

# has annotation set to "true"
kubectl get service -A -o jsonpath='{.items[?(@.metadata.annotations.prometheus\.io/scrape=="true")].metadata.name}'

# pull multiple values for the object
kubectl get service -A -o jsonpath='{range .items[?(@.metadata.annotations.prometheus\.io/scrape=="true")]}{ .metadata.namespace },{ .metadata.name}{"\n"}{end}'

What the fuck! I will never remember this boring syntax! It is too long to type this shit on my keyboard! I just want to get my k8s resources quickly!

kubectl plugin to the rescue

Hopefully, it is quite easy to create a kubectl plugin to do that. A kubectl plugin is just an executable file written in the language of your choice, located in your $PATH, with a name starting with kubectl-something

For the demo, I created a pod and its service, with the annotation server=mail, and 2 plugins.

3 kubectl plugins

~/.local/bin/kubectl-filterannotation

#!/usr/bin/env bash

function _filter_annotation () {
  ANNOTATION=${1:-}
  echo "{range .items[?(@.metadata.annotations.${ANNOTATION//./\.})]}{ .metadata.name }{'\n'}{end}"
}

if [ "$1" == "--help" ] || [ "$1" == "help" ] || [ "$1" == "-h" ] || [ "$#" -eq 0 ]
then
    cat << EOF
Search for resources with a given annotation.

Usage: kubectl filterannotation your-annotation-name your-usual-kubectl-command

Examples:

Get pods who have annotation server:

    kubectl filterannotation server get pods

Get services who have annotation server:

    kubectl filterannotation server get svc
EOF
    exit 0
fi

kubectl -o jsonpath="$(_filter_annotation ${1})" "${@:2}"

With this plugin, you can search if you have objects with a given annotation.

The syntax is: kubectl filterannotation your-annotation-name your-usual-kubectl-command.

As an example, you want to get pods who have the annotation “server”. Instead of kubectl get pods, you will type:

kubectl filterannotation server get pods

If you want to search for services:

kubectl filterannotation server get services

~/.local/bin/kubectl-filterannotationvalue

#!/usr/bin/env bash

function _filter_annotation_value () {
  ANNOTATION=${1:-}
  VALUE=${2:-}
  echo "{range .items[?(@.metadata.annotations.${ANNOTATION//./\.}=='${VALUE}')]}{ .metadata.name }{'\n'}{end}"
}

if [ "$1" == "--help" ] || [ "$1" == "help" ] || [ "$1" == "-h" ] || [ "$#" -eq 0 ]
then
    cat << EOF
Search for resources with specific value for a given annotation.

Usage: kubectl filterannotationvalue your-annotation-name your-annoation-value your-usual-kubectl-command

Examples:

Get pods who have annotation server and mail value:

    kubectl filterannotationvalue server mail get pods

Get services who have annotation server and mail value:

    kubectl filterannotationvalue server mail get svc
EOF
    exit 0
fi

kubectl -o jsonpath="$(_filter_annotation_value ${1} ${2})" "${@:3}"

This second plugin is working in the same way, but instead of searching only for annotation name, you can filter on the value too.

Imagine you want to query pods and services with the “server” annotation and “mail” value:

kubectl filterannotationvalue server mail get pods,svc

Maybe these 2 plugins are not perfect but it is a good start. You can create your owns who fits your needs :-)

Protip: If you call these plugins without argument, a help message will be displayed ;-)

~/.local/bin/kubectl-getannotationvalue

#!/usr/bin/env bash

function _filter_annotation () {
  ANNOTATION=${1:-}
  echo "{range .items[?(@.metadata.annotations.${ANNOTATION//./\.})]}{ .metadata.name }{'\n'}{end}"
}

if [ "$1" == "--help" ] || [ "$1" == "help" ] || [ "$1" == "-h" ] || [ "$#" -eq 0 ]
then
    cat << EOF
Search for resources with a given annotation.

Usage: kubectl filterannotation your-annotation-name your-usual-kubectl-command

Examples:

Get pods who have annotation server:

    kubectl filterannotation server get pods

Get services who have annotation server:

    kubectl filterannotation server get svc
EOF
    exit 0
fi

kubectl -o jsonpath="$(_filter_annotation ${1})" "${@:2}" -o go-template --template "{{index .metadata.annotations \"${1}\"}}"

This plugin will help you to get annotation values.

Kubectl plugin documentation

Read the documentation about kubectl plugin.

My pod and service example

To test the commands while writing this blog post, I quickly created a pod and its associated service. Here is the manifest:

---
apiVersion: v1
kind: Pod
metadata:
  annotations:
    server: mail
  labels:
    app: mail
    run: mailpit
  name: mailpit
spec:
  containers:
  - image: anatomicjc/mailpit
    imagePullPolicy: Always
    name: mailpit
---
apiVersion: v1
kind: Service
metadata:
  annotations:
    server: mail
  labels:
    app: mail
    run: mailpit
  name: mailpit
spec:
  ports:
  - port: 1025
    protocol: TCP
    targetPort: 1025
  selector:
    app: mail
    run: mailpit
  type: ClusterIP