Getting “Permission Denied” error when pulling a docker image in Jenkins docker container on Mac
I was following this tutorial to build a python app using the latest Jenkins container on my mac(10.14)
The image below shows what happened.
TL;DR, check out the solution at the bottom
Environment:
macOS: 10.14
docker CE: 19.03.2
Problem:
Briefly speaking, I created a Jenkins container on my mac and mounted the docker socket and other local directories to the container like what has been mentioned in the tutorial. However, the user in the Jenkins container doesn’t have access permission to the mounted docker socket. I googled this problem, and most of the solutions are the same “adding the user to docker group”. Unfortunately, I misunderstood the solution and got frustrated at the beginning, since there is no “docker group” on macOS, at least I could not find one on my mac.
Command to list all groups on a macOS
dscacheutil -q group
Later I noticed that the user is the one in the Jenkins container instead of the user on my mac.
These commands can reproduce the situation
# create a jenkins container and mount the local docker socket to the container
docker run -d --name jenkins -p 8080:8080 -p 50000:50000 -v /var/run/docker.sock:/var/run/docker.sock -v $(pwd)/local:/var/jenkins_home -v "$HOME":/home jenkinsci/blueocean
The newly created container is named Jenkins
. I log in to the container and check its user information.
docker exec -it jenkins bash
Use id
to show id and group of the current user, and use docker version
to check docker information.
bash-4.4$ id
uid=1000(jenkins) gid=1000(jenkins) groups=1000(jenkins)
bash-4.4$ docker version
Client:
Version: 18.09.8-ce
API version: 1.39
Go version: go1.11.5
Git commit: 0dd43dd87fd530113bf44c9bba9ad8b20ce4637f
Built: Sat Jul 20 15:21:00 2019
OS/Arch: linux/amd64
Experimental: false
Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.39/version: dial unix /var/run/docker.sock: connect: permission denied
The default user in the container is named jenkins
, and its id is 1000
. This user belongs to a user group called jenkins
. The id of the group is also 1000
, but they are used to identify different entities(one for the user, the other for the group). This user has access to the Docker client in the container but not to/var/run/docker.sock
.
Necessary background knowledge:
A UID (user identifier) is a number assigned by Linux to each user on the system. This number is used to identify the user to the system and to determine which system resources the user can access.
Show all users in the container
bash-4.4$ cat /etc/passwdroot:x:0:0:root:/root:/bin/ash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
ntp:x:123:123:NTP:/var/empty:/sbin/nologin
smmsp:x:209:209:smmsp:/var/spool/mqueue:/sbin/nologin
guest:x:405:100:guest:/dev/null:/sbin/nologin
nobody:x:65534:65534:nobody:/:/sbin/nologin
jenkins:x:1000:1000:Linux User,,,:/var/jenkins_home:/bin/bash
...
A GID (group identifier) is a name that associates a system user with other users sharing something in common.
Show all groups in the container
bash-4.4$ cat /etc/grouproot:x:0:root
bin:x:1:root,bin,daemon
daemon:x:2:root,bin,daemon
sys:x:3:root,bin,adm
adm:x:4:root,adm,daemon
nogroup:x:65533:
nobody:x:65534:
jenkins:x:1000:jenkins
docker:x:101:
...
All files and directories are “owned” by the user who created them. The creator can specify who is allowed to read the file, write to the file, or (if it is an application instead of a text file) who can execute the file.
Display details of the /var/run/docker.sock
bash-4.4$ ls -l /var/run/docker.socksrw-rw---- 1 root docker 0 Nov 4 15:26 /var/run/docker.sock# orbash-4.4$ stat /var/run/docker.sockFile: /var/run/docker.sock
Size: 0 Blocks: 0 IO Block: 4096 socket
Device: 10h/16d Inode: 16532 Links: 1
Access: (0660/srw-rw----) Uid: (0/root) Gid: (101/docker)
Access: 2019-11-05 23:05:38.374793000 +0000
Modify: 2019-11-04 15:26:12.637335983 +0000
Change: 2019-11-05 23:05:13.623936000 +0000
Birth: -
The docker.sock
is owned by the user root
whose id is 0
and group docker
whose id is 101
.
srw-rw---- 1 root docker 0 Nov 4 15:26 /var/run/docker.sock
| | | | | |
| | | | owner group
| | | |--- all other users or groups
| | |-- group permission
| |--- owner permission
|--- file type
The ownership of this socket can be dissected into 3 parts:
- owner’s permission:
rw-
.root
user, in this case, canw
rite andr
ead this file, but cannot execute it. - owner group’s permission:
rw-
same as the owner. The owner group isdocker
. - all other groups or users:
---
. Cannot read, write or execute it. Eg.jenkins
Obviously, the user jenkins
doesn’t have the permission to write to or read from the docker socket.
At this moment, I realized that the Jenkins container uses the default user jenkins
to start all the Jenkins services, and this user is in the jenkins
group, not the docker
group.
The solution becomes clear: adding user
jenkins
to groupdocker
.
Solution:
- log in the container as
root
user, since userjenkins
cannot perform the operation.docker exec -it -u root jenkins bash
- install a library called
shadow
. The Jenkins image is on top of alpine image, it doesn’t haveusermod
command. Then add the userjenkins
todocker
group.
apk --no-cache add shadow
usermod -aG docker jenkins
3. log out and restart the container docker restart jenkins
4. user jenkins
in the container should have permission now.
Reference:
https://wiki.archlinux.org/index.php/File_permissions_and_attributes