Yesterday’s post provided a couple of minimal Docker images for spinning up containers to do Scala and Java builds and tests. The second of the images had a pre-loaded Ivy cache for Apache Spark’s dependencies installed in /root
. The setup I suggested for launching these images included mounting a directory from your host inside the container using Docker’s -v
option, but this is less than ideal: any files that are written or modified during a build or test run will be owned by root
instead of by whoever owned the directory on the host!
As I understand it, Docker will be able to map container users to host users in the future, but for now we can work around this problem with a quick hack. The docker run
command lets us pass environment variables that will be set inside the container, and we can use this to make sure that any files written in the container get owned by the right user on the host. Here’s what I did:
- I created another image based on my Spark development image, which I called
willb/java-dev:centos7-spark-uid
- This new image adds a normal user called
dockerdev
and copies the Ivy, Maven, andsbt
caches from/root
to that user’s home directory. - The new image runs a small script on container launch that fixes up the user ID and group ID of the
dockerdev
user and its home directory based on theDEV_UID
andDEV_GID
environment variables supplied todocker run
before substituting to thedockerdev
user and executing a shell.
So to launch a container for Spark development in which your ~/devel
directory is mapped to /devel
and in which all changes to that directory wind up owned by you on the host, you’d do something like this:
docker run --privileged=true -e DEV_UID=$UID -e DEV_GID=$GID -i -t -v ${HOME}/devel:/devel willb/java-dev:centos7-spark-uid
Again, this is a hack – use it at your own risk! –, but it’s useful until Docker supports user mapping more cleanly. I’m interested to hear about your approaches to solving this problem as well!
Appendix: boot.sh
, the user-mapping boot script
#!/bin/sh
export ORIGPASSWD=$(cat /etc/passwd | grep dockerdev)
export ORIG_UID=$(echo $ORIGPASSWD | cut -f3 -d:)
export ORIG_GID=$(echo $ORIGPASSWD | cut -f4 -d:)
export DEV_UID=${DEV_UID:=$ORIG_UID}
export DEV_GID=${DEV_GID:=$ORIG_GID}
ORIG_HOME=$(echo $ORIGPASSWD | cut -f6 -d:)
sed -i -e "s/:$ORIG_UID:$ORIG_GID:/:$DEV_UID:$DEV_GID:/" /etc/passwd
sed -i -e "s/dockerdev:x:$ORIG_GID:/dockerdev:x:$DEV_GID:/" /etc/group
chown -R ${DEV_UID}:${DEV_GID} ${ORIG_HOME}
exec su - dockerdev