Set current host user for docker container
Env: ubuntu 18.04, Docker 18.09.4, Docker-compose 1.23.2
TL;DR
I personally prefer to use docker-compose
to mount all host password related files to the container. See Method3.
Remember to substitute all variables with uppercase with angle bracket. i.e. <VAR>
Warning
If you ues non-user with the same uid as current host user and mount a host volume, it means the data inside host volume is visible by host and can be operated by both host user and user in container because both user have same authority. Please consider whether there is safty issue in your application.
Motivation
When developing inside a container, sometimes it is problematic that you create a file which will be owned by root and not able to be operated with host user, unless the host user runs the command with sudo privileges.
When operating files in the volume from container and host, it often results in some problems due to ownership of files.
Method 1: Run directly from an image
In this method, we mount/overwrite the files related to password and user accounts from host to container.
Pros:
- No extra work to change the existing system or images
- The image is independent to user id
means, the image is valid for everyone.
Cons:
- No colorful output bash prompt if
.bashrc
is not in workdir
Since you didn’t create a user inside the image if you don’t mount your home directory as workdir inside the container, there will be no.bashrc
file, which results in mono bash prompt. Or you can add the bash script to enable colorful prompt. Link - Long command line
export UID=$(id -u)
export GID=$(id -g)
docker run -it \
--user $UID:$GID \
--workdir="/home/$USER" \
--volume="/etc/group:/etc/group:ro" \
--volume="/etc/passwd:/etc/passwd:ro" \
--volume="/etc/shadow:/etc/shadow:ro" \
<IMAGE NAME> /bin/bash
ps. It might show that UID is a read-only variable. You can neglect it.
Method 2: Add user in Docker Image
In this method we install and add a new user to sudo and pass the arguments from command line when building the docker image.
Pros:
- Colorful bash prompt
sinceadduser -m
created a home directory, there is a.bashrc
in it.
Cons:
- The image is dependent on user id
means, this image only works for users who have the same uid on different hosts. i.e. person_A has user id 1000. Person_B with user id other than 1000, for instance 1001, cannot use the image built by person_A. - Default password argument is not encrypted.
Or instead of usinguseradd
, directlyCOPY
files related to password and user accounts into the image [Not tested]
Step1: Create Dockerfile
# Dockerfile
ARG DOCKER_BASE_IMAGE=<BASE IMAGE NAME>
FROM $DOCKER_BASE_IMAGE
ARG USER=docker
ARG UID=1000
ARG GID=1000
# default password for user
ARG PW=docker# Option1: Using unencrypted password/ specifying password
RUN useradd -m ${USER} --uid=${UID} && echo "${USER}:${PW}" | \
chpasswd# Option2: Using the same encrypted password as host
#COPY /etc/group /etc/group
#COPY /etc/passwd /etc/passwd
#COPY /etc/shadow /etc/shadow# Setup default user, when enter docker container
USER ${UID}:${GID}
WORKDIR /home/${USER}
Step2: Build Image
# bash
export UID=$(id -u)
export GID=$(id -g)
docker build --build-arg USER=$USER \
--build-arg UID=$UID \
--build-arg GID=$GID \
--build-arg PW=<PASSWORD IN CONTAINER> \
-t <IMAGE NAME> \
-f <DOCKERFILE NAME>\
.
Step3: Enter container
with the host user when building the imagedocker exec -it <IMAGE NAME> /bin/bash
with rootdocker exec --user root --workdir /root -it <IMAGE NAME> /bin/bash
Method 3: Docker-compose
Pros:
- Easy command line
- No extra work to change the existing system or images
- The image is independent to user id
Cons:
- No colorful output bash prompt if
.bashrc
is not in workdir
Need to create.bashrc
(Link) workdir in an image or mount the.bashrc
In the example, host user’s home directory is mounted, so we still get colorful prompt.
Step1: Create docker-compose.yml
# docker-compose.yml
version: '3'
services:
<SERVICE NAME>:
image: <BASE IMAGE NAME>
user: $UID:$GID
working_dir: $HOME
stdin_open: true
volumes:
- /etc/group:/etc/group:ro
- /etc/passwd:/etc/passwd:ro
- /etc/shadow:/etc/shadow:ro
tty: true
command: tail -f /dev/null
Step2: Start container
export UID=$(id -u)
export GID=$(id -g)
docker-compose -f docker-compose.yml up <SERVICE NAME>
Step3: Enter container
The command is the same as the one in method 2.
Extra: Grant user sudo privileges
Since the characteristic of containerization is clean environment, installing packages or some other action that required sudo privileges should be avoided. If it’s a permanent change, you should add command in Dockerfile and rebuild the image.
But if you are lazy or confident that you can keep the consistency between the image and current container, please see the below.
ps. Known issue with sudo with tty, docker actually suggests using gosu (Link)
Step1: Append the following to Dockerfile and build the image
RUN apt-get update && apt-get install -y sudo && \
adduser ${USER} sudo
Step2.1: Mount extra volume, when start container with docker run
--volume="/etc/sudoers.d:/etc/sudoers.d:ro"
Or
Step2.2: Add the last line under the volume tag in the docker-compose file
volumnes:
- ...
- ...
- /etc/sudoers.d:/etc/sudoers.d:ro
References
http://wiki.ros.org/docker/Tutorials/GUI
Running docker containers as current host user
Running a Docker container as a non-root user
specifying user and group in docker-i2e
How-to-use-sudo-inside-a-docker-container
SSH into container
But not suitable for ROS developer, since the communication between nodes is based on randomly assigned ports. Therefore, the network_mode of container should be host, which allow container to use the network from host. Therefore, it is not possible to redirect container’s port 22 to host port 2222, for example.(Link)
Which ports are needed for ROS
Follow us on Twitter 🐦 and Facebook 👥 and join our Facebook Group 💬.
To join our community Slack 🗣️ and read our weekly Faun topics 🗞️, click here⬇