Keep your container images up to date.
CLade allows you to manage multiple Dockerfiles as a dependency tree and list images older than the upstream image.
$ go install github.com/lesomnus/clade/cmd/clade@latest
Command clade
reads Port files named port.yaml
in the directories of ports
directory to construct a dependency tree. Port file describes what an image's tag is and which image that tag depends on.
$ mkdir -p ports/my-gcc
$ code ports/my-gcc/port.yaml
# ports/my-gcc/port.yaml
name: ghcr.io/my_name/my-gcc
images:
- tags: ['my-tag']
from: registry.hub.docker.com/library/gcc:latest
The above Port file describes that ghcr.io/my_name/my-gcc:my-tag
is built from the registry.hub.docker.com/library/gcc:latest
.
Let's see if this parses well:
$ clade tree
registry.hub.docker.com/library/gcc:latest
ghcr.io/my_name/my-gcc:my-tag
This is the most basic usage of CLade.
How can we create a new image with that version name whenever a new version of GCC is updated? Probably the simplest way would be to populate a list of images
for all versions. Alternatively, there is a way to have CLade fetch tags from the remote repository. Updates our Port file as:
# ports/my-gcc/port.yaml
name: ghcr.io/my_name/my-gcc
images:
- tags: ( printf "%d.%d" $.Major $.Minor )
from:
name: registry.hub.docker.com/library/gcc
tagd: ( tags | semverLatest )
$ clade tree
registry.hub.docker.com/library/gcc:12.2
ghcr.io/my_name/my-gcc:12.2
What happened? Where did 12.2 come from? Let's find out one by one. First, what ( remoteTags | semverLatest )
is? This is pipeline expression. The result of the previous function becomes the argument of the next function. So it means, fetch the tags from registry.hub.docker.com
, then take the latest semver. That would be 12.2 at this point. The result of the pipeline is Semver type and it is passed to pipeline in tags
as a data and the result of the pipeline become result tags.
If there is more than one result of the from
pipeline, CLade generates that many images. Let's create my-gcc:12.X
for all gcc 12 versions using semverMajorN
which filters last N major versions. Also if there are more than one tag or tag pipeline is provided, multiple tags will be created from the same image.
# ports/my-gcc/port.yaml
name: ghcr.io/my_name/my-gcc
images:
- tags:
- ( printf "%d.%d" $.Major $.Minor )
- ( printf "%d" $.Major )
from:
name: registry.hub.docker.com/library/gcc
tags: ( tags | semverMajorN 1 )
$ clade tree
registry.hub.docker.com/library/gcc:12
ghcr.io/my_name/my-gcc:12.0
registry.hub.docker.com/library/gcc:12.1
ghcr.io/my_name/my-gcc:12.1
registry.hub.docker.com/library/gcc:12.2
ghcr.io/my_name/my-gcc:12.2
ghcr.io/my_name/my-gcc:12
You can now track upstream container images. To build, you can use the clade build
command. Before that, let's create a Dockerfile first.
code ports/my-gcc/Dockerfile
# ports/my-gcc/Dockerfile
ARG BASE
FROM ${BASE}
ARG USERNAME=my_name
ARG USER_UID=${UID:-1000}
ARG USER_GID=${GID:-${USER_UID}}
RUN groupadd ${USER_GID} --gid ${USER_GID} \
&& useradd \
--create-home ${USERNAME} \
--shell /bin/bash \
--uid ${USER_UID} \
--gid ${USER_GID}
WORKDIR /home/${USERNAME}
USER ${USERNAME}
Note that argument BASE
is remote container image reference.
The command for the default option, clade build
simply spawns docker
command with proper arguments.
Let's see what CLade runs:
$ clade build --dry-run ghcr.io/my_name/my-gcc:12
[/usr/bin/docker build --file /path/to/ports/my-gcc/port.yaml/Dockerfile --tag ghcr.io/my_name/my-gcc:12.2 --tag ghcr.io/my_name/my-gcc:12 --build-arg BASE=registry.hub.docker.com/library/gcc@sha256:9c9194913f48efd4c74ad2cd669b843bdea6325df71f6a32ac04fdd343bec0e0 /path/to/ports/my-gcc]
- More examples of Port file → ports
- Full Port file reference → docs/port.md
- Available pipeline functions → docs/pipeline-functions.md