In Running Arbitrary Startup Scripts in Docker Containers, I described a recipe cribbed from MyBinder/repo2docker, for running arbitrary scripts on startup of a Docker container.
One thing I hadn’t fully appreciated was the role of permissions in making sure that scripts and services called in the startup script had enough permissions to run. In the containers we are using, which are inspired by the official Jupyter stack containers, the containers are started with a specified user (in the Jupyterverse, this is user
jovyan wuth UID 1000, by convention).
The start script runs under the user that is started into the container, so trying to start the postgres database service from my start script resulted in a permissions error.
One possible fix is to elevate the permissions of the user so that they can run the desired start commands. This is perhaps not as unreasonable as it might sound, at least in an educational context. The containers are single user environments, and when run from a multi-user JupyterHub environment (at least under Kubernetes, rather than for example in The Littlest JupyterHub). Whilst we don’t want learners to be in a position where they accidentally destroy their environment, my personal belief is that we should allow learners to have as much ownership of the environment as possible. (It should also be noted that if a student does mangle a containerised environment, respawning the environment from the original image as a new container should put everything back in place…)
So how do we go about elevating permissions? The approach I have used to date (for example, in here) is to allocate sudoers priviliges to the user in respect of at least the commands that are used to start up services in the start up script.
For example, the following Dockerfile command gives the user permission to start the postgresql service, run the mongo server and fire up an external start script:
RUN echo "$NB_USER ALL=(ALL:ALL) NOPASSWD: /sbin/service postgresql restart" >> /etc/sudoers && \ echo "$NB_USER ALL=(ALL:ALL) NOPASSWD: /usr/bin/mongod" >> /etc/sudoers && \ echo "$NB_USER ALL=(ALL:ALL) NOPASSWD: /var/startup/start_jh_extras" >> /etc/sudoers
The extra start script is actually provided as a place for additional startup items required when used in a JupyterHub environment, about which more in a later post. (The sudoers bit for that script should probably really be in the Dockerfile that generates the JupyterHub image, which slightly differs from the local image in my build.)
if [ -f "/var/startup/start_jh_extras" ]; then sudo /var/startup/start_jh_extras fi
PS for a complementary approach to all this, see my colleague Mark Hall’s