Dockerfile replicate the host user UID and GID to the image - docker

Similar to the SO post about replicating UID/GID in container from host but how do you build the image with a user with replicate UID and GID? Preferably, how do you do it with a dockerfile?
I can do it with a bash script:
#!/bin/bash
# current uid and gid
curr_uid=`id -u`
curr_gid=`id -g`
# create bb.dockerfile:
cat << EOF1 > bb.dockerfile
FROM ubuntu:xenial-20170214
ARG UNAME=testuser
EOF1
echo ARG UID=${curr_uid} >> bb.dockerfile
echo ARG GID=${curr_gid} >> bb.dockerfile
cat << EOF2 >> bb.dockerfile
RUN groupadd -g \$GID \$UNAME
RUN useradd -m -u \$UID -g \$GID -s /bin/bash \$UNAME
USER \$UNAME
CMD /bin/bash
EOF2
docker build -f bb.dockerfile -t testimg .
This bash will generate a docker file as the following and build on it.
FROM ubuntu:xenial-20170214
ARG UNAME=testuser
ARG UID=1982
ARG GID=1982
RUN groupadd -g $GID $UNAME
RUN useradd -m -u $UID -g $GID -s /bin/bash $UNAME
USER $UNAME
CMD /bin/bash
What I'm asking for, is to remove the hardcoded host UID 1982 and GID 1982 from the dockerfile.

You can pass it as a build arg. Your Dockerfile can be static:
FROM ubuntu:xenial-20170214
ARG UNAME=testuser
ARG UID=1000
ARG GID=1000
RUN groupadd -g $GID -o $UNAME
RUN useradd -m -u $UID -g $GID -o -s /bin/bash $UNAME
USER $UNAME
CMD /bin/bash
Then you'd pass the options on your build command:
docker build --build-arg UID=$(id -u) --build-arg GID=$(id -g) \
-f bb.dockerfile -t testimg .
Note that I've solved similar problems to this a different way, by running an entrypoint as root that looks a file/directory permissions of the host volume mount, and adjust the uid/gid of the users inside the container to match the volume uid/gid. After making that change, it drops access from the root user to the modified uid/gid user and runs the original command/entrypoint. The result is the image can be run unchanged on any developer machine. An example of this can be found in my jenkins-docker repo:
https://github.com/sudo-bmitch/jenkins-docker

Eventually the bb.bash looks like:
#!/bin/bash
# current uid and gid
curr_uid=`id -u`
curr_gid=`id -g`
# create bb.dockerfile:
cat << EOF2 > bb.dockerfile
FROM ubuntu:xenial-20180417
ARG UNAME=testuser
ARG UID=1000
ARG GID=1000
RUN groupadd -g \$GID \$UNAME
RUN useradd -m -u \$UID -g \$GID -s /bin/bash \$UNAME
USER \$UNAME
CMD /bin/bash
EOF2
docker build --build-arg UID=${curr_uid} --build-arg GID=${curr_gid} \
-f bb.dockerfile -t testimg .
Then another script is to create the container:
#!/bin/bash
docker run -it -d -v $(pwd)/shared:/home/testuser/shared \
--name testcontainer -P testimg

Related

Permission Denied on "docker compose exec --user alice app /bin/bash"

