Docker Inspect Template Magic

Most Docker users are aware of the docker inspect command which is used to get metadata on a container or image, and may have used the -f argument to pull out some specific data, for example using docker inspect -f {{.IPAddress}} to get a container’s IP Address. However, a lot of users seem confused by the syntax of this feature and very few people take full advantage of it (most people seem to pipe the output through grep, which is effective but messy). In this post, I’ll look into how the -f argument works and show some examples of how to use it.

Put simply, the -f argument takes a Go template as input and runs it against the metadata for the given containers or images. The first problem is the phrase “Go template” is rather nebulous, at least to anyone inexperienced in Go — my first feeling was atavistic fear from the memory of C++ templates. Thankfully, Go templates has nothing in common with C++ templates or generics, and is in fact a template engine that takes a data source and a template pattern and combines the two to produce an output document. This idea should be very familiar to most web developers and common examples of template engines include Jinga2 (commonly used with Python and Flask), Mustache and JavaServer Pages. The concept is perhaps best explained by a simple example:

As we can see, the argument to -f is a simple pattern (or template) that we want to apply to the metadata of container. In fact, we don’t even have to do anything with the metadata:

But, if we learn a bit of Go templating magic, things that were once tricky become much simpler. For example, to find the names of all containers with a non-zero exit code:

(Unfortunately Docker prints a new-line for each container, whether it matches the if or not).

Or to find the host directory for the volume /var/jenkins_home in my jenkins-data container:

At the moment, both of these examples are probably a little hard to parse. There are a few basics you need to understand before you can get started with your own templates.

Directives

The {{ }} syntax is used for processing directives. Anything outside of the curly brackets will be output literally.

The . Context

A “.” stands for the “current context”. Most of the time this is the whole data structure for the metadata of the container, but it can be rebound in certain cirumstances, including using the with action:

You can always get the root context by using $. e.g.

Note that it is perfectly valid to use a “.” by itself, the following will just output the full data completely unformatted:

Data Types

The inspect data seems to consist of floats, strings and booleans. These can be tested and compared using various functions. At the moment, it seems that all numbers are floats, although Go templates do support integers, which would seem to be more appropriate in most cases (I’ve submitted an issue about this). Use double quotes when working with strings.

Values which appear as “null” appear to be not present in the data at all, and can’t be compared:

Data Structures

The inspect data uses maps and arrays. Maps are normally easy, you can just chain stuff together to access inner maps as we’ve seen already:

However, this isn’t possible if the key for the map isn’t in a suitable format (for example, if it uses a non alphanumeric character). If that’s the case, you can use the index function as we did in the volumes example:

You can also use index to get an array entry by number:

Functions

Apart from index, there are a few more functions that are likely to be useful. The logical functions and, or and not are available and operate largely as expected, returning a boolean result. Note that as they are functions, they cannot be used infix i.e:

Not:

The following comparison functions are available:

  • eq (equals)
  • ne (not eqaul)
  • lt (less than)
  • le (less than or equal to)
  • gt (greater than)
  • ge (greater than or equal to)

They can compare strings, floats or integers:

But note that output types have to match, and numbers in Docker seem to be all floats, despite how they are printed:

UPDATE: This seems to have been fixed; now both integers and floats will work correctly e.g:

(This was tested in Docker 1.7).

There is also a json function for generating JSON:

So you can combine templates with the jq tool, which you may be more familiar with:

 

Of course, the default output of docker inspect is also JSON, so this also works:

 

There are a few more functions listed in the official Go documentation, but it weirdly seems to be missing the json function (which I learnt from Nathan LeClaire’s blog) — if someone knows the reason for this, please let me know!

If Statements

Conditional statements can be handled with an if statement and normally use one of the previous comparison functions:

Note the {{end}} statement is required to terminate the if. The else if and else parts are optional.

Conclusion

I think this covers most of the stuff you are likely to need when using templates with docker inspect, but there are more features available, such as using range to iterate over data, defining your own functions and using pipes.

I have yet to find a good, complete reference to using Go templates. The best I have found so far is a chapter from a the free e-book “Network programming with Go” by Jan Newmarch.

There is also the official Go documentation, but it is little terse and hard to follow, especially if you’re not a Go programmer.

The following two tabs change content below.

Adrian Mouat

Adrian Mouat is Chief Scientist at Container Solutions and the author of the O'Reilly book "Using Docker". He has been a professional software developer for over 10 years, working on a wide range of projects from small webapps to large data mining platforms.

Latest posts by Adrian Mouat (see all)

9 Comments

    • Any idea on how to get the last element of Config.Env ?

      I can get the whole list, the first element, the second, the length of the array, but have tried various syntaxes looking, like len-1
      , to no avail.

      $ docker inspect -f ‘{{ .Config.Env }}’ 7a7
      [DISPLAY=:0 PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin LANG=fr_FR.UTF-8 LANGUAGE=fr_FR:en LC_ALL=fr_FR.UTF-8 DEBIAN_FRONTEND=noninteractive HOME=/home/gg WINEARCH=win32 WINEPREFIX=/home/gg/.wine_captvty]
      $ docker inspect -f ‘{{ index ( .Config.Env) 0 }}’ 7a7
      DISPLAY=:0
      $ docker inspect -f ‘{{ index ( .Config.Env) 1 }}’ 7a7
      PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
      $ docker inspect -f ‘{{ len .Config.Env }}’ 7a7
      9

      Thanks for this great tutorial

  1. @Labadie

    I’m glad you found the post useful.

    There are no maths functions defined by default in templates, so you can’t do +, – or even inc or dec. I think you might be able to solve your problem using range, but it would be a bit messy (the solution that springs to mind is iterating through the array, saving the current value in a variable until you come to the last value, when you print the previous value).

    Adrian.

  2. Jérôme Petazzoni tweeted a solution for this, thanks to him

    docker inspect –format “{{ index .Config.Cmd $[$(docker inspect –format ‘{{ len .Config.Cmd }}’ $CID)-1]}}” $CID

    • Ha, excellent. I didn’t think of embedded inspects, which of course lets you use bash to do maths. Thanks for updating this with the answer.

Leave a Reply

Your email address will not be published. Required fields are marked *