I’m writing a Dockerfile where the root user creates a user named blog
to manage website deployment. I’m using the Docker Hub wordpress container as a base. The root user creates folders under /var/www/html
and gives the blog
user permissions to write underneath.
In the next set of RUN commands following USER blog
, these commands do not acknowledge the previous state where blog
user was given permission to write in /var/www/html
. This user needs to clone a git repo in there, but I get the error fatal: could not create leading directories of '/var/www/html/wp-content/uploads': Permission denied
due to the new user not being able to write there, despite setting permissions for this user previously.
Here are the commands I’m using to create the blog
user, copy files to their home directory, and then clone a repo with this user:
ENV WORDPRESS_DB_USER=wp_blog WORDPRESS_DB_NAME=wp_blog WORDPRESS_DIR=/var/www/html TERM=xterm # Setup the WordPress site user # Preliminary command RUN useradd --create-home --shell /bin/false --groups www-data blog COPY id_rsa* known_hosts /home/blog/.ssh/ ## First set of commands RUN mkdir --parents "$WORDPRESS_DIR"/wp-content/uploads && chown --recursive blog:blog "$WORDPRESS_DIR" && chown --recursive blog:blog /home/blog USER blog ## Second set of commands RUN chmod u=rw,g=,o= /home/blog/.ssh/id_rsa && chmod u=rw,g=r,o=r /home/blog/.ssh/id_rsa.pub && chmod u=rw,g=r,o=r /home/blog/.ssh/known_hosts && eval $(ssh-agent -s) && ssh-add && export PATH=$PATH:/usr/sbin # Use the WordPress user to download the content repo and hooks # The following command results in a permissions error: && git clone git@gitlab.com:jb-merideoux/jbm-uploads.git "$WORDPRESS_DIR"/wp-content/uploads && mkdir --parents /home/blog/git/wpgithooks && cd /home/blog/git/wpgithooks && git clone git@github.com:enderandpeter/wpgithooks.git /home/blog/git/wpgithooks && git checkout --git-dir=/home/blog/git/wpgithooks/.git --track origin/wpaddons && chmod u+x /home/blog/git/wpgithooks/*.sh && echo Run the script at /home/blog/git/wpgithooks/setup.sh to get started
The blog
user is able to set permissions for the copied SSH key pair, but it cannot if the chown --recursive blog:blog /home/blog
command is not present. I would think that the previous chown --recursive blog:blog "$WORDPRESS_DIR"
command would have an equal effect on whether or not the blog
user can write in /var/www/html
in the same set of commands where blog
changes permissions for files copied to its home by root
after the root
user made sure everything under /home/blog
was owned by blog
. Somehow, the permissions for /home/blog
are in effect in the second set of RUN commands, but not the permissions for /var/www/html
.
Upon closer inspection, it would appear that the mkdir --parents "$WORDPRESS_DIR"/wp-content/uploads
instruction has not run either because when I precede the git clone
command with something to create a file like touch "$WORDPRESS_DIR"/wp-content/uploads/afile
, the error is touch: cannot touch '/var/www/html/wp-content/uploads/afile': No such file or directory
.
When I try to createafile
in /var/www/html/
(which already exists because it was created by the base wordpress container), I get the error touch: cannot touch '/var/www/html/afile': Permission denied
, indicating that the chown --recursive blog:blog "$WORDPRESS_DIR"
command was not acknowledged. Of the three commands in the first set of RUN statements, it looks like the only one acknowledged by the second set of RUN statements is chown --recursive blog:blog /home/blog
.
How might I write this Dockerfile so that all of the commands in the first RUN statement have been issued by the time the second set of RUN statements are executed by the new user?
Advertisement
Answer
Wow, that was intense. The second set of commands just never pick up on what was done beforehand. I’ve seen examples where subsequent RUN commands are aware of things that happened in previous ones, so I’m still not clear on just how that is determined.
The solution I found was to use su
in the first set of commands, right after root creates directories and sets permissions:
RUN mkdir --parents "$WORDPRESS_DIR"/wp-content/uploads && chown --recursive blog:blog "$WORDPRESS_DIR" && chown --recursive blog:blog /home/blog && su - blog -s /bin/bash -c ' chmod u=rwx,g=,o= /home/blog/.ssh && chmod u=rw,g=,o= /home/blog/.ssh/id_rsa ... && git clone git@gitlab.com:jb-merideoux/jbm-uploads.git '"$WORDPRESS_DIR"'/wp-content/uploads ... && echo '"$WORDPRES_DIR"' setup complete.'
As you can see, that is some insane quoting, but luckily you can format the commands exactly as though they were given straight to the Dockerfile. I did use USER blog
at the very end to do things that didn’t depend on the earlier stuff, but I guess sometimes with Docker, you have to string a whole bunch of commands together, but I can probably get all this into a separate script…