In my Dockerfile, I create a user, "alice" (generic name that isn't industry-specific) with a home directory. Alice has /home/.bashrc and root has /root/.bashrc (which all users can read - chmod a+r /root/bashrc).
I can run docker compose exec app /bin/bash and access the app container's command line as the root user. I can then su alice and have full access to the container as Alice.
However, if I run docker compose exec --user alice app /bin/bash, I get "bash: /root/.bashrc: Permission denied" followed by the "alice#sha:working/directory" cli prompt. ls ~/ gives the error: "ls: cannot open directory '/root/': Permission denied".
My docker-compose.yml file (abridged):
services:
app:
build:
context: ./docker/app
dockerfile: Dockerfile
args:
- HOST_GID=${HOST_GID}
- HOST_UID=${HOST_UID}
volumes:
${full_source_path}:/var/www/html
...
env_file: .env
My Dockerfile (abridged):
FROM --platform=$BUILDPLATFORM php:7.1-apache
# Set up Apache
RUN a2enmod rewrite
# UID & GID are passed in to use the same UID/GID as the host user's user account
ARG HOST_UID
ARG HOST_GID
RUN echo "Creating alice" && \
groupadd \
--force \
--gid ${HOST_GID} \
alice && \
sync && \
useradd \
--no-log-init \
--uid ${HOST_UID} \
--gid ${HOST_GID} \
--create-home \
--shell /bin/bash \
alice \
&& \
sync && \
echo "DONE"
# copy externally created files, including .bashrc, into /home/alice/
...
RUN chmod a+r /root/.bashrc
RUN chmod a+r /home/alice/.bashrc
RUN echo "Finalizing" && \
chown -R alice:alice /home/alice/ && \
echo "DONE"
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
# Persist cached writes
RUN sync
WORKDIR /var/www/html
ENTRYPOINT ["/entrypoint.sh"]
My entrypoint.sh file:
#!/usr/bin/env bash
set -e
echo "Starting Apache"
exec apache2-foreground
echo "Container Ready"
sleep infinity
My host:
MacOS 12.4
Docker Desktop 4.10.1

Dockerfile, groupadd with GUI parameter

I am trying to add group with id declared in dockerfile, however I always get error:
groups: cannot find name for group ID 1001
My dockerfile:
FROM python:3.7.1
ARG UID=1001
RUN apt-get update && apt-get install -y openssh-server sudo
RUN mkdir /var/run/sshd
RUN echo 'root:pycharm' | chpasswd
RUN sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
RUN sed 's#session\s*required\s*pam_loginuid.so#session optional pam_loginuid.so#g' -i /etc/pam.d/sshd
RUN groupadd -r charm -g 1001
RUN useradd -ms /bin/bash charm -g charm -u 1001
RUN echo "export VISIBLE=now" >> /etc/profile
ADD helpers /opt/.pycharm_helpers
EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]
Error message I get when I try to enter container with:
docker exec -ti -u 1001 pydebug1 bash
Group doesn't exists in /etc/group file. When I run commands inside container then works but I want to have them inside Dockerfile.
Saved your dockerfile content in Dockerfile and touched a file with name helpers.
Then build the image and enter into the image. Screen shot shows 2nd build, commit hash etc and id from the image. You can see all the commands in screen shot.
You may build as docker build -t pydebug1 . as well.

Dockerfile overriding env var at "docker run" time

Dockerfile
FROM ubuntu
ENV UID "1234"
ENV USERNAME "default"
RUN addgroup $USERNAME && useradd -u $UID -g $USERNAME -ms /bin/bash $USERNAME
CMD ["/usr/bin/id", "-u", "myname"]
and running docker via:
docker build -t setuser .
docker run -e UID=5555 -e USERNAME=myname setuser
OUTPUT
/usr/bin/id: 'myname': no such user
this error tells me that useradd in Dockerfile was not executed during "docker run" time.
how could I achieve this?
CMD ["/usr/bin/id", "-u", "default"] works but i want to be able to supply the UID and USERNAME at run time, not at Dockerfile build time
To elaborate Henry's answer
Following portion of your Dockerfile executed when you build your image.
FROM ubuntu
ENV UID "1234"
ENV USERNAME "default"
RUN addgroup $USERNAME && useradd -u $UID -g $USERNAME -ms /bin/bash $USERNAME
So, this time, UID=1234 & USERNAME=default are set.
When you run your image, It starts with ENTRYPOINT & CMD. It has no effect on RUN addgroup $USERNAME ...
So you need to run a script to use your passing ENV.
#!/bin/bash
addgroup $USERNAME && useradd -u $UID -g $USERNAME -ms /bin/bash $USERNAME
id -u $USERNAME
Here, your passing ENV values will be used.
The useradd was executed when the image was created. If you want to run some commands when the container is started put them into a script that is executed at start time.

How to add user with dockerfile?

