Docker: permission denied while trying to connect to Docker Daemon with local CircleCI build
Asked Answered
V

4

11

I have a very simple config.yml:

version: 2

jobs:
  build:
    working_directory: ~/app
    docker:
      - image: circleci/node:8.4.0
    steps:
      - checkout
      - run: node -e "console.log('Hello from NodeJS ' + process.version + '\!')"
      - run: yarn
      - setup_remote_docker
      - run: docker build .

All it does: boot a node image, test if node is running, do a yarn install and a docker build.

My dockerfile is nothing special; it has a COPY and ENTRYPOINT.

When I run circleci build on my MacBook Air using Docker Native, I get the following error:

Got permission denied while trying to connect to the Docker daemon socket at unix://[...]

If I change the docker build . command to: sudo docker build ., everything works as planned, locally, with circleci build.
However, pushing this change to CircleCI will result in an error: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

So, to summarize: using sudo works, locally, but not on CircleCI itself. Not using sudo works on CircleCI, but not locally.

Is this something the CircleCI staff has to fix, or is there something I can do?

For reference, I have posted this question on the CircleCI forums as well.

Verleneverlie answered 21/8, 2017 at 12:4 Comment(0)
V
8

I've created a workaround for myself.

In the very first step of the config.yml, I run this command:

if [[ $CIRCLE_SHELL_ENV == *"localbuild"* ]]; then
  echo "This is a local build. Enabling sudo for docker"
  echo sudo > ~/sudo
else
  echo "This is not a local build. Disabling sudo for docker"
  touch ~/sudo
fi

Afterwards, you can do this:

eval `cat ~/sudo` docker build .

Explanation:

The first snippet checks if the CircleCI-provided environment variable CIRCLE_SHELL_ENV contains localbuild. This is only true when running circleci build on your local machine. If true, it creates a file called sudo with contents sudo in the home directory. If false, it creates a file called sudo with NO contents in the home directory.

The second snippet opens the ~/sudo file, and executes it with the arguments you give afterwards. If the ~/sudo file contains "sudo", the command in this example will become sudo docker build ., if it doesn't contain anything, it will become docker build ., with a space before it, but that will be ignored.

This way, both the local (circleci build) builds and remote builds will work.

Verleneverlie answered 21/8, 2017 at 12:4 Comment(3)
This is a good workaround, but it's too bad their CLI doesn't handle this case...Complacency
I believe your touch ~/sudo won't clear the file. It should be : > ~/sudo or similar, to actually clear out the file. Essentially it always uses sudo since the file never clears.Abbie
@lilone no, every build starts with no sudo file. I'm just creating it as an empty file, because otherwise the eval would not work.Verleneverlie
E
3

To iterate on the answer of Jeff Huijsmans,

an alternative version is to use a Bash variable for docker:

- run:
    name: Set up docker
    command: |
        if [[ $CIRCLE_SHELL_ENV == *"localbuild"* ]]; then
            echo "export docker='sudo docker'" >> $BASH_ENV
        else
            echo "export docker='docker'" >> $BASH_ENV
        fi

Then you can use it in your config

- run:
    name: Verify docker
    command: $docker --version

You can see this in action in my test for my Dotfiles repository

Documentation about environment variables in CircleCi

Eth answered 3/1, 2020 at 13:45 Comment(0)
D
3

You might also solve your issue by running the docker image as root. Specify user: root under the image parameter:

...
jobs:
  build:
    working_directory: ~/app
    docker:
      - image: circleci/node:8.4.0
        user: root
    steps:
      - checkout
      ...
...
Dowling answered 18/11, 2021 at 14:59 Comment(4)
This works but it's heavy-handed and may cause issues for non-trivial setups. In my case, things installed by pip ended up under the root user's dirs and thus not being accessible to scripts.Costmary
@Costmary you can configure pip to get around thatDowling
ok yeah, but that would just fix one specific case - depending on your setup, many more issues might crop up, currently or in the future, due to the "heavy-handedness" of this... you know?Costmary
@Costmary no Im not sure what issues you are referring to. Container is running as root, so it's weaker security, but root is unlimited so I can't see how it would not work. I mean I've never been unable to install something as root that didn't work for root, whereas non-root install will often fail due to missing permissions. Maybe I'm misunderstanding your situation, but that's why in my answer I say "might".Dowling
C
0

Another approach, provided you have access to the host with the self-hosted runner, is to add circleci user to the docker group.

sudo usermod -aG docker circleci
sudo systemctl restart circleci-runner

On a Linux system, only users belonging to the docker group can run docker commands without sudo.

Find user under which the circleci-runner service is running.

systemctl show -pUser,UID circleci-runner
UID=1001
User=circleci

Add circleci user to the docker group.

sudo usermod -aG docker circleci

Restart circleci-runner service for the change to take effect.

sudo systemctl restart circleci-runner

This avoids any changes to config.yml

Chordophone answered 5/6 at 19:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.