Configuration
Configuration is done using a YAML file named .scuba.yml
in the root
directory of your project. It is expected that .scuba.yml
will be
checked-in to version control.
An example .scuba.yml
file might look like this:
image: gcc:5.1
aliases:
build: make -j4
In this example, running scuba build foo
would execute make -j4 foo
in
a gcc:5.1
Docker container.
Scuba YAML File Reference
.scuba.yml
is a YAML file which defines project-specific settings,
allowing a project to use Scuba as part of manual command-line interaction.
As with many other YAML file schemas, most options are controlled by top-level
keys.
Top-level keys
Key |
Scuba Version |
Description |
Alias |
---|---|---|---|
(all) |
Docker image to run |
Can override |
|
2.3.0 |
Environment variables |
Can extend or override |
|
2.8.0 |
Additional arguments to |
Can extend or override |
|
2.9.0 |
Additional volumes to mount |
Can extend or override |
|
1.1.0 |
Command/script aliases |
||
1.7.0 |
Hook scripts run during startup |
||
2.6.0 |
Override container shell path |
Can override |
|
2.4.0 |
Override container ENTRYPOINT path |
Can override |
image
The image
node defines the Docker image from which Scuba containers are
created.
Example:
image: debian:8.2
The image
node is usually necessary but, as of scuba 2.5, can be omitted
for .scuba.yml
files in which only the aliases
are intended to be used.
environment
The optional environment
node (added in v2.3.0) allows environment
variables to be specified. This can be either a mapping (dictionary), or a
list of KEY=VALUE
pairs. If a value is not specified, the value is taken
from the external environment.
Examples:
environment:
FOO: "This is foo"
SECRET:
environment:
- FOO=This is foo
- SECRET
docker_args
The optional docker_args
node (added in v2.8.0) allows additional docker
arguments to be specified.
Example:
docker_args: --privileged -v "/tmp/hello world:/tmp/hello world"
The value of docker_args
is parsed as shell command line arguments using
shlex.split.
The previous example could be equivalently written in YAML’s single-quoted style:
docker_args: '--privileged -v "/tmp/hello world:/tmp/hello world"'
volumes
The optional volumes
node (added in v2.9.0) allows additional
bind-mounts to be specified.
As of v2.13.0, named volumes
are also supported.
volumes
is a mapping (dictionary) where each key is the container-path.
In the simple form, the value is a string, which can be:
An absolute or relative path which results in a bind-mount.
A Docker volume name.
volumes:
/var/lib/foo: /host/foo # bind-mount: absolute path
/var/lib/bar: ./bar # bind-mount: path relative to .scuba.yml dir
/var/log: persist-logs # named volume
In the complex form, the value is a mapping with the following supported keys:
hostpath
: An absolute or relative path specifying a host bind-mount.name
: The name of a named Docker volume.options
: A comma-separated list of volume options.
hostpath
and name
are mutually-exclusive and one must be specified.
volumes:
/var/lib/foo:
hostpath: /host/foo # bind-mount
options: ro,cached
/var/log:
name: persist-logs # named volume
The paths (host or container) used in volume mappings can contain environment
variables which are expanded in the host environment. For example, this
configuration would map the user’s /home/username/.config/application1
directory into the container at the same path.
volumes:
$TEST_HOME/.config/application1: $TEST_HOME/.config/application1
If a referenced environment variable is not set, Scuba exits with a configuration error.
Volume container paths must be absolute.
Bind-mount host paths can be absolute or relative. If a relative path is used,
it is interpreted as relative to the directory in which .scuba.yml
is
found. To avoid ambiguity with a named volume, relative paths must start with
./
or ../
.
Bind-mount host directories which do not already exist are created as the current user before creating the container.
Note
Because variable expansion is now applied to all volume paths, if one
desires to use a literal $
character in a path, it must be written as
$$
.
Note
Docker named volumes are created with drwxr-xr-x
(0755) permissions.
If scuba is not run with --root
, the scuba user will be unable to write
to this directory. As a workaround, one can use a root hook to change permissions on the directory.
volumes:
/foo: foo-volume
hooks:
root: chmod 777 /foo
aliases
The optional aliases
node is a mapping (dictionary) of bash-like aliases,
where each key is an alias, and each value is the command that will be run when
that alias is specified as the user command during scuba invocation. The
command is parsed like a shell command-line, and additional user arguments from
the command line are appended to the alias arguments. Aliases follow the
common script schema.
Example:
aliases:
build: make -j4
In this example, $ scuba build foo
would execute make -j4 foo
in the
container.
Aliases can also extend/override various top-level keys. See Alias-level keys.
hooks
The optional hooks
node is a mapping (dictionary) of “hook” scripts that run
as part of scubainit
before running the user command. They use the
common script schema. The following hooks exist:
root
- Runs just beforescubainit
switches fromroot
toscubauser
user
- Runs just beforescubainit
executes the user command
Example:
hooks:
root:
script:
- 'echo "HOOK: This runs before we switch users"'
- id
user: 'echo "HOOK: After switching users, uid=$(id -u) gid=$(id -g)"'
shell
The optional shell
node (added in v2.6.0) allows the default shell that
Scuba uses in the container (/bin/sh
) to be overridden by another shell.
This is useful for images that do not have a shell located at /bin/sh
.
Example:
shell: /busybox/sh
entrypoint
The optional entrypoint
node (added in v2.4.0) allows the ENTRYPOINT
of the Docker image to be overridden:
entrypoint: /another/script
The entrypoint can also be set to null, which is useful when an image’s entrypoint is not suitable:
entrypoint:
Alias-level keys
Key |
Scuba Version |
Description |
---|---|---|
1.1.0 |
Override Docker image to run |
|
2.3.0 |
Extend / override environment variables |
|
2.8.0 |
Extend / override additional arguments to |
|
2.9.0 |
Extend / override additional volumes to mount |
|
2.6.0 |
Override container shell path |
|
2.4.0 |
Override container ENTRYPOINT path |
|
2.6.0 |
Run container as root |
image
Aliases can override the global image
, allowing aliases to use different
images. Example:
image: default_image
aliases:
# This one inherits the default, top-level 'image' and specifies "script" as a string
default:
script: cat /etc/os-release
# This one specifies a different image to use and specifies "script" as a list
different:
image: alpine
script:
- cat /etc/os-release
environment
Aliases can add to the top-level environment
and override its values using
the same syntax:
environment:
FOO: "Top-level"
aliases:
example:
environment:
FOO: "Override"
BAR: "New"
script:
- echo $FOO $BAR
docker_args
Aliases can extend the top-level docker_args
. The following example will
produce the docker arguments --privileged -v /tmp/bar:/tmp/bar
when
executing the example
alias:
docker_args: --privileged
aliases:
example:
docker_args: -v /tmp/bar:/tmp/bar
script:
- ls -l /tmp/
Aliases can also opt to override the top-level docker_args
, replacing it with
a new value. This is achieved with the !override
tag:
docker_args: -v /tmp/foo:/tmp/foo
aliases:
example:
docker_args: !override -v /tmp/bar:/tmp/bar
script:
- ls -l /tmp/
The content of the docker_args
key is re-parsed as YAML in order to allow
combining the !override
tag with other tags; however, this requires quoting
the value, since YAML forbids a plain-style scalar from beginning with a !
(see the spec). In the next
example, the top-level alias is replaced with an explicit !!null
tag, so
that no additional arguments are passed to docker when executing the example
alias:
docker_args: -v /tmp/foo:/tmp/foo
aliases:
example:
docker_args: !override '!!null'
script:
- ls -l /tmp/
volumes
Aliases can extend or override the top-level volumes
:
volumes:
/var/lib/foo: /host/foo
aliases:
example:
volumes:
/var/lib/foo: /example/foo
/var/lib/bar: /example/bar
script:
- ls -l /var/lib/foo /var/lib/bar
shell
Aliases can override the shell from the default or the top-level of
the .scuba.yml
file:
aliases:
my_shell:
shell: /bin/cool_shell
script:
- echo "This is executing in cool_shell"
busybox_shell:
script:
- echo "This is executing in scuba's default shell"
entrypoint
An alias can override the image-default or top-level .scuba.yml
entrypoint,
which is most useful when an alias defines a special image.
aliases:
build:
image: build/image:1.2
entrypoint:
root
The optional root
node (added in v2.6.0) allows an alias to specify
whether its container should be run as root:
aliases:
root_check:
root: true
script:
- echo 'Only root can do this!'
- echo "I am UID $(id -u)"
- cat /etc/shadow
Common script schema
Several parts of .scuba.yml
which define “scripts” use a common schema.
The common script schema can define a “script” in one of several forms:
The simple form is simply a single string value:
hooks:
user: echo hello
The complex form is a mapping, which must contain a script
subkey, whose
value is either single string value:
hooks:
root:
script: echo hello
… or a list of strings making up the script:
hooks:
root:
script:
- 'echo hello!'
- touch foo
- 'echo goodbye :-('
Note that in any case, YAML strings do not need to be enclosed in quotes, unless there are “confusing” characters (like a colon). In any case, it is always safer to include quotes.
Accessing external YAML content
In addition to normal YAML syntax, an additional constructor, !from_yaml
,
(added in v1.2.0) is available for use in .scuba.yml
which allows a value
to be retrieved from an external YAML file. It has the following syntax:
!from_yaml filename key
Arguments:
filename
- The path of an external YAML file (relative to.scuba.yaml
)key
- A dot-separated locator of the key to retrieve
This is useful for projects where a Docker image in which to build is already specified in another YAML file, for example in .gitlab-ci.yml. This eliminates the redundancy between the configuration files. An example which uses this:
image: gcc:5.1
image: !from_yaml .gitlab-ci.yml image
Here’s a more elaborate example which defines multiple aliases which correspond
to jobs defined by .gitlab-ci.yml
:
build_c:
image: gcc:5.1
script:
- make something
- make something-else
build_py:
image: python:3.7
script:
- setup.py bdist_wheel
# Note that 'image' is not necessary if only invoking aliases
aliases:
build_c:
image: !from_yaml .gitlab-ci.yml build_c.image
script: !from_yaml .gitlab-ci.yml build_c.script
build_py:
image: !from_yaml .gitlab-ci.yml build_py.image
script: !from_yaml .gitlab-ci.yml build_py.script
An easier but less-flexible method is to simply import the entire job’s
definition. This works becaue Scuba ignores unrecognized keys in an alias
:
aliases:
build_c: !from_yaml .gitlab-ci.yml build_c
build_py: !from_yaml .gitlab-ci.yml build_py
This example which concatenates two jobs from .gitlab-ci.yml
into a single
alias. This works by flattening the effective script
node that results by
including two elements that are lists.
image: gcc:5.1
part1:
script:
- make something
part2:
script:
- make something-else
image: !from_yaml .gitlab-ci.yml image
aliases:
all_parts:
script:
- !from_yaml .gitlab-ci.yml part1.script
- !from_yaml .gitlab-ci.yml part2.script
Dots (.
) in a YAML path can be escaped using a backslash (which must be
doubled inside of quotes). This example shows how to reference job names
containing a .
character:
image: gcc:5.1
.part1:
script:
- make something
.part2:
script:
- make something-else
image: !from_yaml .gitlab-ci.yml image
aliases:
build_part1: !from_yaml .gitlab-ci.yml "\\.part1.script"
build_part2: !from_yaml .gitlab-ci.yml "\\.part2.script"
Additional examples can be found in the example
directory.