Skip to content

Instantly share code, notes, and snippets.

@kousu
Created April 11, 2021 18:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kousu/e8cfb34a07540d53b8f6caf9f9d45e5e to your computer and use it in GitHub Desktop.
Save kousu/e8cfb34a07540d53b8f6caf9f9d45e5e to your computer and use it in GitHub Desktop.
dockerize for travis-ci

This is a wrapper around docker exec that makes sure to set up a matching user; it also has a pre-script hook. It's kind of janky but it was useful.

It's a lot like Microsoft's `wsl -- command'

Originally written as part of https://github.com/neuropoly/spinalcordtoolbox/blob/916ab591ca2e35cab9f5f27ec2439ce8fdb0b9d2/util/dockerize.sh but that project migrated to Github Actions.

We used it like this:

# if this is a docker job, run in the container instead; but if not just run it here.
if [ -n "${DOCKER_IMAGE:-}" ]; then
    ./util/dockerize.sh ./.ci.sh
elif [ "${TRAVIS_OS_NAME:-}" = "windows" ]; then
    choco install wsl-ubuntu-1804 -y --ignore-checksums
     # or, instead of choco, use curl + powershell:
     # https://docs.microsoft.com/en-us/windows/wsl/install-manual#downloading-distros-via-the-command-line
    # wsl --setdefault "Ubuntu-18.04"
     # TODO: Travis's version of wsl is too old for --setdefault.
     # Instead we trust that wsl will default to the installed
     # Ubuntu because it is the only option, but it would be
     # better to be explicit when it becomes possible.

    # disable apt's helpful (and build-breaking) interactive mode
    # https://linuxhint.com/debian_frontend_noninteractive/
    export DEBIAN_FRONTEND="noninteractive"
    # Use WSLENV to actually pass it into WSL
    # https://devblogs.microsoft.com/commandline/share-environment-vars-between-wsl-and-windows/
    export WSLENV=DEBIAN_FRONTEND

    wsl apt-get update
    #wsl apt-get -y upgrade  # this step is probably important, but it's also sooo slow
    wsl apt-get install -y gcc git curl
    wsl ./.ci.sh
else
    ./.ci.
#!/usr/bin/env bash
# dockerize.sh: run a script inside of another environment.
#
# usage: DOCKER_IMAGE="<image>" DOCKER_DEPS_CMD="<command to run before script>" dockerize.sh script.sh
# stricter shell mode
# https://sipb.mit.edu/doc/safe-shell/
set -eo pipefail # exit if non-zero error is encountered (even in a pipeline)
set -u # exit if unset variables used
shopt -s failglob # error if a glob doesn't find any files, instead of remaining unexpanded
CONTAINER=$(docker run \
--init \
-it -d \
--rm \
-v "`pwd`":/repo -w /repo \
"$DOCKER_IMAGE")
trap "docker stop "$CONTAINER"" EXIT
# set up a user:group matching that of the volume mount /repo, so the installer isn't confused
#
# TODO: it would be nice if the volume was mounted at `pwd`/, to further reduce the distinction
# between docker/nondocker runs, but docker gets the permissions wrong:
# it does `mkdir -p $mountpoint` *as root* so while the contents of the mountpoint are owned by
# $USER, its parents are owned by root, usually including /home/$USER which breaks things like pip.
# and there's no way to boot a container, `mkdir -p` manually, then attach the volume *after*.
docker exec "$CONTAINER" groupadd -g "`id -g`" "`id -g -n`"
docker exec "$CONTAINER" useradd -m -u "`id -u`" -g "`id -g`" "`id -u -n`"
# install platform-specific dependencies
if [ -n "$DOCKER_DEPS_CMD" ]; then
docker exec "$CONTAINER" sh -c "$DOCKER_DEPS_CMD"
fi
# recurse to run the real test script
# --user `id -u` makes sure the build script is the owner of the files at /repo
# TODO: pass through the Travis envs: https://docs.travis-ci.com/user/environment-variables/
docker exec --user "`id -u`":"`id -g`" "$CONTAINER" "$1"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment