Skip to content

Instantly share code, notes, and snippets.



Last active Jul 9, 2020
What would you like to do?
bootstrap (bs) run (vcs-run)

Docker ubuntu containers are pretty useless by themselves. The expectation is that the user will create a DockerFile and build their own image and push that image somewhere and maintain it.

In 2013 I authored vcs-run as part of cloud-utils. It is installed by default in ubuntu server images, but not in the docker images. :-(. The idea of vcs-run is that you can just invoke something like:

vcs-run https://your.git.server/repo.git bootstrap your-args-here

vcs-run would handle:

  • installing git
  • cloning repo
  • change dir to repo
  • executing bootstrap with your-args-here

Well, since there is nothing inside the ubuntu:20.04 docker image that can do that, we'll have to put it all into the cmdline of shell. Successfully providing complex command lines to a container can be difficult. So to work around bugs in "helpful" infrastructure parsing of string fields into arrays, 'stuffit' here will output a somewhat simple command and uses an environment variable to actually carry the payload. Stuffit then has the following dependencies on an image:

  • apt-get - for getting 'wget' and ca-certificates if not present. (this is actually a dependency of 'bs')
  • base64 - for decoding BS_BLOB
  • sh

So here is how you can enable a ubuntu:20.04 image to do the famous curl | bash bootstrap mechanism.

$ ./stuffit
sh -c 'p=$(echo $BS_BLOB | base64 --decode) && exec sh -c "$p" bsblob "$@"'

Now, to run that in docker:

$ docker run \
    --env=BS_URL= \
    --env=BS_BLOB=Y29tbWFuZCAtdiB3Z2V0ID4vZGV2L251bGwgMj4mMSB8fCB7CiAgYXB0LWdldCB1cGRhdGUgLXEgJiYKICBERUJJQU5fRlJPTlRFTkQ9bm9uaW50ZXJhY3RpdmUgXAogICAgYXB0LWdldCBpbnN0YWxsIC15IC0tbm8taW5zdGFsbC1yZWNvbW1lbmRzIHdnZXQgY2EtY2VydGlmaWNhdGVzOwp9IHx8IGV4aXQ7CmV4cG9ydCBCU19GSUxFPSR7QlNfRklMRTotL3J1bi9ic307ClsgLXogIiRCU19VUkwiIC1hICQjIC1nZSAxIF0gJiYgeyBCU19VUkw9IiQxIjsgc2hpZnQ7IH0Kd2dldCAiJEJTX1VSTCIgLU8gIiRCU19GSUxFIgpjaG1vZCA3NTUgIiRCU19GSUxFIgpleGVjICIkQlNfRklMRSIgIiRAIgo= \
    ubuntu:20.04 \
    sh -c 'p=$(echo $BS_BLOB | base64 --decode) && exec sh -c "$p" bsblob "$@"'


I'm able to successfully run a container in rancher using this mechanism. I had problems getting the 'command' to take multiple arguments with double or single quotes. I think it tries to parse them or pass them to sh, but I have not figure out the pattern.

So, just use the 'sh -c' line of 'stuffit' output as above, and then fill in Environment variables BS_URL and BS_BLOB.

sh -c 'p=$(echo $BS_BLOB | base64 --decode) && exec sh -c "$p" bsblob "$@"'
command -v wget >/dev/null 2>&1 || {
apt-get update -q &&
DEBIAN_FRONTEND=noninteractive \
apt-get install -y --no-install-recommends wget ca-certificates;
} || exit;
export BS_FILE=${BS_FILE:-/run/bs};
[ -z "$BS_URL" -a $# -ge 1 ] && { BS_URL="$1"; shift; }
wget "$BS_URL" -O "$BS_FILE" || exit
chmod 755 "$BS_FILE"
exec "$BS_FILE" "$@"
msg() {
echo "$@"
echo "$@" >> "$LOG"
: > "$LOG"
msg "HELLO WORLD. I'm up, and am pid $$"
msg "sleeping now for 1d. further output in $LOG."
set -x
exec sleep 1d >>"$LOG" 2>&1
fail() { echo "$@" 1>&2; exit 1; }
[ $# -eq 0 ] || shift
b64=$(base64 --wrap=0 "$bsfile") ||
fail "failed base64 encode $bsfile"
shcode='p=$(echo $BS_BLOB | base64 --decode) && exec sh -c "$p" bsblob "$@"'
if [ -n "$#" ]; then
ptargs=$(getopt --shell sh --options "" -- -- "$@")
ptargs=${ptargs# -- }
[ -n "$bsurl" ] && printf "BS_URL=%s\n" "$bsurl"
printf "BS_BLOB=%s\n" "$b64"
if [ -z "$ptargs" ]; then
printf "sh -c '%s' bsarg0 %s\n" "$shcode"
printf "sh -c '%s' bsarg0 %s\n" "$shcode" "$ptargs"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment