Detailed explanation of Docker Volume authority management

  • 2020-12-13 19:13:34
  • OfStack

Volume data volume is an important concept of Docker. A data volume is a special directory that can be used by one or more containers and provides valuable features for containers to apply storage:

Persistent data is decoupled from the container's life cycle: The contents of the data volume can be retained after the container is deleted. named volume (named file volumes) introduced after Docker 1.9 makes it easier to manage the life cycle of data volumes. Data volumes can be created and deleted independently. Data volumes can be used to achieve data sharing between containers Different types of data storage implementations can be supported

By default, Docker provides support for a host local file volume that can be mounted into a container. Without the performance cost of a container-layered file system, local file volumes are ideal for scenarios that require high-performance data access, such as the storage of MySQL database files. At the same time, Docker supports different types of data volumes through volume plugin, which can meet the storage requirements of different application loads more flexibly. For example, in the ali cloud container service, cloud disk-based block storage and OSSFS and NAS/NFS shared file storage can be provided for containers.

However, the authority management of Docker data volumes is often very confusing. This article will introduce common problems and solutions in Docker data volume authority management with examples.

Start with the Jenkins mount local data volume error

A recent colleague encountered a problem running Jenkins with containers, and the steps to reproduce it are as follows:

Note: For Windows/Mac, you need to log on to the Boot2docker virtual machine, not Linux.


docker-machine ssh default

Start the Jenkins official mirror and check the log


docker run -d -p 8080:8080 -p 50000:50000 --name jenkins jenkins
docker logs jenkins

We can see that the "jenkins" container log shows that 1 cut is normal

However, in order to persist the Jenkins configuration data, the problem arises when we mount the data folder in the current directory of the host to the directory "/var/jenkins_home" in the container:


docker rm -f jenkins
docker run -d -p 8080:8080 -p 50000:50000 -v $(pwd)/data:/var/jenkins_home --name jenkins jenkins
docker logs jenkins

The error log is as follows

[

touch: cannot touch '/var/jenkins_home/copy_reference_file ': Permission denied
Can not write to /var/jenkins_home/copy_reference_file.log. Wrong volume permissions?

]

What's going on here?

We check the "/var/jenkins_home" directory permissions in the previous startup mode to see the current user of the Jenkins container: the current user is "jenkins" and the "/var/jenkins_home" directory is owned by the jenkins user


docker@default:~$ docker run -ti --rm --entrypoint="/bin/bash" jenkins -c "whoami && id"
jenkins
uid=1000(jenkins) gid=1000(jenkins) groups=1000(jenkins)

docker@default:~$ docker run -ti --rm --entrypoint="/bin/bash" jenkins -c "ls -la /var/jenkins_home"
total 20
drwxr-xr-x 2 jenkins jenkins 4096 Jun 5 08:39 .
drwxr-xr-x 28 root  root  4096 May 24 16:43 ..
-rw-r--r-- 1 jenkins jenkins 220 Nov 12 2014 .bash_logout
-rw-r--r-- 1 jenkins jenkins 3515 Nov 12 2014 .bashrc
-rw-r--r-- 1 jenkins jenkins 675 Nov 12 2014 .profile

When the local data volume is mapped, the /var/jenkins_home directory owner becomes the root user


docker run -ti --rm -v $(pwd)/data:/var/jenkins_home --entrypoint="/bin/bash" jenkins -c "ls -la /var/jenkins_home"
total 4
drwxr-sr-x 2 root staff  40 Jun 5 08:32 .
drwxr-xr-x 28 root root 4096 May 24 16:43 ..

This explains why the Permission denied problem occurs when the "jenkins" user's process accesses the "/var/jenkins_home" directory

Let's also examine the data volume directory on the host. The owner of the "data" directory in the current path is "root", because this directory is created by the Docker process by default.


docker@default:~$ ls -la data
total 0
drwxr-sr-x  2 root   staff      40 Jun 5 08:32 ./
drwxr-sr-x  5 docker  staff     160 Jun 5 08:32 ../

Once the problem is discovered, the solution is simple: assign the owner of the current directory to uid 1000, and start the "jenkins" container and it will cut right.


