Dockron is able to execute docker commands on (groups of) entities on a regular basis, based on a cron-like syntax. Example of such entities are containers, but also, networks, (Swarm) nodes, secrets, etc. It relies on the Docker client implementation in Tcl (See the end of this document for how to resolve dependencies).
The rationale for Dockron is to be able to move scheduling (as in time scheduling, not container scheduling) into one or several central places. Sometimes, you need to schedule tasks that are meaningful to your application/stack, and expressing these as a Dockron service (in a compose file, for example) is meaningful. Other scenarios are to regularly schedule various operations on an entire Swarm.
Note dockron
probably does not do exactly what you think it does: In its
simplest form, it will relay the tockler API, and not the regular
command-line docker
API that you are probably used to. However, given a
little bit more configuration, you should be also be able to use the CLI if
tockler is not enough. See dockron.yml for an example.
Dockron is able to connect to the local Docker UNIX socket, but also remote docker daemons. The program takes a number of dash-led options and arguments. Provided it is properly installed, running it as below should provide help for its options.
./dockron.tcl -h
The actions to perform on entities are taken from the command-line option
-rules
. Its value should be a white-space separated list of specifications,
which length depends on the value of the command-line option -precision
. When
-precision
is seconds, the list should contain a multiple of 9 items and The
items are taken in turns and are interpreted as described below:
- The second of the day (see below)
- The minute of the day (see below)
- The hour of the day (see below)
- The day of the month (see below)
- The month number (see below)
- The day of the week (see below)
- The combination of an entity type and a glob-style pattern to match against the name(s) of the entity. When the type is not explicitely specified, it will be considered to target containers.
- The command to execute, e.g.
restart
,pause
, as available from the API implementation. - Additional arguments to the command.
For all the date and time related specifications, the component controller
follows the crontab
conventions, meaning that you should be able to specify
"any" using *
, but also intervals such as 0-5,14-18,34
, or "every 3" using
*/3
. The command to execute can be empty, in which case the arguments are
used in a slightly different way as explained below.
The value of the -precision
command-line option will influence the number of
necessary items in the -rules
list. It is case insensitive and matches on the
first letter, even though it is advised to specify using the entire word (prefer
writing seconds
rather than just s
). The length of the list in -rules
will
vary with the value of -precision
as follows:
- When the precision is set to
seconds
, i.e. starts with the letters
, all 9 items need to be present in-rules
. - When the precision is set to
minutes
, i.e. starts with the letterm
, there should be only 8 items present in-rules
, starting from #2 above, i.e. minute of the day. This is the default and also is how the UNIXcron
utility works. - When the precision is set to
hours
, i.e. starts with the letterh
, there should be only 7 items present in-rules
, starting from #3 above, i.e. hour of the day. - When the precision is set to
days
, i.e. starts with the letterd
, there should be only 6 items present in-rules
, starting from #4 above, i.e. day of the month.
IMPORTANT NOTE: dockron
tries to cope with the time taken for talking to
the underlying docker daemon. It also tries to minimise the number of calls to
the API as much as possible. However, collecting relevant lists of resources
(containers, configs, etc.) and mostly operating on these (e.g. restarting a
container) takes time and calls are made synchronously. This means that when
going down to seconds precision, it is highly possible that dockron
will miss
clock ticks because operations took too long time to execute. A workaround is to
write rules that do not overlap over time when executing.
When looking for matching entities, the specification (6th argument in the rule
list) should be composed of a type specification, followed by a slash /
,
followed by a glob-style pattern. The type can be omitted, in which case the
slash can also be omitted. Empty patterns lead to slightly different behaviours
(see below).
The type specification is case insensitive and can be shortened to the minimum descriptive string within the set of entities for brievity. At present, Dockron supports the following (mostly self explanatory) types of entities:
C
or any string beginning withCONT
(as for exampleCONTAINER
).S
or any string beginning withSER
(as for exampleSERVICE
). This will match against the existing services among a manager of the swarm.- Any string beginning with
V
(as for exampleVOLUME
). - Any string beginning with
I
(as for exampleIMAGE
). N
or any string beginning withNO
(as for exampleNODE
). This will match against the existing nodes known to a manager of the swarm.W
or any string beginning withNE
(as for exampleNETWORK
).R
or any string beginning withSEC
(as for exampleSECRET
). This will match against the existing secrets known to a manager of the swarm.G
or any string beginning withCONF
(as for exampleCONFIG
). This will match against the existing configurations known to a manager of the swarm.
In general, the glob-style pattern will be matched against the name(s) of the entities. For containers, the leading slashes of the name will not be considered. For images, matching will happen against the tags.
When constructing the API call to communicate with the Docker daemon, the
identifiers of all the entities matching the pattern will automatically be
appended to the command, followed by the arguments. For example, a rule
specification expressed as follows will arrange for restarting all containers
matching the pattern *myworker*
.
12 */2 * * * C/*myworker* "container restart" ""
An empty glob-style pattern (or the single dash -
) is a special case that can
be used for system commands, or commands that do not operate on a specific
entity, e.g. prune
commands. For example, a rule expressed as follows will
arrange to prune all stopped containers at a host.
12 */2 * * * C/- "container prune" ""
An empty command is yet another special case, a case that can be used to express
more complex command sequences. In that case, the remaining arguments are used
to form a Tcl command that will communicate with the Docker daemon once some
keywords have been substituted. Keywords are surrounded by the percent %
sign, and the list of known keywords is the following:
%cx
(or%docker%
, an alias) will automatically be replaced by the internal identifier of the Docker connection, as returned by calls todocker connect
by the API implementation.%id%
will be replaced by the identifier of the entity that matched the pattern.%name%
will be replaced by the name of the entity that matched the pattern.
For example, a rule specification as below will, once again, but expressed
differently restart all containers matching the pattern *myworker*
. Note the
use of the leading %cx%
, and of %id%
which will, once dynamically
substituted, lead to a valid call to the Tcl Docker API implementation.
12 */2 * * * C/*myworker* "" "%cx% container restart %id%"
Note that the command formed as such is called directly in the context of the executing procedure and there are no security guards, nor execution within a safe interpreter.
Sometimes, tockler is not complete, alternatively makes it complex to
express what the regular docker
CLI command makes easier to interface. In
those cases, and as long as you remain on the same host, you should be able to
call the local docker
binary (usually at /usr/bin/docker
) using Tcl's exec
command. It is even possible to perform this kind of operation from within the
Docker container of dockron, provided you mount the docker controlling
socket at /var/run/docker.sock
and the binary itself at /usr/bin/docker
into
the container. The Dockerfile adds a number of compability packages to the base
Alpine installation to make it possible to call the docker
binary from Alpine,
even if the container runs on, e.g. Ubuntu, and the binary is mounted into the
container. This is possible because of the minimal dependencies that are present
in Go binaries.
When the first character of the arguments is an arobas @
, all characters of
the first argument after the arobas form the path to a template file that will
be read once. Its content will be substituted each time necessary, as if it had
come from the arguments and is explained in the previous section. Additional
arguments are also substituted and passed further using the argv
global
variable. Offloading content to a file allows for even more complex calls and/or
construction, benefiting from the entire expressiveness of the Tcl syntax.
For example, creating the following content in a file called test.tcl
and
arranging for setting the 8th item of the rule list to @./test.tcl
would
arrange to prune away all dangling images. Note that the command makes a direct
call to docker filters
, a helper procedure from the Docker Tcl implementation
meant to facilitate the construction of JSON expressions that should be sent as
part of the API query.
%cx% image prune -filter [docker filters dangling 1]
Some operations are easier to execute using the regular docker
command-line
client as opposed to through the API, e.g. scaling a service. For these
usecases, it is possible to use calls to Tcl exec
to relay identifiers and or
names to the regular docker
command-line client. For example, supposing that
%name%
matches the name of an existing service, the following line in such a
template, would arrange to scale the matching service to 3 replicas:
exec docker service scale %name%=3
If you want to run such operations when dockron
is run as part of its Docker
image you will have to ensure that the docker
executable is itself
accessible to the container, e.g. through mounting the executable from the host
into the container as a volume: -v /usr/bin/docker:/usr/bin/docker
.
To run Dockron from compose, you would could specify something like the
following, which would automatically restart two sorts of worker components once
every two hours. Pay attention to the quotes around starting and ending the list
of -rules
.
watchdog:
image: efrecon/dockron
restart: always
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
command: >-
-rules
"12 */2 * * * *myworker* restart \"\"
13 */2 * * * *myotherworker* restart \"\""
-verbose INFO
Dockron is best run as a Docker container. Get it from the hub, where it will always be available at its latest version, or build it yourself using:
docker build -t efrecon/dockron .
To run it locally, you will need to mount the docker socket into the component, e.g. (but the following command wouldn't do much...):
docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock efrecon/dockron -h
dockron
uses git submodules, make sure to clone with recursion to arrange
for accessing the Docker API implementation.
The Docker compose file dockron.yml provides examples of all the various
command conventions for operating on Docker resource using a dummy container
called date-out
. Provided a recent version of Docker compose, run the file
using the following command.
docker-compose -f dockron.yml up --build
This will create a dummy container called date-out
that outputs the current
date and time every seconds and will be restarted using dockron
running in
another container. Everytime date-out
is restarted, compose will change the
colour of the line header to ease recognising that the container is effectively
restarted. dockron
is setup to use seconds precision for quicker tests:
- At second 0, the old-style API is used, issuing the command
restart
on the container which names matches the pattern. - At second 15, the new-style API is used, issuing a tockler command once substitution has occured (and the container matching the pattern found).
- At second 30, the real
docker
binary (mounted as a volume into the container) is called through the Tclexec
command. Arguments are substituted prior to execution, making it possible for%name%
to be replaced with the name of the container that matches the pattern. - At second 45, the same happens, but this time through an external script file.
Arguments to the script file are substituted and passed further, then picked
up again in the file (implementation) as the
::argv
global Tcl variable.