dow.sh

A multi-user Docker Compose wrapper that creates and reuses per-user containers from a single host.

5 min read Updated

dow.sh is a small Docker Compose wrapper that lets several users share one host: each invocation resolves the calling user, creates or reuses a per-user container and runs the requested command inside it. It is useful on development machines where people need isolated environments without editing Compose files by hand. The full script is reproduced below.

A basic docker-compose with multi user accounts support

dow.sh

bash
#!/bin/sh

#
## Author: Sébastien Demanou
## Source: https://gitlab.com/snippets/1730907.js

binary=$(basename $0)

usage() {
  echo "$binary - Docker Wrapper SH"
  echo ""
  echo "Usage: $binary [OPTIONS] COMMAND"
  echo ""
  echo "  Commands:"
  echo "    start                     Start the container"
  echo "    stop                      Stop the container"
  echo "    restart                   Restart the container"
  echo "    delete                    Delete the container"
  echo "    list                      List containers"
  echo ""
  echo "    NOTE: By default, commands are launched in debug environment."
  echo "          To run a command in the release environment, add the '-r'"
  echo "          option as prefix: $binary -r make bin"
  echo ""
  echo "  Options:"
  echo "    --help                    Print usage"
  echo "    --path string             Set the Dockerfile's path"
  echo "    -d, --dns list            Set custom DNS servers. Default: $DNS"
  echo "    -i, --image string        Set the image name. Default: $IMAGE"
  echo "    -h, --hostname string     Set the container hostname"
  echo "    -n, --name string         Assign a name to the container"
  echo "    -p, --project string      Set the project name"
  echo "    -r, --release             Run command to the release environment"
  echo "    -u, --user string         Container's username. Default: \$USER"
  echo "    -w, --workdir string      Working directory inside the container. Default \$(pwd)"
  echo ""
  echo "  Start the debug environment:"
  echo "    $ $binary start"
  echo ""
  echo "  Start the release environment:"
  echo "    $ $binary -r start"
  echo ""
  echo "  Launch the container's bash:"
  echo "    $ $binary bash"
  echo ""
  echo "  Init (done once):"
  echo "    $ $binary make clean"
  echo "    $ $binary make external"
  echo ""
  echo "  Build in debug mode:"
  echo "    $ $binary make bin"
  echo ""
  echo "  Build in release mode:"
  echo "    $ $binary -r make bin"
  echo ""
  echo "  Package sources:"
  echo "    $ $binary make source"
  echo ""
  echo "  Package binaries:"
  echo "    $ $binary make pkg"
  echo ""
}

homedir() {
  echo "/home/$DUSER"
}

image_exist() {
  res=$(docker images -q $IMAGE 2> /dev/null)

  if [ "$res" = '' ]; then
    echo 'false'
  else
    echo 'true'
  fi
}

image_build() {
  echo -n "Building the Docker image $IMAGE... "

  docker build -t $IMAGE $DOCKER_PATH \
    && echo "done"
}

container_create() {
  echo -n "Creating container $(container_name)... "

  docker run -d -it \
    --name $(container_name) \
    --dns=$DNS \
    --hostname $(container_hostname) \
    --env DEBUG=$DEBUG_VALUE \
    --volume $(pwd):$(container_workdir) \
    --workdir $(container_workdir) $IMAGE > /dev/null \
    && echo "done"
}

container_create_user() {
  echo -n "Creating user $DUSER... "

  docker exec $(container_name) useradd $DUSER
  docker cp $DOCKER_PATH/.bash_profile $(container_name):$(homedir)/
  docker cp $DOCKER_PATH/.bashrc $(container_name):$(homedir)/
  docker cp $DOCKER_PATH/.inputrc $(container_name):$(homedir)/

  echo "done"
}

container_start() {
  echo -n "Starting $(container_name)... "

  docker start $(container_name) > /dev/null \
    && echo "done"
}

container_exist() {
  res=$(docker inspect -f {{.Id}} $(container_name) 2> /dev/null)

  if [ "$res" = '' ]; then
    echo 'false'
  else
    echo 'true'
  fi
}

container_is_stopped() {
  res=$(docker inspect -f {{.State.Status}} $(container_name) 2> /dev/null)

  if [ "$res" = 'exited' ]; then
    echo 'true'
  else
    echo 'false'
  fi
}

container_init() {
  if [ $(image_exist) = 'false' ]; then
    image_build
  fi

  if [ $(container_exist) = 'false' ]; then
    container_create && container_create_user 2> /dev/null
  else
    if [ $(container_is_stopped) = 'true' ]; then
      container_start
    fi
  fi
}

container_stop() {
  if [ $(container_is_stopped) = 'false' ]; then
    echo -n "Stopping $(container_name)... "

    docker stop $(container_name) > /dev/null \
      && echo "done"
  fi
}

container_rm() {
  echo -n "Deleting $(container_name)... "

  docker rm $(container_name) > /dev/null \
    && echo "done"
}

container_name() {
  if [ "$CONTAINER_NAME" = '' ]; then
    echo "$DUSER-$PROJECT-$MODE"
  else
    echo $CONTAINER_NAME
  fi
}

container_hostname() {
  if [ "$HOSTNAME" = '' ]; then
    container_name
  else
    echo $HOSTNAME
  fi
}

container_workdir() {
  echo "$(homedir)/$PROJECT"
}

display_containers() {
  docker ps -a
}

docker_exec() {
  docker exec -it --user $DUSER $(container_name) $@
}

DOCKER_PATH="docker-files"
IMAGE="centos:mq"
MODE="debug"
DEBUG_VALUE="true"
pwd=$(pwd)
PROJECT=$(basename $pwd)
CONTAINER_NAME=""
HOSTNAME=""
DUSER=$USER
DNS="10.55.35.248"

while [ "$1" != "" ]; do
  case $1 in
    --path )
      shift
      DOCKER_PATH=$1
      shift
      ;;
    -d | --dns )
      shift
      DNS=$1
      shift
      ;;
    -h | --hostname )
      shift
      HOSTNAME=$1
      shift
      ;;
    -i | --image )
      shift
      IMAGE=$1
      shift
      ;;
    -n | --name )
      shift
      CONTAINER_NAME=$1
      shift
      ;;
    -p | --project )
      shift
      PROJECT=$1
      shift
      ;;
    -r | --release )
      shift
      MODE="release"
      DEBUG_VALUE="false"
      ;;
    -u | --user )
      shift
      DUSER=$1
      shift
      ;;
    start )
      container_init
      exit
      ;;
    stop )
      if [ $(container_is_stopped) = 'false' ]; then
        container_stop
      fi
      exit
      ;;
    restart )
      if [ $(container_is_stopped) = 'false' ]; then
        container_stop && container_init
      else
        container_init
      fi
      exit
      ;;
    list )
      display_containers
      exit
      ;;
    delete )
      if [ $(container_is_stopped) = 'true' ]; then
        container_rm
      fi
      exit
      ;;
    --help )
      usage
      exit
      ;;
    * )
      docker_exec $@
      exit
  esac
done

usage
exit 1

Search articles

Type to filter articles. Use the arrow keys to move through results and Enter to open one. Press Escape to close.