Writing Docker Hub hooks in Perl
Published: 2020-12-21 18:57:53

---
title: Writing Docker Hub hooks in Perl
published: true
description: How to create a hook that automatically builds a set of images in Docker Hub. using Perl
tags: 
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/s46oei9lo1qvhbfajq5q.jpg
---
One of the great things about [Docker Hub](https://hub.docker.com) is its automation tools. You can trigger a cascade of image creation from a single change in a base image.
But what happens if you want to trigger the creation of a whole set of images, all of them contained in a single repository and generated from a single Dockerfile? Well, we've got that covered too, in principle: using [hooks](https://docs.docker.com/docker-hub/builds/advanced/).

As in the case of [git hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks), they're a set of events triggered in different phases of the build process. Create a file with a certain name, put it in your repo's `hook` directory, make it executable, and Bob's your uncle.

All examples I had seen, however, were written using shell scripts; for instance, [this one](https://dev.to/samuelea/automate-your-builds-on-docker-hub-by-writing-a-build-hook-script-13fp). However, as soon as you need to create something with some complexity (processing JSON, for instance, or *cough* doing string comparisons) it starts to get really tiring. Mind you, shell scripts are incredibly powerful. But you can really save time using a real language.

It was not totally clear [which languages](https://stackoverflow.com/questions/65389399/what-tools-are-available-in-docker-hub-hooks) were available, however. After a while (and some commands placed in hooks) I discovered, however, that it was an instance of [Amazon Linux](https://aws.amazon.com/es/amazon-linux-ami/2018-03-packages/) and that, indeed, there were a few languages available. Among them, Perl.
![Showing output of the hook, with Perl](https://dev-to-uploads.s3.amazonaws.com/i/tvy22ln1iwtapqxaqrwe.png)

Initially I used Perl simply to extract tags. But then I realized I could use it for everything. So [here's the resulting script](https://github.com/JJ/docker-raku-test/blob/master/hooks/post_push)

```perl
use strict;
use warnings;

use v5.14;

my $tags = `curl https://registry.hub.docker.com/v1/repositories/jjmerelo/alpine-raku/tags`;

my @tags = ($tags =~ /\"(2[^\"]+)\"/g );

for my $tag ( @tags ) {
    say "👷 Building for $tag";
    if ( $tag ge "2020.06" ) {
       say "🚧 docker build hooks --build-arg CODE_VERSION=$tag -t jjmerelo/raku-test:$tag";
       `docker build . -f hooks/Dockerfile --build-arg CODE_VERSION=$tag -t jjmerelo/raku-test:$tag`;
    } else {
       say "🚧 docker build -f hooks/root.Dockerfile --build-arg CODE_VERSION=$tag -t jjmerelo/raku-test:$tag";
       `docker build . -f hooks/root.Dockerfile --build-arg CODE_VERSION=$tag -t jjmerelo/raku-test:$tag`;
    }
    `docker push jjmerelo/raku-test:$tag`;
}
```

What I needed was for the script to find out all tags in the [`alpine-raku`](https://hub.docker.com/r/jjmerelo/alpine-raku) base image, and then build the corresponding `test-raku` image with the same tag. The [Dockerfile](https://github.com/JJ/docker-raku-test/blob/master/hooks/Dockerfile) had been slightly tweaked to be able to use a base image that was defined, in part, by a command-line argument:

```Dockerfile
ARG  CODE_VERSION
FROM jjmerelo/alpine-raku:${CODE_VERSION}
ARG  CODE_VERSION
LABEL version="7.0.0" maintainer="JJ Merelo <jjmerelo@GMail.com>"

ARG DIR="/test"
USER root

# Set up dirs
RUN  echo "Building from version ${CODE_VERSION}" && mkdir $DIR && chown raku $DIR
COPY --chown=raku test.sh /home/raku
VOLUME $DIR
WORKDIR $DIR

USER raku

# Will run this
ENTRYPOINT ["/home/raku/test.sh"]
```

[`ARG`](https://docs.docker.com/engine/reference/builder/#arg) needs to be repeated, since `FROM` creates a new scope; that's only needed if you want to print something while building (which I might delete later).

Other than that, the script is relatively straightforward:

- Downloads the tags for the base image using the Docker Hub API. That gets all versions in a JSON, but I didn't want to install additional modules, so I just leverage the fact that all tags I'm interested with start with `2` and are between quotes to get that out of the JSON.
- Then it's build/push time. The only thing here is that, prior to the `2020.07` version, I didn't use a non-privileged user for the image. So I needed to create two different Dockerfiles, one for each, which is why I need to find out what's the tag before choosing what to build.
- Then it's build and push, with results [already shown](https://hub.docker.com/repository/docker/jjmerelo/raku-test)

It would be great if we had the full reference of things that can be used; for instance, having `jq` installed would have saved me some trouble. Meanwhile, [this pull request](https://github.com/docker/docker.github.io/pull/11952) asks for adding, at least, some information on what's there so that we can build great hooks to automate the hell out of our docker image builds.