I’m trying to use the host docker from the container. However, due to the specificity of my app, I have to start as a non-root user.
So the docker run looks like this:
docker run -u $(id -u) -it -v /var/run/docker.sock:/var/run/docker.sock my-app:0.0.1
The problem is /var/run/docker.sock is created as non-writable for non-root users
$ ls -l /var/run/docker.sock
srwxr-xr-x 1 root root 0 Dec 9 13:11 /var/run/docker.sock
So, when my app tries to do anything, it reasonably gets “permission denied”:
sh-4.2$ docker ps
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.24/containers/json": dial unix /var/run/docker.sock: connect: permission denied
Does anyone know a way to change permissions for the socket?
I know that I can join this container and make chmod from there but it doesn’t look like a good option: this stuff runs in the batch mode and such a pattern will be quite complicated to implement there.
If you only set the uid, the user still belongs to the root group:
docker run -u $(id -u) -it -v /var/run/docker.sock:/var/run/docker.sock alpine id
uid=1001 gid=0(root) groups=0(root)
Thus, if instead of 755, your permissions would be 660, it should work. You do not want to give others access to the docker sock, as it would mean everyone could create containers that could be used for privilege escalation.
Note: By default the permissions and ownership for the docker.sock should look like this:
srw-rw---- 1 root docker 0 xxx x xx:xx /var/run/docker.sock
Your docker.sock looks modified and lacks write permissions for the group.
You can either add the group id to the -u argument, or use --group-add to add it as additional group. To illustrate the outcome, I used alpine as image and id as command to see the effect:
docker run -u $(id -u):$(getent group docker | cut -d: -f3) -it -v /var/run/docker.sock:/var/run/docker.sock alpine id
uid=1001 gid=999(ping) groups=999(ping)
docker run -u $(id -u) --group-add $(getent group docker | cut -d: -f3) -it -v /var/run/docker.sock:/var/run/docker.sock alpine id
uid=1001 gid=0(root) groups=0(root),999(ping)
Handling permissions in Docker Desktop for Mac is different from the way on Linux. I am not 100 percent sure either how it works exactly, but passing the userid to docker run does not affect file permissions on Linux without Docker Desktop but it does in some cases in Docker Desktop. It can be useful when you want to mount something from your home folder because you own those files and you can decide which user needs to access those files in the containers in the virtual machine of Docker Desktop by passing the userid. It is not true when you want to mount the Docker socket from /var/run/docker.sock. So you could think that you don’t need that file since that is only a symbolic link to an other file which is in fact in your home directory:
$HOME/.docker/run/docker.sock
It will not work and you will probably get “Unsupported operation”. The reason is that when you mount /var/run/docker.sock you actually mount the socket from the virtual machine, not from the host operating system (in this case macOS). That socket is only for the host and if I am not mistaken, only for compatibility reason. So you can’t mount the socket from the host.
Let’s see what you can do.
You know that you can mount the socket from the virtual machine and you can access it as root.
You can share network namespaces between containers so you don’t have to forward the unix sockat to a public IP address, only the localhost of that container.
You can configure the docker client to connect to ny unix socket or tcp socket.
One “problem” remains, however. You will run a container as a non-root user but every process in the container would be able to access the docker socket. Fortunately the container that has the docker client does not have to run multiple processes. All of the other containers will run in separate namespaces so the only process you have to worry about is the docker command which (I guess) will be run by you.
If you need an example how that would work, I can share my “local-builder” compose file that I created for local CI/CD testing but I can also use it on CircleCI.
Note that I used the host network, because I wanted to have the least isolation and I only wanted a specific environment, but you can use the container or service network mode:
I haven’t tried this version so I just hope I could give you some ideas with this example.
Please, confirm that you want to “host” the client only and not the daemon That would be a completely different case that would not need the docker ocket to be mounted.