I'm trying to write a Dockerfile that creates a user with a home directory who is part of sudoers group and that launches the container as this user.
The problem I'm facing is that, from within the container, every command needs to be prepended sudo, which obviously creates permission issues for every file that's created.
My reasoning behind doing this is that I want a container that mimics a clean linux environment from which I can write install scripts for users.
Here is a copy of my Dockerfile so far:
FROM ubuntu:20.04
# Make user home
RUN mkdir -p /home/nick
# Create a nick user
RUN useradd -r -d /home/nick -m -s /sbin/nologin -c "Docker image user" nick
# Add to sudoers
RUN usermod -a -G sudo nick
# Change ownership of home directory
RUN chown -R nick:nick $HOME
# Set password
RUN echo "nick:******" | chpasswd
# Install sudo
RUN apt-get -y update && apt-get -y install sudo
ENV HOME=/home/nick
WORKDIR $HOME
USER nick
I don't understand why this doesn't work:
FROM continuumio/miniconda3
# FROM --platform=linux/amd64 continuumio/miniconda3
MAINTAINER Brando Miranda "brandojazz#gmail.com"
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ssh \
git \
m4 \
libgmp-dev \
opam \
wget \
ca-certificates \
rsync \
strace \
gcc \
rlwrap \
sudo
# https://github.com/giampaolo/psutil/pull/2103
RUN useradd -m bot
# format for chpasswd user_name:password
RUN echo "bot:bot" | chpasswd
RUN adduser bot sudo
WORKDIR /home/bot
USER bot
# CMD /bin/bash
Related
I have a dockerfile in which I have specified the entrypint as shell script named run-services.sh
Contents of the shell script are as follows:
apache2ctl start
echo "Started apache2ctl..."
python3 mock_ta.py
Now when I deploy this service at my local machine I get an error saying
python3: command not found
I removed entrypoint and went inside the container and executed the which python3 command and I can see that python3 is installed at /usr/bin/python3.
Ideally it should run the python script if python is installed, right? Any idea why this happens?
============================================================
Edit:Added Dockerfile
FROM php:7.1-apache
# Utilities
RUN apt-get update && \
apt-get -y install apt-transport-https git curl vim --no-install-recommends && \
rm -r /var/lib/apt/lists/*
# SimpleSAMLphp
ARG SIMPLESAMLPHP_VERSION=1.15.2
RUN curl -s -L -o /tmp/simplesamlphp.tar.gz https://github.com/simplesamlphp/simplesamlphp/releases/download/v$SIMPLESAMLPHP_VERSION/simplesamlphp-$SIMPLESAMLPHP_VERSION.tar.gz && \
tar xzf /tmp/simplesamlphp.tar.gz -C /tmp && \
rm -f /tmp/simplesamlphp.tar.gz && \
mv /tmp/simplesamlphp-* /var/www/simplesamlphp && \
touch /var/www/simplesamlphp/modules/exampleauth/enable
COPY config/simplesamlphp/config.php /var/www/simplesamlphp/config
COPY config/simplesamlphp/authsources.php /var/www/simplesamlphp/config
COPY config/simplesamlphp/saml20-sp-remote.php /var/www/simplesamlphp/metadata
COPY config/simplesamlphp/server.crt /var/www/simplesamlphp/cert/
COPY config/simplesamlphp/server.pem /var/www/simplesamlphp/cert/
# Apache
COPY config/apache/ports.conf /etc/apache2
COPY config/apache/simplesamlphp.conf /etc/apache2/sites-available
COPY config/apache/cert.crt /etc/ssl/cert/cert.crt
COPY config/apache/private.key /etc/ssl/private/private.key
RUN echo "ServerName localhost" >> /etc/apache2/apache2.conf && \
a2enmod ssl && \
a2dissite 000-default.conf default-ssl.conf && \
a2ensite simplesamlphp.conf
COPY config/run-services.sh /var/www/simplesamlphp/config/run-services.sh
ENTRYPOINT ["/var/www/simplesamlphp/config/run-services.sh"]
# Set work dir
WORKDIR /var/www/simplesamlphp
# General setup
EXPOSE 8080 8443
Thanks #David
With your help I was able to figure out that the python3 image that was present inside container was not accessible indeed.
So I had to install python3 and pip packages with the help of following command
RUN apt update -y && apt upgrade -y && apt install -y python3 && apt install -y python3-pip
I have the following docker file
FROM ubuntu:18.04
ARG user_id
ARG user_gid
# Essential packages for building on a Ubuntu host
# https://docs.yoctoproject.org/ref-manual/system-requirements.html#ubuntu-and-debian
# Note, we set DEBIAN_FRONTEND=noninteractive prior to the call to apt-get
# install because otherwise we'll get prompted to select a timezone when the
# tzdata package gets included as a dependency.
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \
gawk wget git-core diffstat unzip texinfo gcc-multilib build-essential \
chrpath socat cpio python3 python3-pip python3-pexpect xz-utils \
debianutils iputils-ping python3-git python3-jinja2 libegl1-mesa \
libsdl1.2-dev pylint3 xterm python3-subunit mesa-common-dev sudo
# Add a user and set them up for passwordless sudo. We're using the same user
# ID and group numbers as the host system. This allows us to give the yocto
# user ownership of files and directories in the poky volume we're going to add
# without needing to change ownership which would also affect the host system.
RUN groupadd -g $user_gid yoctouser
RUN useradd -m yoctouser -u $user_id -g $user_gid
#echo "yoctouser ALL=(ALL:ALL) NOPASSWD:ALL" | tee -a /etc/sudoers
USER yoctouser
WORKDIR /home/yoctouser
ENV LANG=en_US.UTF-8
CMD /bin/bash
The useradd command is hanging, and specifically the -u option is the issue. If I remove -u $user_id everything works fine. Furthermore, docker is filling up my disk. /var/lib/docker/overlay2/ goes from being 852MB before adding the -u option to gigabytes after just a few seconds. If I don't kill it, it entirely fills up my disk and I end up having to stop the docker daemon and manually remove folders inside of the overlay2 directory.
Why might specifying this uid be an issue?
Here is the relevant section of a python script I wrote to drive this so you can see how I'm getting the user ID and passing it to docker build.
def build_docker_image():
print("Building a docker image named:", DOCKER_IMAGE_NAME)
USERID_ARG = "user_id=" + str(os.getuid())
USERGID_ARG = "user_gid=" + str(os.getgid())
print(USERID_ARG)
print(USERGID_ARG)
try:
subprocess.check_call(['docker', 'build',
'--build-arg', USERID_ARG,
'--build-arg', USERGID_ARG,
'-t', DOCKER_IMAGE_NAME, '.',
'-f', DOCKERFILE_NAME])
except:
print("Failed to create the docker image")
sys.exit(1)
FWIW, on my system
user_id=1666422094
user_gid=1666400513
I am running Docker version 20.10.5, build 55c4c88 on a Ubuntu 18.04 host.
I need to use the -l / --no-log-init option when calling useradd to workaround a bug in docker relating to how large UIDs are handled.
My final dockerfile looks like
FROM ubuntu:18.04
ARG user_id
ARG user_gid
# Essential packages for building on a Ubuntu host
# https://docs.yoctoproject.org/ref-manual/system-requirements.html#ubuntu-and-debian
# Note, we set DEBIAN_FRONTEND=noninteractive prior to the call to apt-get
# install because otherwise we'll get prompted to select a timezone when the
# tzdata package gets included as a dependency.
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \
gawk wget git-core diffstat unzip texinfo gcc-multilib build-essential \
chrpath socat cpio python3 python3-pip python3-pexpect xz-utils \
debianutils iputils-ping python3-git python3-jinja2 libegl1-mesa \
libsdl1.2-dev pylint3 xterm python3-subunit mesa-common-dev
# Set up locales
RUN apt-get install -y locales
RUN dpkg-reconfigure locales && \
locale-gen en_US.UTF-8 && \
update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8
ENV LC_ALL=en_US.UTF-8
ENV LANG=en_US.UTF-8
ENV LANGUAGE=en_US.UTF-8
# Add a user and set them up for passwordless sudo. We're using the same user
# ID and group numbers as the host system. This allows us to give the yocto
# user ownership of files and directories in the poky mount we're going to add
# without needing to change ownership which would also affect the host system.
# Note the use of the --no-log-init option for useradd. This is a workaround to
# [a bug](https://github.com/moby/moby/issues/5419) relating to how large UIDs
# are handled.
RUN apt-get install -y sudo && \
groupadd --gid ${user_gid} yoctouser && \
useradd --create-home --no-log-init --uid ${user_id} --gid yoctouser \
yoctouser && \
echo "yoctouser ALL=(ALL:ALL) NOPASSWD:ALL" | tee -a /etc/sudoers
USER yoctouser
WORKDIR /home/yoctouser
CMD ["/bin/bash"]
I have the following DOCKER FILE
FROM alpine:3.10 as builder
ARG VERSION=7.12.0
ARG DISTRO=tomcat
ARG SNAPSHOT=true
ARG EE=false
ARG USER
ARG PASSWORD
RUN apk add --no-cache \
ca-certificates \
maven \
tar \
wget \
xmlstarlet
COPY settings.xml download.sh camunda-tomcat.sh camunda-wildfly.sh /tmp/
RUN /tmp/download.sh
#Enable Basic AUTH
COPY web.xml /camunda/webapps/engine-rest/WEB-INF/web.xml
##### FINAL IMAGE #####
FROM alpine:3.10
ARG VERSION=7.12.0
ENV CAMUNDA_VERSION=${VERSION}
ENV DB_DRIVER=com.microsoft.sqlserver.jdbc.SQLServerDriver
ENV DB_URL=xx
ENV DB_USERNAME=dbname#xx
ENV DB_PASSWORD=xx
ENV DB_CONN_MAXACTIVE=20
ENV DB_CONN_MINIDLE=5
ENV DB_CONN_MAXIDLE=20
ENV DB_VALIDATE_ON_BORROW=true
ENV DB_VALIDATION_QUERY="SELECT 1"
ENV SKIP_DB_CONFIG=
ENV WAIT_FOR=
ENV WAIT_FOR_TIMEOUT=120
ENV TZ=UTC
ENV DEBUG=TRUE
ENV JAVA_OPTS="-Xmx768m -XX:MaxMetaspaceSize=256m"
EXPOSE 8080 8000
# Downgrading wait-for-it is necessary until this PR is merged
# https://github.com/vishnubob/wait-for-it/pull/68
RUN apk add --no-cache \
bash \
ca-certificates \
openjdk11-jre-headless \
tzdata \
tini \
xmlstarlet \
&& wget -O /usr/local/bin/wait-for-it.sh \
"https://raw.githubusercontent.com/vishnubob/wait-for-it/a454892f3c2ebbc22bd15e446415b8fcb7c1cfa4/wait-for-it.sh" --no-check-certificate \
&& chmod +x /usr/local/bin/wait-for-it.sh
RUN addgroup -g 1000 -S camunda && \
adduser -u 1000 -S camunda -G camunda -h /camunda -s /bin/bash -D camunda
WORKDIR /camunda
USER camunda
#MSSQL SERVER JDBC DRIVER INSTALL
COPY mssql-jdbc-7.2.2.jre11.jar /camunda/lib/
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["./camunda.sh"]
COPY --chown=camunda:camunda --from=builder /camunda .
This runs a CAMUNDA workflow Engine with an External SQL Paas Database and it works perfectly fine.
However in order to troubleshoot I need to be able to SSH into the container.
I found on this website how to do it:
https://learn.microsoft.com/en-us/azure/app-service/containers/tutorial-custom-docker-image
However the problem is that both ENTRYPOINT and CMD only allows ONE command, so I am not sure how to start up SSH
# ssh
ENV SSH_PASSWD "root:xyz"
RUN apt-get update \
&& apt-get install -y --no-install-recommends dialog \
&& apt-get update \
&& apt-get install -y --no-install-recommends openssh-server \
&& echo "$SSH_PASSWD" | chpasswd
COPY sshd_config /etc/ssh/
COPY init.sh /usr/local/bin/
RUN chmod u+x /usr/local/bin/init.sh
EXPOSE 8000 2222
# end ssh config
The Azure docs on this could be a bit better but you're almost there.
Firstly, since you're using Alpine Linux, your Dockerfile steps are a bit different from their example. Notably, you use apk add instead of apt-get install. Take a look at this guide which has examples of setting up SSH for Azure with Alpine.
RUN apk add openssh \
&& echo "root:Docker!" | chpasswd
COPY ./path/to/sshd_config /etc/ssh/
The sshd_config should look something like this:
Port 2222
ListenAddress 0.0.0.0
LoginGraceTime 180
X11Forwarding yes
Ciphers aes128-cbc,3des-cbc,aes256-cbc,aes128-ctr,aes192-ctr,aes256-ctr
MACs hmac-sha1,hmac-sha1-96
StrictModes yes
SyslogFacility DAEMON
PasswordAuthentication yes
PermitEmptyPasswords no
PermitRootLogin yes
Subsystem sftp internal-sftp
PidFile /etc/ssh/run/sshd.pid
HostKey /etc/ssh/ssh_host_rsa_key
The last step is to make sure that sshd gets started when the container starts up. While you're right that CMD can only take one command, that command can be a script which runs multiple things. By default, sshd forks a background process rather than running in the foreground so you should be ok. Your startup command could look like this for example:
#!/bin/sh
# ...
# Start sshd for Azure
ssh-keygen -f /etc/ssh/ssh_host_rsa_key -N '' -t rsa
mkdir -p /etc/ssh/run
/usr/sbin/sshd
# Run any additional commands like ./camunda.sh
Azure has some repositories with full sample projects including the SSH setup. Here's a good example although it is Ubuntu and your container is Alpine so it's a bit different.
Here are some suggestions:
create a custom script that you will run at container startup ( CMD tag) that starts the ssh daemon and your other services
(more hacky) like in this answer simply put everything in your CMD
I am using a docker container to execute a python script located at my host machine. The script should make a new directory at a target location.
When the target location is located under $HOME or $HOME/*, everything works. However, when I want to create a directory at /media/my_name/external_drive, the terminal says that PermissionError: [Errno 13] Permission denied: '/media/my_name'
Here is the code I run
sudo docker-compose run --rm --user="$(id -u):$(id -g)" main process_all.py
Here is docker-compose.yml:
version: '2.3'
services:
main:
build: .
volumes:
- .:/app
- /etc/localtime:/etc/localtime:ro
environment:
- PYTHONIOENCODING=utf_8
init: true
network_mode: host
Here is the dockerfile
FROM ubuntu:16.04
# Install some basic utilities
RUN apt-get update && apt-get install -y \
curl \
ca-certificates \
sudo \
git \
bzip2 \
axel \
&& rm -rf /var/lib/apt/lists/*
# Create a working directory
RUN mkdir /app
WORKDIR /app
# Create a non-root user and switch to it
RUN adduser --disabled-password --gecos '' --shell /bin/bash user \
&& chown -R user:user /app
RUN echo "user ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/90-user
USER user
# All users can use /home/user as their home directory
ENV HOME=/home/user
RUN chmod 777 /home/user
# Install Miniconda
RUN curl -so ~/miniconda.sh https://repo.continuum.io/miniconda/Miniconda3-4.4.10-Linux-x86_64.sh \
&& chmod +x ~/miniconda.sh \
&& ~/miniconda.sh -b -p ~/miniconda \
&& rm ~/miniconda.sh
ENV PATH=/home/user/miniconda/bin:$PATH
# Create a Python 3.6 environment
RUN /home/user/miniconda/bin/conda install conda-build \
&& /home/user/miniconda/bin/conda create -y --name py36 python=3.6.4 \
&& /home/user/miniconda/bin/conda clean -ya
ENV CONDA_DEFAULT_ENV=py36
ENV CONDA_PREFIX=/home/user/miniconda/envs/$CONDA_DEFAULT_ENV
ENV PATH=$CONDA_PREFIX/bin:$PATH
# Ensure conda version is at least 4.4.11
# (because of this issue: https://github.com/conda/conda/issues/6811)
ENV CONDA_AUTO_UPDATE_CONDA=false
RUN conda install -y "conda>=4.4.11" && conda clean -ya
# Install FFmpeg
RUN conda install --no-update-deps -y -c conda-forge ffmpeg=3.2.4 \
&& conda clean -ya
# Install NumPy
RUN conda install --no-update-deps -y numpy=1.13.3 \
&& conda clean -ya
# Install build tools
RUN sudo apt-get update \
&& sudo apt-get install -y build-essential gfortran libncurses5-dev \
&& sudo rm -rf /var/lib/apt/lists/*
# Build and install CDF
RUN cd /tmp \
&& curl -O https://spdf.sci.gsfc.nasa.gov/pub/software/cdf/dist/cdf36_4/linux/cdf36_4-dist-all.tar.gz \
&& tar xzf cdf36_4-dist-all.tar.gz \
&& cd cdf36_4-dist \
&& make OS=linux ENV=gnu CURSES=yes FORTRAN=no UCOPTIONS=-O2 SHARED=yes all \
&& sudo make INSTALLDIR=/usr/local/cdf install
# Install other dependencies from pip
COPY requirements.txt .
RUN pip install -r requirements.txt
# Create empty SpacePy config (suppresses an annoying warning message)
RUN mkdir /home/user/.spacepy && echo "[spacepy]" > /home/user/.spacepy/spacepy.rc
# Copy scripts into the image
COPY --chown=user:user . /app
# Set the default command to python3
CMD ["python3"]
Untested, going by memory but I would debug the issue with an interactive version of your container.
Something like:
sudo docker run -t -i --rm --user="$(id -u):$(id -g)" main /bin/bash
You'll get a bash shell. Then you can debug it by
cd /media
ls -l
What I think you'll find is that the drive is probably not mounted. Or, the user doesn't have permission to access it.
With regards to mounts, either pass it through from the host or create a volume mount. I'm a little bit unsure about what you can do there because since I last used docker many changes around mounting and volume drivers were introduced. But the documentation on the docker website is pretty good. So experiment.
This is the cmd line reference for docker: https://docs.docker.com/engine/reference/run/
The key is to use the -t -i parameters to make it interactive.
I am currently trying to docker-ize a Azure Hybrid Worker using the instructions provided at:
https://learn.microsoft.com/en-us/azure/automation/automation-linux-hrw-install
I am 90% successful however when I try to run the final step using onboarding.py the script is not found in the location specificied by the documentation. Basically the file is not found anywhere in the container. Any help would be great.
FROM ubuntu:14.04
RUN apt-get update && \
apt-get -y install sudo
ENV user docker
RUN useradd -m -d /home/${user} ${user} && \
chown -R ${user} /home/${user} && \
adduser ${user} sudo && \
echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
USER ${user}
#WORKDIR /home/${user}
RUN sudo apt-get -y install apt-utils && \
sudo apt-get -y install openssl && \
sudo apt-get -y install curl && \
sudo apt-get -y install wget && \
sudo apt-get -y install cron && \
sudo apt-get -y install net-tools && \
sudo apt-get -y install auditd && \
sudo apt-get -y install python-ctypeslib
RUN sudo wget https://raw.githubusercontent.com/Microsoft/OMS-Agent-for-Linux/master/installer/scripts/onboard_agent.sh && \
sudo sh onboard_agent.sh -w <my-workplace-id> -s <my-workspace-key>
RUN sudo python /opt/microsoft/omsconfig/modules/nxOMSAutomationWorker/DSCResources/MSFT_nxOMSAutomationWorkerResource/automationworker/scripts/onboarding.py --register <arguments-removed-for-stackoverflow-post>
EXPOSE 443
Although I don't know the exact reason why it doesn't work yet, I have made some progress that I would like to share.
I've been experimenting with this problem by comparing the differences between centos running on a VM and a centos docker container. Although I haven't been able to pinpoint the exact things that are missing, I was able to get the onboarding.py file to show up on a centos docker container.
First what I did is create a file that has a list of packages that are installed on a minimal centos VM. In my docker file I run through this file and install each package. I plan to cut down the file to see what's necessary for this to work.
The second thing is you must have systemd, which is not installed by default. Here is what my docker image looks like while I'm testing:
FROM centos:7
RUN yum -y update && yum install -y sudo
RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == \
systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*;\
rm -f /etc/systemd/system/*.wants/*;\
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*;\
rm -f /lib/systemd/system/anaconda.target.wants/*;
ENV user docker
RUN useradd -m -d /home/${user} ${user}
RUN chown -R ${user} /home/${user}
RUN echo "docker ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
USER ${user}
WORKDIR /home/${user}
COPY ./install_packages .
RUN sudo yum install -y $(cat ./install_packages)
sudo wget https://raw.githubusercontent.com/Microsoft/OMS-Agent-for-Linux/master/installer/scripts/onboard_agent.sh
CMD ["/usr/sbin/init"]
After that I use docker run to run my container locally and start systemd:
docker run -v /run -v /sys/fs/cgroup:/sys/fs/cgroup:ro -d container_id
I then exec into my container and run the onboard script:
sudo sh onboard_agent.sh -w 'xxx' -s 'xxx'
After it's done, you sometimes need to wait about 5 minutes for the missing folders to appear. To trigger this to happen sooner, you need to run this command:
/opt/microsoft/omsagent/bin/service_control restart {OMS_WORKSTATION_ID}
My understanding is this command will restart the OMS agent and it requires systemctl.
I understand this doesn't answer your question on how to get it working from building and running the container without having to remote into it. I'm still working on that and I'll let you know if I find an answer.
Good luck.