Docker RUN does NOT persist files

2019-05-10 11:39发布

问题:

I have a problem with Docker which does not persist commands launch via "RUN".

Here is my Dockerfile :

FROM jenkins:latest

RUN echo "foo" > /var/jenkins_home/toto ; ls -alh  /var/jenkins_home
RUN ls -alh  /var/jenkins_home

RUN rm /var/jenkins_home/.bash_logout  ; ls -alh  /var/jenkins_home
RUN ls -alh  /var/jenkins_home

RUN echo "bar" >> /var/jenkins_home/.profile ; cat /var/jenkins_home/.profile
RUN  cat /var/jenkins_home/.profile

And here is the output :

Sending build context to Docker daemon 373.8 kB Step 1 : FROM jenkins:latest  ---> fc39417bd5fb Step 2 : RUN echo "foo" > /var/jenkins_home/toto ; ls -alh  /var/jenkins_home  ---> Using cache 
---> c614b13d9d83 Step 3 : RUN ls -alh  /var/jenkins_home  ---> Using cache  ---> 8a16a0c92f67 Step 4 : RUN rm /var/jenkins_home/.bash_logout  ; ls -alh  /var/jenkins_home  ---> Using cache  ---> f6ca5d5bdc64 Step 5 : RUN ls -alh  /var/jenkins_home
---> Using cache  ---> 3372c3275b1b Step 6 : RUN echo "bar" >> /var/jenkins_home/.profile ; cat /var/jenkins_home/.profile  ---> Running in 79842be2c6e3
# ~/.profile: executed by the command interpreter for login shells.
# This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login
# exists.
# see /usr/share/doc/bash/examples/startup-files for examples.
# the files are located in the bash-doc package.

# the default umask is set in /etc/profile; for setting the umask
# for ssh logins, install and configure the libpam-umask package.
#umask 022

# if running bash if [ -n "$BASH_VERSION" ]; then
    # include .bashrc if it exists
    if [ -f "$HOME/.bashrc" ]; then     . "$HOME/.bashrc"
    fi fi

# set PATH so it includes user's private bin if it exists if [ -d "$HOME/bin" ] ; then
    PATH="$HOME/bin:$PATH" fi bar  ---> 28559b8fe041 Removing intermediate container 79842be2c6e3 Step 7 : RUN cat /var/jenkins_home/.profile  ---> Running in c694e0cb5866
# ~/.profile: executed by the command interpreter for login shells.
# This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login
# exists.
# see /usr/share/doc/bash/examples/startup-files for examples.
# the files are located in the bash-doc package.

# the default umask is set in /etc/profile; for setting the umask
# for ssh logins, install and configure the libpam-umask package.
#umask 022

# if running bash if [ -n "$BASH_VERSION" ]; then
    # include .bashrc if it exists
    if [ -f "$HOME/.bashrc" ]; then     . "$HOME/.bashrc"
    fi fi

# set PATH so it includes user's private bin if it exists if [ -d "$HOME/bin" ] ; then
    PATH="$HOME/bin:$PATH" fi  ---> b7e47d65d65e Removing intermediate container c694e0cb5866 Successfully built b7e47d65d65e

Do you guys know why "foo" file is not persisted on step 3? Why ".bash_logout" file is recreated on step 5? Why "bar" is not in my ".profile" file anymore on step 7?

And of course, if I start a container based on this image, none of my modifications are persisted... so my Dockerfile is... useless. Any clue?

回答1:

The reason those changes are not persisted, is that they are inside a volume the Jenkins Dockerfile marks /var/jenkins_home/ as a VOLUME.

Information inside volumes is not persisted during docker build, or more precisely; each build-step creates a new volume based on the image's content, discarding the volume that was used in the previous build step.

How to resolve this?

I think the best way to resolve this, is to;

  • Add the files you want to modify inside jenkins_home in a different location inside the image, e.g. /var/jenkins_home_overrides/
  • Create a custom entrypoint based on, or "wrapping", the default entrypoint script that copies the content of your jenkins_home_overrides to jenkins_home the first time the container is started.

Actually...

And just when I wrote that up; It looks like the official Jenkins image already support this out of the box; https://github.com/jenkinsci/docker/blob/683b0d6ed17016ee3211f247304ef2f265102c2b/jenkins.sh#L5-L23

According to the documentation, you need to add your files to the /usr/share/jenkins/ref/ directory, and those will be copied to /var/jenkins/home upon start.

Also see https://issues.jenkins-ci.org/browse/JENKINS-24986



回答2:

Just for testing, check if the issue persists with RUN directives written like:

RUN bash -c 'echo "foo" > /var/jenkins_home/toto'
RUN bash -c 'echo "bar" >> /var/jenkins_home/.profile'