15 Jan 2018 - tags:
I often use Docker to try out software in an isolated environment without ‘polluting’ my workstation with the installation of dependencies. It is also very useful to bundle dependencies for a certain project in a Docker image, e.g. the compiler tool chain for the latest single board computer.
In the following I describe a very trivial example: Instead of installing the zip
package on my Ubuntu workstation, I decide to create a Docker container image base on the latest Debian version that has zip
installed.
First we need a Dockerfile
:
FROM debian
RUN apt update && apt install -y zip sudo
Now run docker build
in the directory of the Dockerfile
:
docker build -t zipper .
So, to create a zip archive that contains all the file in let’s say $HOME/Pictures
we can run
docker run --rm -it -v $HOME/Pictures:/Pictures -v $PWD:/work -w /work \
zipper \
bash -c 'zip pictures.zip /Pictures/*'
This leaves us with the archive file pictures.zip
in the current directory:
-rw-r--r-- 1 root root 2578830 Jan 15 10:24 pictures.zip
But what’s that? The file is owned by root. To change that we have to tell Docker to run the container with your current users UID/GUID:
docker run --rm -it -v $HOME/Pictures:/Pictures -v $PWD:/work -w /work \
-u $(id -u):$(id -g) \
zipper \
bash -c 'zip pictures2.zip /Pictures/*'
This time pictures2.zip
is owned by the current user:
-rw-r--r-- 1 alex alex 2578830 Jan 15 10:30 pictures2.zip
As part of an automated build process there are often scripts that run inside of a Docker container.
They need to produce files that are accessible by the current workstation user, but in addition need to acquire super-user rights for certain tasks.
That’s where the sudo
command comes in. However, simply running the trivial example
docker run --rm -it -v $HOME/Pictures:/Pictures -v $PWD:/work -w /work \
-u $(id -u):$(id -g) \
zipper \
sudo bash -c 'zip shadow.zip /etc/shadow'
gives the error message:
sudo: unknown uid 1000: who are you?
Let’s fix that! We need to pass in your workstation’s /etc/password
and /etc/group
into our container environment:
docker run --rm -it -v $HOME/Pictures:/Pictures \
-v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/groupd:ro \
-v $PWD:/work -w /work -u $(id -u):$(id -g) zipper \
sudo bash -c 'zip shadow.zip /etc/shadow'
Now we are one step further, and sudo asks us for our password:
We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:
#1) Respect the privacy of others.
#2) Think before you type.
#3) With great power comes great responsibility.
[sudo] password for alex:
However, even if you entered your workstation user’s password you won’t get access because we haven’t passed in /etc/shadow
into our container.
Anyway, manually entering a password in an automated build script is probably not what you want.
Therefore, we setup sudo to work passwordless (only inside our container, of course) by first creating a sudoers
file in the current directory with the follwing content:
ALL ALL = (ALL) NOPASSWD: ALL
Now this file needs to be owned by root. On your workstation type:
sudo chown root:root sudoers
And finally, we pass in our passwordless sudoers
file and try again:
docker run --rm -it -v $HOME/Pictures:/Pictures \
-v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/groupd:ro \
-v $PWD/sudoers:/etc/sudoers
-v $PWD:/work -w /work -u $(id -u):$(id -g) zipper \
sudo bash -c 'zip shadow.zip /etc/shadow'
Et voilà! It works.
I admit, on first sight my example appears pointless: we are first changing to a less privileged user to run our container only to acquire super-user rights later on. However, in more advanced examples, e.g. building Debian packages for a different architecture in a Docker container this can be really useful.