Skip to content

Commit

Permalink
Merge pull request #558 from KrisThielemans/docker_opt_permissions
Browse files Browse the repository at this point in the history
docker: no longer chown /opt a lot of files by creating another user in the container.

Fixes #555
  • Loading branch information
KrisThielemans authored Jun 15, 2021
2 parents 74ed03d + 2c7f966 commit 5d565e6
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 25 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ jobs:
$DCC build sirf
# extract updated ccache
# sudo rm -rf devel/.ccache/*
$DCC run --rm sirf /bin/bash -c 'sudo rm -rf /devel/.ccache/* && sudo cp -a /opt/ccache/* /devel/.ccache/'
$DCC run --rm sirf /bin/bash -c 'rm -rf /devel/.ccache/* && cp -a /opt/ccache/* /devel/.ccache/'
# replace travis' ccache with the built images's
mv devel/.ccache ~
); fi
Expand Down
6 changes: 5 additions & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

## v3.x.x
- disable built of NiftyPET by default as requires Python2 for which we dropped support
- docker: add dependencies that are available only from conda-forge (for CIL)
- docker:
- major change w.r.t. users and permissions. We know build as user jovyan (by default)
and still switch to sirfuser for running the container. This avoids having to
reset permissions of many files, and therefore speeds-up container start-up.
- add dependencies that are available only from conda-forge (for CIL)
- updated ISMRMRD to 1.4.2.1

## v3.0.0
Expand Down
9 changes: 8 additions & 1 deletion docker/DocForDevelopers.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ After building a container, you can optionally replace the cache on the host wit
```bash
SIRF-SuperBuild/docker$ sudo rm -rf devel/.ccache/*
SIRF-SuperBuild/docker$ ./sirf-compose run --rm sirf \
/bin/bash -c 'sudo cp -a /opt/ccache/* /devel/.ccache/'
/bin/bash -c 'cp -a /opt/ccache/* /devel/.ccache/'
```
This way, the cache will be used when you update SIRF in the container, or when you build another container.