How can I add a user with Dockerfile - the following does not work.
USER vault
WORKDIR /usr/local/bin/vault
My full Dockerfile:
FROM alpine:3.4
RUN apk update && apk add curl unzip
RUN useradd -ms /bin/bash vault
USER vault
WORKDIR /usr/local/bin/vault
ADD /vault.hcl /etc/vault/vault.hcl
RUN curl -SL https://releases.hashicorp.com/vault/0.5.0/vault_0.5.0_linux_amd64.zip > vault.zip
RUN unzip vault.zip -d /usr/local/bin && rm vault.zip
Use useradd instead of its interactive adduser to add user.
RUN useradd -ms /bin/bash vault
Below command will not create user .
USER vault
WORKDIR /usr/local/bin/vault
it will use vault user
please Refer Dockerfile User Documentation
The USER instruction sets the user name or UID to use when running the
image and for any RUN, CMD and ENTRYPOINT instructions that follow it
in the Dockerfile.
NOTE : Ensures that bash is the default shell.
If default shell is /bin/sh you can do like:
RUN ln -sf /bin/bash /bin/sh
RUN useradd -ms /bin/bash vault
To add group and to associate a new user, use code below.
FROM <base image>
RUN groupadd -g 2000 go \
&& useradd -m -u 2001 -g go go
USER go
OR
RUN addgroup -g 1001 -S appuser && adduser -u 1001 -S appuser -G appuser
If you also want your user to have a password, use this for Alpine based-images:
FROM alpine
ARG USER=usernameThatYouWant
ARG PASS="some password"
RUN adduser -D $USER && echo "$USER:$PASS" | chpasswd
The ARG lines are there so you can (optionally) choose another username and password when building the image (without having to change the Dockerfile).
-D so that adduser doesn't set a password just yet.Without this option adduser would become interactive and ask for a password. It doesn't accept this from the regular STDIN, so piping the password is also not an option.
echo "$USER:$PASS" | chpasswd to finally set the password.
Note that I do not set a shell with -s /path/to/some/shell in adduser because Alpine only has ash and sh available. Both of these are just symlinks to busybox anyway.(But if you are going to install another shell in your image you probably do want to use it.)
For Ubuntu-based images use this:
FROM ubuntu
ARG USER=usernameThatYouWant
ARG PASS="some password"
RUN useradd -m -s /bin/bash $USER && echo "$USER:$PASS" | chpasswd
I am using:
useradd because here this is the program for non-interactive usage.
-m so that we the user has a homedir.
-s /bin/bash so that the user has bash as default shell.
(For most other base-images you will also need to use the Ubuntu-method )

Run docker with jenkins user inside jenkins container on Centos7