sudo chown -R 1000 data
docker start jenkins

When using the browser to access "http: / / 192.168.99.100:8080 /" can see Jenkins Web interface. Note: If not accessible, you may need to obtain the IP address of the current Docker host via the docker-ES116en ip command.

When we go inside the container and look at the permissions of the "/var/jenkins_home" directory, the owner has changed to "jenkins"


docker@default:~$ docker exec jenkins ls -la /var/jenkins_home
total 24
drwxr-sr-x 11 jenkins staff 340 Jun 5 09:00 .
drwxr-xr-x 28 root  root 4096 May 24 16:43 ..
drwxr-sr-x 3 jenkins staff  60 Jun 5 08:59 .java
-rw-r--r-- 1 jenkins staff 289 Jun 5 08:59 copy_reference_file.log
...

Interestingly, the owner of the "data" directory we see on the host is "docker", because the "docker" user also has "1000" on the "boot2docker" host.


docker@default:~$ ls -la data
total 20
drwxr-sr-x  2 docker  staff      40 Jun 5 11:55 ./
drwxr-sr-x  6 docker  staff     180 Jun 5 11:55 ../
...

At this point we already know that the permissions of the files/directories in the container's local data volume are the same as those on host 1, except that uid/gid may map to different user/group names in the Docker container and host.

In the previous article, we used a common trick of using uid instead of a specific user name when executing the chown command on the host to ensure that the correct owner is set up.

The problem is solved, but the thinking is not over. Because when using a local data volume, the Jenkins container relies on the correctness of the host directory permissions, this creates additional work for automated deployment. Is there a way for the Jenkins container to automatically set the correct permissions for the data volume? This question also has implications for many applications that run non-ES150en.

Mount local data volumes correctly for non-root applications

We can find many relevant discussions from the omnipotent ES158en.com, one of which is very instructive and q&A is as follows

http://stackoverflow.com/questions/23544282/what-is-the-best-way-to-manage-permissions-for-docker-shared-volumes

There are two basic ideas:

One is to use the method of Data Container to share data volumes between containers. This avoids the permission issue of resolving data volumes on the host. Since Docker provided named volume in place of pure data containers after version 1.9, we also needed to really address this issue.

Another idea is to start the container as root user, use the "chown" command in the container startup script to correct the data volume file permissions, and then switch to non-ES178en user to execute the program

Let's look at the second idea to solve this problem

Here is an Dockerfile based image: it switches to the "root" user and adds the "gosu" command to the image, along with a new entry point "/ entrypoint.sh"


FROM jenkins:latest
USER root
RUN GOSU_SHA=5ec5d23079e94aea5f7ed92ee8a1a34bbf64c2d4053dadf383992908a2f9dc8a \
 && curl -sSL -o /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/1.9/gosu-$(dpkg --print-architecture)" \
 && chmod +x /usr/local/bin/gosu \
 && echo "$GOSU_SHA /usr/local/bin/gosu" | sha256sum -c - 
COPY entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

Note: gosu is a gadget that often appears in the official Docker image. It is a lightweight alternative to the "su" and "sudo" commands and solves one of their problems in tty and signalling.

The new entry point "entrypoint.sh" reads as follows: it sets the "jenkins" permissions for the "JENKINS_HOME" directory and uses the "gosu" command to switch to the "jenkins" user to execute the "jenkins" application.


docker run -d -p 8080:8080 -p 50000:50000 --name jenkins jenkins
docker logs jenkins
0

You can directly from https: / / github com/denverdino/docker - jenkins get the code, and build their own Jenkins image. Execute the command as follows:


docker run -d -p 8080:8080 -p 50000:50000 --name jenkins jenkins
docker logs jenkins
1

Then start the Jenkins container based on the new image


docker run -d -p 8080:8080 -p 50000:50000 --name jenkins jenkins
docker logs jenkins
2

conclusion

This article introduced the basic concepts of Docker data volumes. We present a solution to the access problem of the ES228en-ES229en process to local data volumes. We plan to continue summarizing some of the other issues with Docker data volumes in the future,


Related articles: