4

I'm building images on a small server and spinning them up with docker-compose.

When it's disk gets full I run docker prune -a so all the stopped containers, dangling image are cleaned out.

But I'd like to keep one or two recent images in case I need to roll back quickly.

The docker prune documentation says --filter until=<timestamp>. But the timestamps from the previous images could be days, weeks or months old.

Then suggested method for pruning by date is:

a) find the timestamp by listing the images with this format

docker images --format 'table {{.Repository}}\t{{.Tag}}\t{{.ID}}\t{{.CreatedAt}}\t{{.Size}}'

which produces

REPOSITORY          TAG                 IMAGE ID            CREATED AT                      SIZE
foo                 latest              2f287ac753da        2017-01-04 13:42:23 -0800 PST   3.98 MB
alpine              latest              88e169ea8f46        2016-12-27 10:17:25 -0800 PST   3.98 MB
busybox             latest              e02e811dd08f        2016-10-07 14:03:58 -0700 PDT   1.09 MB

How can I automatically select the second created at timestamp in the list it produces?

...to then pass it as a variable into

b) docker image prune -a --force --filter "until=<2rd timestamp from list>"

Is there an way to use awk ? Is there another way to leave an extra image ?

Kickaha
  • 153
  • 1
  • 6

2 Answers2

4

The problem is that the date format isn't ideal.

Supported formats for date formatted time stamps include RFC3339Nano, RFC3339, 2006-01-02T15:04:05, 2006-01-02T15:04:05.999999999, 2006-01-02Z07:00, and 2006-01-02

Reference: https://docs.docker.com/engine/reference/commandline/system_prune/#filtering

So this is really just a half answer, since it will use the date and the local timestamp.

The local timezone on the daemon will be used if you do not provide either a Z or a +-00:00 timezone offset at the end of the timestamp.

Thankfully, this comes sorted.

~: docker images --format '{{.CreatedAt}}'
2020-06-09 12:44:57 -0700 PDT
2020-05-29 14:19:46 -0700 PDT
2020-05-05 13:40:47 -0700 PDT
2020-04-28 11:55:11 -0700 PDT
2020-03-09 10:35:34 -0700 PDT
2020-03-09 10:14:43 -0700 PDT
2020-03-09 10:14:43 -0700 PDT
2020-03-09 10:14:43 -0700 PDT
2020-02-26 07:10:58 -0800 PST

I don't know how to transform timestamps in bash off the top of my head, so let's just do this the quick and messy way... the whole date!

 ~: docker images --format '{{.CreatedAt}}' | sed -n '2p' | awk '{print $1;}'
2020-05-29

Now we can do command substitution.

~: docker image prune --force --filter "until=`docker images --format '{{.CreatedAt}}' | sed -n '2p' | awk '{print $1;}'`"
Total reclaimed space: 1.344GB

I didn't put a heck of a lot of thought in to this answer, so there may be some edges cases I didn't consider. Also, if someone with better bash-fu can transform that timestamp, that would be awesome.

Woodland
  • 1,338
  • 8
  • 14
1

It is also possible to use before filter.

E.g., if the question would be about removing "all but 1(one) most recent image", the answer could be:

docker images -q --filter before=$nameTag $nameOnly | xargs --no-run-if-empty docker rmi --force || true

And Jenkins method could look like:

def previousImagesCleanup(String nameTag) {
  String nameOnly=nameTag.split(':')[0]
  log.info("Clean up if build succeeded - delete images prior to the current one ($nameTag). Preserving last one for cache purposes.")
  sh("docker images -q --filter before=$nameTag $nameOnly | xargs --no-run-if-empty docker rmi --force || true")
}