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