tuplip generates and checks Docker tags in a transparent and convention-forming way
tuplip accepts three kinds of tag vectors (i.e., sub elements that define a tag) as the input, namely (unversioned) alias vectors, (versioned) dependency vectors, and one (versioned) root vector.
The alias vector does not contain a version and is just passed as it. It can be used to identify a feature or a branch of the Docker image.
The dependency vector depicts the dependencies of the Docker image. All versioned sub layers, binaries, and imports of the image can be depicted with their regarding semantic version variants. To let tuplip create all possible tuples for the semantic version of the dependency, pass the tag vector alias colon-separated from the version. For example, use 'alpine:3.8' to create the vector tuple 'alpine', 'alpine3', and 'alpine3.8' that are then further combined with the other given input vectors.
Root vectors are similar to the dependency vectors but they don't contain the alias prefix.
They are meant to be used for the core product that the Docker images represents.
The root vector is always placed in front of the remaining elements.
A root vector is defined by setting _
as the version alias (e.g., as in _:1.0.0
).
The tag vectors are fetched from the cli standard input by default, either line-separated or separated by the given
separator argument. Alternatively, in fromFile
, a Dockerfile can be used instead of the standard input
to parse its FROM instructions as vectors.
go install github.com/gofunky/tuplip/cmd/tuplip@main
go get -u github.com/gofunky/tuplip
docker pull gofunky/tuplip
echo "dep _:1.0.0" | tuplip build from stdin
import "github.com/gofunky/tuplip/pkg/tupliplib"
docker run --rm -i gofunky/tuplip build from tag _:1.0
tag
1
1.0
1-tag
1.0-tag
tuplip build
generates all possible tag representations that a given Docker image should receive.
A repository can be defined to be prefixed to the tags. Leave the argument out to use it without a repository.
By default, all tags are printed line by line to the stdout
. Errors are printed to the stderr
.
sudo ~/go/bin/tuplip build to gofunky/ignore from tag _:1.0
gofunky/ignore:tag
gofunky/ignore:1
gofunky/ignore:1.0
gofunky/ignore:1-tag
gofunky/ignore:1.0-tag
tuplip tag
tags the given source image with all tags that the build
command would generate.
A repository can be defined to be prefixed to the tags. Leave the argument out to use it without a repository.
Docker needs to be installed. If you usually need sudo
for the docker cli, also use sudo
for tuplip
.
sudo ~/go/bin/tuplip tag source-tag to gofunky/ignore from test _:0.0.1 -l
gofunky/ignore:latest
gofunky/ignore:test
gofunky/ignore:0
gofunky/ignore:0.0
gofunky/ignore:0.0.1
gofunky/ignore:0-test
gofunky/ignore:0.0-test
gofunky/ignore:0.0.1-test
tuplip push
tags the given source image with all tags that the build
command would generate,
and pushes them afterwards. Contrasted to docker push org/repository
, this method ensures that only the intended
tags are pushed, and no accidentally pulled outdated ones with the same repository prefix.
Docker needs to be installed. If you usually need sudo
for the docker cli, also use sudo
for tuplip
.
You need to be logged in to the Docker Hub for pushes (e.g., by calling docker login
).
sudo ~/go/bin/tuplip push source-tag to gofunky/ignore from test _:0.0.2
gofunky/ignore:0
gofunky/ignore:0.0
gofunky/ignore:0.0.2
gofunky/ignore:test
gofunky/ignore:0-test
gofunky/ignore:0.0-test
gofunky/ignore:0.0.2-test
tuplip find
works vice versa. Projects with larger dependency graphs are difficult to track.
This command helps you to find the most appropriate tag given your required dependency versions.
It finds the tag matching as many of your given dependencies as possible with as little overhead as possible.
The Docker Hub repository to check can be any repository that follows the common convention.
If only few dependencies are defined, finding an appropriate image is no hassle.
However, the more vectors are given, the more possible variations in the vector order exist.
tuplip uses an alphabetical order (prioritizing root vectors), but other tags may use another order.
The tuplip find
command not only checks the order, it also finds a suitable version variant.
Let's assume we always want the latest git version but we require alpine 3.8.
tuplip find in gofunky/git from alpine:3.8
Then, the most appropriate image would be:
alpine3.8
For those who are wondering now, why the output tag does not contain the version of git itself, the answer is that according to a mostly-used Docker convention, all unmentioned dependencies implicitly equal the latest versions since these images are always rebuilt. Only the versions explicitly defining an outdated dependency are not rebuilt and preserve the defined versions.
Let's assume, we need git version 2.18.0 besides the given alpine version 3.8.
tuplip find gofunky/git from alpine:3.8
Then, the most appropriate image would be:
2.18.0-alpine3.8
Unversioned alias tag vectors describe dependencies without versions or special build parameters that define a separate output portion.
echo "something fancy" | tuplip build from stdin
something
fancy
fancy-something
Versioned tag vectors describe dependencies with versions. Given as such, the versions are altered and depicted in all their variants.
echo "go:1.2.3" | tuplip build from stdin
go
go1
go1.2
go1.2.3
A versioned root tag vector is used to depict the different version representations of the project itself.
echo "_:1.0 dep" | tuplip build from stdin
1
1.0
dep
1-dep
1.0-dep
Separate the tag vectors either by newlines or by spaces.
echo "something fancy" | tuplip build from stdin
Separate the tag vectors by spaces.
tuplip build from something fancy
FROM org/image:tag as alias
Define the tag vectors as FROM
instructions in a Dockerfile.
tuplip find from file yourDockerfile
The advantage of using a Dockerfile is that you can use Dockerfile dependency update tools. Instead of hard coding the Docker tags, you can let tuplip find the most appropriate one from a Dockerfile in your project path. Once a pull request is created with an updated dependency from a Docker repository, tuplip checks if the given image has an updated version. Finally, you will have an immediate notification if dependencies are updated and if your required Docker images have tags available that match them.
FROM golang:1.11.4 as builder
FROM scratch as master
FROM gofunky/docker:18.09.0
ARG VERSION=2.4
ARG REPOSITORY=gofunky/ignore
The above Dockerfile shows an example. It could be a separate file just for version resolving. Alternatively, one may also use an existing Dockerfile for a target image and build the target tags from it.
The ARG
instruction that is called VERSION
will be interpreted as the root tag vector version.
Alternatively, one may use the --root-version
, or short -r
, flag to override it.
If no root tag vector is required, simply remove the respective ARG
instruction.
The target repository will be derived (e.g, the one to check using the find
command)
from the ARG
instruction that is called REPOSITORY
.
If no target repository is required, simply remove the respective ARG
instruction.
All FROM
instructions that contain a tag or version will be interpreted as dependency tag vectors.
The image
name (without the org
) will be used as alias by default.
This derived alias can be overridden by setting scratch
as image
name and setting a custom alias
(e.g., FROM scratch:0.1 as dep
).
All other FROM
instructions that do not contain a tag or version will be interpreted as alias tag vectors.
The image
name (without the org
) will be used as alias by default.
This derived alias can be overridden by setting scratch
as image
name and setting a custom alias
(e.g., FROM scratch as alias
).
Transitive multi-vector-tagged image dependencies will be interpreted correctly.
That means, FROM gofunky/golang:1.11.0-alpine3.8 as builder
for instance,
will return the vectors golang:1.11.0
and alpine:3.8
.
Any FROM
instructions that use an alias with the prefix i__
(e.g., i__builder
) will be ignored.
--exclude-major
or -m
excludes the major versions (e.g., go1
for go:1.2.3
) from the considered version variants.
echo "go:1.2.3" | tuplip build from stdin --exclude-major
go
go1.2
go1.2.3
--exclude-minor
or -i
excludes the minor versions (e.g., go1.2
for go:1.2.3
) from the considered version variants.
echo "go:1.2.3" | tuplip build from stdin --exclude-minor
go
go1
go1.2.3
--exclude-base
or -b
excludes the base alias (e.g., go
for go:1.2.3
) from the considered variants.
echo "go:1.2.3" | tuplip build from stdin --exclude-base
go1
go1.2
go1.2.3
--add-latest
or -l
adds the latest
tag to the output set.
tuplip build from _:1.2.3 --add-latest
1
1.2
1.2.3
latest
--exclusive-latest
or -e
makes the latest
root tag vector version an exclusive tag if given.
This is especially useful for automated builds (e.g., Docker Hub builds) where the root tag vector version is passed from the build system.
tuplip build from _:latest alias:1.2.3 --exclusive-latest
latest
--separator
or -s
sets a different tag vector separator when reading from standard input.
echo "something; fancy" | tuplip build from stdin --separator=";"
something
fancy
fancy-something
--root-version
or -r
overrides the root tag vector's version of the given Dockerfile.
It is available in the from file
commands.
tuplip build from file Dockerfile -f golang,docker,master -r 1.1.1 -m -i
docker-golang-master
docker-golang1.11.4-master
docker18.9.0-golang-master
docker18.9.0-golang1.11.4-master
1.1.1-docker-golang-master
1.1.1-docker18.9.0-golang1.11.4-master
1.1.1-docker18.9.0-golang-master
1.1.1-docker-golang1.11.4-master
--straight
or -s
lets tuplip use the input tags directly without any mixing.
It is available in the tag
and push
commands.
tuplip push image to gofunky/ignore from foo goo -s
gofunky/ignore:foo
gofunky/ignore:goo
Notice that there is no foo-goo
present since the given arguments are no tag vectors but simple input tags that are passed to docker.
--filter
or -f
excludes all tags without the given set of tag vectors from the output set.
tuplip build from one two:0.1 three --filter one,two
one-two
one-two0
one-two0.1
one-three-two
one-three-two0
one-three-two0.1
--verbose
or -v
enables descriptive logging to the stderr.
Nevertheless, stdout will only receive the output tags to ensure a strict separation that
doesn't hinder any post-processing.
tuplip push image to gofunky/ignore from foo goo -s --verbose
{"level":"info","message":"queueing read from slice"}
{"level":"info","message":"queueing tagging","source tag":"image"}
{"level":"info","message":"execute","args":"docker"}
{"level":"info","message":"queueing push"}
{"level":"info","message":"execute","args":"docker"}
{"level":"info","message":"execute","args":"docker tag image gofunky/ignore:foo"}
{"level":"info","message":"tagged","tag":"gofunky/ignore:foo"}
{"level":"info","message":"fetching tags for remote repository","repository":"gofunky/ignore"}
{"level":"info","message":"execute","args":"docker tag image gofunky/ignore:goo"}
{"level":"info","message":"tagged","tag":"gofunky/ignore:goo"}
{"level":"info","message":"execute","args":"docker push gofunky/ignore:foo"}
{"level":"info","message":"pushed","tag":"gofunky/ignore:foo"}
{"level":"info","message":"fetching tags for remote repository","repository":"gofunky/ignore"}
{"level":"info","message":"execute","args":"docker push gofunky/ignore:goo"}
{"level":"info","message":"pushed","tag":"gofunky/ignore:goo"}
gofunky/ignore:foo
gofunky/ignore:goo