I try to run Docker inside my Jenkins slave container on Centos7.1.
This are the steps I performed in my dockerfile:
FROM java:8
ARG user=jenkins
ARG group=jenkins
ARG uid=1000
ARG gid=1000
RUN groupadd -g ${gid} ${group} \
&& useradd -d "$JENKINS_HOME" -u ${uid} -g ${gid} -m -s /bin/bash ${user}
RUN groupadd -g 983 docker \
&& gpasswd -a ${user} docker
So I have a user jenkins (id1000) in a group jenkins (gid1000) + in a group docker (gid983). Why did I chose gid 983?
Well if I check /etc/group on my host I see:
docker:x:983:centos
In my docker-compose script I'm mounting my docker socket so that's why I used the same gid as on my host.
Part of docker-compose:
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /usr/bin/docker:/usr/bin/docker
When I exec inside my container as root:
root#c4af16c386d7:/var/jenkins_home# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
jenkins-slave 1.0 94a5d6606f86 10 minutes
jenkins 2.7.1 b4974ba62598 3 weeks ago 741 MB
java 8-jdk 264282a59a95 7 weeks ago 669.2 MB
But as jenkins user:
Cannot connect to the Docker daemon. Is the docker daemon running on this host?
In my container:
cat /etc/passwd
jenkins:x:1000:1000::/var/jenkins_home:/bin/bash
cat /etc/group
jenkins:x:1000:
docker:x:983:jenkins
Addition:
$ docker exec -it ec52d4125a02 bash
root#ec52d4125a02:/var/jenkins_home# whoami
root
root#ec52d4125a02:/var/jenkins_home# su jenkins
jenkins#ec52d4125a02:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a23521523249 jenkins:2.7.1 "/bin/tini -- /usr/lo" 20 minutes ago Up 20 minutes 0.0.0.0:8080->8080/tcp, 0.0.0.0:32777->22/tcp, 0.0.0.0:32776->50000/tcp jenkins-master
ec52d4125a02 jenkins-slave:1.0 "setup-sshd" 20 minutes ago Up 20 minutes 0.0.0.0:32775->22/tcp, 0.0.0.0:32774->8080/tcp, 0.0.0.0:32773->50000/tcp jenkins-slave
but:
$ docker exec -it -u jenkins ec52d4125a02 bash
jenkins#ec52d4125a02:~$ docker ps
Cannot connect to the Docker daemon. Is the docker daemon running on this host?
In the first case my jenkins user:
uid=1000(jenkins) gid=1000(jenkins) groups=1000(jenkins),983(docker)
In the second case:
uid=1000(jenkins) gid=1000(jenkins) groups=1000(jenkins)
First, why do you need to spin containers from inside another with Jenkins? Here's why this is not a good idea.
Having that said and you still want to go ahead. First thing is that there are several steps you need to take to run Docker inside a Docker container. For example, have you started this container in --priviledged mode?
You should try using Jerome Petazzoni's Docker in Docker as it does everything you need.
You can then combine DInD's stuff with a Jenkins installation. Here's an example that I've put together by mashing up Jerome's DInD with other things and assembling a docker container that has Jenkins, Docker Compose and other useful stuff:
Dockerfile:
FROM ubuntu:xenial
ENV UBUNTU_FLAVOR xenial
#== Ubuntu flavors - common
RUN echo "deb http://archive.ubuntu.com/ubuntu ${UBUNTU_FLAVOR} main universe\n" > /etc/apt/sources.list \
&& echo "deb http://archive.ubuntu.com/ubuntu ${UBUNTU_FLAVOR}-updates main universe\n" >> /etc/apt/sources.list
MAINTAINER Rogério Peixoto
ENV JENKINS_HOME /var/jenkins_home
ENV JENKINS_SLAVE_AGENT_PORT 50000
ARG user=jenkins
ARG group=jenkins
ARG uid=1000
ARG gid=1000
# Jenkins is run with user `jenkins`, uid = 1000
# If you bind mount a volume from the host or a data container,
# ensure you use the same uid
RUN groupadd -g ${gid} ${group} \
&& useradd -d "$JENKINS_HOME" -u ${uid} -g ${gid} -m -s /bin/bash ${user}
# useful stuff.
RUN apt-get update -q && apt-get install -qy \
apt-transport-https \
ca-certificates \
curl \
lxc \
supervisor \
zip \
git \
iptables \
locales \
nano \
make \
openssh-client \
openjdk-8-jdk-headless \
&& rm -rf /var/lib/apt/lists/*
# Install Docker from Docker Inc. repositories.
RUN curl -sSL https://get.docker.com/ | sh
# Install the wrapper script from https://raw.githubusercontent.com/docker/docker/master/hack/dind.
ADD ./wrapdocker /usr/local/bin/wrapdocker
RUN chmod +x /usr/local/bin/wrapdocker
# Define additional metadata for our image.
VOLUME /var/lib/docker
ENV JENKINS_VERSION 2.8
ENV JENKINS_SHA 4d83a40319ecf4eaab2344a18c197bd693080530
RUN mkdir -p /usr/share/jenkins/ \
&& curl -SL http://repo.jenkins-ci.org/public/org/jenkins-ci/main/jenkins-war/${JENKINS_VERSION}/jenkins-war-${JENKINS_VERSION}.war -o /usr/share/jenkins/jenkins.war
# RUN echo "$JENKINS_SHA /usr/share/jenkins/jenkins.war" | sha1sum -c -
ENV JENKINS_UC https://updates.jenkins.io
RUN mkdir -p /usr/share/jenkins/ref \
&& chown -R ${user} "$JENKINS_HOME" /usr/share/jenkins/ref
RUN usermod -a -G docker jenkins
ENV DOCKER_COMPOSE_VERSION 1.8.0-rc1
# Install Docker Compose
RUN curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
RUN chmod +x /usr/local/bin/docker-compose
RUN apt-get install -y python-pip && pip install supervisor-stdout
EXPOSE 8080
EXPOSE 50000
ADD supervisord.conf /etc/supervisor/conf.d/supervisord.conf
CMD ["/usr/bin/supervisord"]
supervisord.conf
[supervisord]
nodaemon=true
[program:docker]
priority=10
command=wrapdocker
startsecs=0
exitcodes=0,1
[program:chown]
priority=20
command=chown -R jenkins:jenkins /var/jenkins_home
startsecs=0
[program:jenkins]
priority=30
user=jenkins
environment=JENKINS_HOME="/var/jenkins_home",HOME="/var/jenkins_home",USER="jenkins"
command=java -jar /usr/share/jenkins/jenkins.war
stdout_events_enabled = true
stderr_events_enabled = true
[eventlistener:stdout]
command=supervisor_stdout
buffer_size=100
events=PROCESS_LOG
result_handler=supervisor_stdout:event_handler
You can get wrapdocker file here
Put all that in the same directory and build it:
docker build -t my_dind_jenkins .
Then run it:
docker run -d --privileged \
--name=master-jenkins \
-p 8080:8080 \
-p 50000:50000 my_dind_jenkins

Resources