Expand All @@ -26,6 +26,11 @@ We use the [`ENTRYPOINT` mechanism](https://docs.docker.com/engine/reference/bui

The very first time the container is run, `entrypoint.sh` creates the `sirfuser` user, copies files in correct places, and takes care of file permissions (see below).

### Why the jovyan user?
The `NB_USER` (by default called `jovyan`) is a convention used by JupyterHub. It launches jupyter
notebooks under this user. Due to permission problems, it should not have `root` access.
We build all files as this user.

### File permissions

Quoting from https://blog.gougousis.net/file-permissions-the-painful-side-of-docker/.
Expand All @@ -36,6 +41,8 @@ Quoting from https://blog.gougousis.net/file-permissions-the-painful-side-of-doc

We handle this by creating the container `sirfuser` with the same `UID:GID` as the user who executes `sirf-compose*` (by passing `USER_ID` and `GROUP_ID` as environment variables), and execute processes in the container as `sirfuser`. (Note that often Docker containers run processes as `root`). Unfortunately, this means that `entrypoint.sh` also has to `chown` various files.

As `chown` can take quite some time when the container is created, we try to minimise this by adding both `jovyan` and `sirfuser` to the `users` group, and giving "group" `rw` access to the files created by `jovyan`. This way, `entrypoint.sh` needs to `chown` (or `chmod`) only the `sirfuser` home-directory and a few others.

## `sirf-compose*`

This is a sequence of convenience scripts that essentially calls `docker-compose` with relevant `.yml` files. These specify parameters for building the images and running the containers. Note that a `.yml` file can specify different "services", e.g. `sirf`, `core`, `gadgetron`. (There is an unfortunate name-clash with SIRF "service" images (which use the `sirf` "service"). Sorry about that.)
108 changes: 101 additions & 7 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ ARG BASE_IMAGE=ubuntu:18.04
FROM ${BASE_IMAGE} as base

LABEL \
author.name="Casper da Costa-Luis" \
author.name="Casper da Costa-Luis, Kris Thielemans, Edoardo Pasca" \
author.email=imaging@caspersci.uk.to \
maintainer.email=ccppetmr@stfc.ac.uk \
maintainer.url=https://www.ccpsynerbi.ac.uk/ \
Expand Down Expand Up @@ -52,6 +52,7 @@ RUN [ -e /usr/bin/X ] || ln -s /usr/bin/Xorg /usr/bin/X
RUN apt-get update -qq && apt-get install -yq --no-install-recommends \
gosu \
&& apt-get clean

ENV DEBIAN_FRONTEND ''
WORKDIR /home-away
COPY entrypoint.sh /usr/local/bin/
Expand All @@ -61,23 +62,58 @@ CMD ["/bin/bash"]
FROM core as sirf
LABEL description="CCP SyneRBI SIRF"

# create user jovyan (jupyterhub seems to require this name)
ARG NB_USER="jovyan"
ARG NB_GROUP="users"
# some crazy number, hopefully not conflicting
ARG NB_UID="22222"
# standard guid for users
ARG NB_GID="100"
ARG HOME="/home/${NB_USER}"

ENV DEBIAN_FRONTEND noninteractive

# make /opt writeable for all users
RUN chmod go+rwx /opt

# copy to $WORKDIR (i.e. /home-away) as this is where entrypoint.sh will pick them up
COPY .bashrc .
COPY .profile .
RUN chmod 644 .bashrc .profile

# Create NB_GROUP and NB_USER
RUN (addgroup --gid ${NB_GID} "${NB_GROUP}" || true) && \
(useradd -l -m -s /bin/bash -N -u "${NB_UID}" -g "${NB_GID}" "${NB_USER}" || true)
# TODO add into sudo ? (probably not for safety)

WORKDIR ${HOME}

# copy to home of NB_USER
COPY .bashrc .
COPY .profile .
RUN chmod 644 .bashrc .profile && chown -R "${NB_USER}":"${NB_GROUP}" "${HOME}"

# run user scripts as NB_USER
USER ${NB_USER}:${NB_GROUP}

# Python (virtualenv)
COPY requirements.txt .
COPY requirements_conda_forge.txt .
COPY user_python-ubuntu.sh .
RUN bash user_python-ubuntu.sh
RUN rm user_python-ubuntu.sh requirements.txt requirements_conda_forge.txt
RUN bash user_python-ubuntu.sh && \
rm user_python-ubuntu.sh requirements.txt requirements_conda_forge.txt

# SIRF
COPY user_sirf-ubuntu.sh .
# ccache
USER root
COPY devel/.ccache/ /opt/ccache/
# give everyone write permisions
RUN chmod -R go+w /opt/ccache

# SIRF
USER "${NB_USER}"

RUN ccache -o cache_dir=/opt/ccache
COPY user_sirf-ubuntu.sh .

ARG BUILD_FLAGS="\
-DCMAKE_BUILD_TYPE=Release\
-DBUILD_STIR_WITH_OPENMP=ON -DUSE_SYSTEM_ACE=ON\
Expand All @@ -90,25 +126,83 @@ ARG EXTRA_BUILD_FLAGS=""
RUN bash user_sirf-ubuntu.sh
RUN rm user_sirf-ubuntu.sh

RUN mv ~/.git-prompt.sh .
# give everyone write and execute permission
RUN chmod -R go+rwX /opt/SIRF-SuperBuild/INSTALL

ENV DEBIAN_FRONTEND ''

# go back to root (entrypoint.sh will switch users)
USER root
CMD ["/bin/bash"]

FROM sirf as service

ENV DEBIAN_FRONTEND noninteractive

ARG NB_USER="jovyan"
ARG NB_GROUP="users"
ARG HOME="/home/${NB_USER}"

USER "${NB_USER}"

COPY requirements-service.txt .
COPY user_service-ubuntu.sh .
RUN bash user_service-ubuntu.sh
RUN rm user_service-ubuntu.sh requirements-service.txt

USER root
COPY download_data.sh /usr/local/bin/

COPY service.sh /usr/local/bin/
ENV DEBIAN_FRONTEND ''
CMD ["/usr/local/bin/service.sh"]

# note: remain root (entrypoint.sh will switch users)

FROM service as multi
COPY service.multi.sh /usr/local/bin/

FROM sirf as jupyterhub

ENV DEBIAN_FRONTEND noninteractive

ARG NB_USER="jovyan"
ARG NB_GROUP="users"
ARG HOME="/home/${NB_USER}"

USER root

# Install all OS dependencies for notebook server that starts but lacks all
# features (e.g., download as all possible file formats)
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update --yes && \
apt-get install --yes --no-install-recommends \
wget \
ca-certificates \
sudo \
locales \
fonts-liberation \
run-one && \
apt-get clean && rm -rf /var/lib/apt/lists/*

# remove some sudo permissions
RUN echo "auth requisite pam_deny.so" >> /etc/pam.d/su && \
sed -i.bak -e 's/^%admin/#%admin/' /etc/sudoers && \
sed -i.bak -e 's/^%sudo/#%sudo/' /etc/sudoers

# Add Tini (note: no tini apt-package yet in Ubuntu 18.04)
ENV TINI_VERSION v0.19.0
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini
RUN chmod +x /tini

# TODO install jupyterhub requirements

USER "${NB_USER}"

ENTRYPOINT ["/tini", "-g", "--"]
# TODO some stuff here
#CMD ["/usr/local/bin/service-jupyterhub.sh"]

# TODO set some env variables (or do it in a compose file)

ENV DEBIAN_FRONTEND ''
19 changes: 10 additions & 9 deletions docker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,10 @@ and change directory to this folder, `SIRF-SuperBuild/docker`.
the next line will build it, resulting in a much smaller download but longer build time.
4. Run `./sirf-compose-server up -d sirf` (or `./sirf-compose-server-gpu up -d sirf`)
5. Open a browser at <http://localhost:9999>.
Note that starting the container may take 10 minutes or more the first
time, but only a few seconds afterwards.
Note that starting the container may take a few seconds the first
time, but will be very quick afterwards.
(Run `docker logs -f sirf` to see the container's progress -
eventually there should be a message stating the notebook has started.)
The password is `virtual`.
The directory is mounted at `/devel` in the docker container
from `./devel` (in this folder) on the host. The container will copy
[SIRF-Exercises] into this folder if not present. This means that
files and notebooks in `./devel` will persist on your host between sessions and
even docker-image upgrades.
6. Stop the container (preserving its status) with `docker stop sirf`.
7. Next time, just do `docker start sirf`.

Expand All @@ -35,7 +29,14 @@ even docker-image upgrades.
[NVidia-container-runtime]: https://github.com/nvidia/nvidia-container-runtime#installation
[SIRF-Exercises]: https://github.com/SyneRBI/SIRF-Exercises

Note: If on Windows, `localhost` probably won't work.
### Important notes:
- The `Jupyter` password is `virtual`.
- The directory is mounted at `/devel` in the docker container
from `./devel` (in this folder) on the host. The container will copy
[SIRF-Exercises] into this folder if not present. This means that
files and notebooks in `./devel` will persist between sessions and
even docker-image upgrades.
- If on Windows, `localhost` probably won't work.
Find out the service IP address using:
```
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' sirf
Expand Down
8 changes: 6 additions & 2 deletions docker/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#!/bin/bash

# This script is expected to be run as root
# at container start-up time

# Add local user
# Either use runtime USER_ID:GROUP_ID or fallback 1000:1000

Expand Down Expand Up @@ -29,12 +32,13 @@ addgroup --quiet --system --gid "$GROUP_ID" "$mainUser"
adduser --quiet --system --shell /bin/bash \
--no-create-home --home /home/"$mainUser" \
--ingroup "$mainUser" --uid "$USER_ID" "$mainUser"
addgroup "$mainUser" users

echo "$mainUser ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/"$mainUser"

for i in /opt/* "$HOME"; do
for i in /opt/*-Exercises /opt/*-Demos "$HOME"; do
if [ -d "$i" ]; then
echo "Updating file permissions for $i"
echo "Updating file ownership for $i"
chown -R $mainUser:$mainUser "$i"
fi
done
Expand Down
8 changes: 4 additions & 4 deletions docker/service.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ stop_service()
for i in $(jobs -p); do kill -n 15 $i; done 2>/dev/null

if [ "$DEBUG" != 0 ]; then
if [ -f gadgetron.log ]; then
echo "----------- Last 70 lines of gadgetron.log"
tail -n 70 gadgetron.log
if [ -f ~/gadgetron.log ]; then
echo "----------- Last 70 lines of ~/gadgetron.log"
tail -n 70 ~/gadgetron.log
fi
fi

Expand All @@ -34,7 +34,7 @@ echo "start gadgetron"
GCONFIG=./INSTALL/share/gadgetron/config/gadgetron.xml
[ -f "$GCONFIG" ] || cp "$GCONFIG".example "$GCONFIG"
[ -f ./INSTALL/bin/gadgetron ] \
&& ./INSTALL/bin/gadgetron >& gadgetron.log&
&& ./INSTALL/bin/gadgetron >& ~/gadgetron.log&

echo "make sure the SIRF-Exercises are in the expected location (/devel in the container)"
cd /devel
Expand Down

0 comments on commit 5d565e6

Please sign in to comment.