Docker:在使用本地CircleCI构建时尝试连接到Docker守护程序时出现权限被拒绝的错误。

11

我有一个非常简单的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 .

它的作用很简单:启动一个 node 镜像,测试 node 是否正在运行,进行 yarn installdocker build
我的 Dockerfile 没有什么特别之处,只有 COPY 和 ENTRYPOINT。
在我的 MacBook Air 上使用 Docker Native 运行 circleci build 时,我会收到以下错误信息: Got permission denied while trying to connect to the Docker daemon socket at unix://[...] 如果我将 docker build . 命令更改为 sudo docker build .,在本地使用 circleci build 时,一切都按计划进行。 然而,将此更改推送到 CircleCI 将导致错误:Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running? 因此,总结一下:在本地使用 sudo 可以正常工作,但在 CircleCI 自身上无法正常工作。在 CircleCI 上不使用 sudo 可以正常工作,但在本地上无法正常工作。
这是 CircleCI 工作人员需要解决的问题,还是我可以做些什么? 供参考,我也在 CircleCI 论坛上发布了这个问题。
3个回答

8

我已经为自己创建了一种解决方法。

在config.yml的第一步中,我运行了以下命令:

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

之后,您可以执行以下操作:

eval `cat ~/sudo` docker build .

说明:

第一段代码检查CircleCI提供的环境变量CIRCLE_SHELL_ENV中是否包含localbuild。只有在本地计算机上运行circleci build时才为真。 如果是真的,它会在主目录中创建一个名为sudo的文件,并将其内容设置为sudo。 如果是假的,它会在主目录中创建一个名为sudo的文件,但不包含任何内容。

第二段代码打开~/sudo文件,并使用您之后给出的参数执行它。如果~/sudo文件包含“sudo”,则此示例中的命令将变为sudo docker build .,如果它不包含任何内容,则它将变为docker build .,其中有一个空格,但这将被忽略。

这样,本地(circleci build)构建和远程构建都可以正常工作。


3
这是一个很好的解决方法,但很遗憾他们的CLI不能处理这种情况... - Nathaniel Ford
我相信你的 touch ~/sudo 不会清空文件。应该使用 : > ~/sudo 或类似的命令来真正清空文件。因为文件从未被清空,所以它始终使用 sudo - lilole
@lilone 不,每个构建都不会有sudo文件。我只是创建一个空文件,否则eval将无法工作。 - Jeff Huijsmans

3

您也可以通过以root用户身份运行docker镜像来解决问题。在image参数下指定user: root

...
jobs:
  build:
    working_directory: ~/app
    docker:
      - image: circleci/node:8.4.0
        user: root
    steps:
      - checkout
      ...
...

这种方法虽然可行,但是有些过于粗暴,对于复杂的设置可能会引起问题。在我的情况下,通过 'pip' 安装的文件最终存储在 root 用户的目录下,因此不能被脚本访问。 - Paul
@Paul,你可以配置pip来解决这个问题。 - Oliver
1
好的,但这只能解决一个具体问题 - 根据您的设置,由于此操作的“重手”,当前或将来可能会出现更多问题,你懂的? - Paul
@Paul,我不确定你指的是哪些问题。容器正在以root身份运行,因此安全性较弱,但root是无限制的,所以我看不出为什么它不会工作。我的意思是,我从来没有遇到过像root那样无法安装某些东西而对root有效的情况,而非root安装通常会由于缺少权限而失败。也许我误解了你的情况,但这就是为什么在我的答案中我说“可能”。 - Oliver

3

在Jeff Huijsmans的回答基础上,另一种选择是使用Bash变量来代替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

然后您可以在配置文件中使用它

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

您可以在我的 Dotfiles 存储库的测试中看到此操作的实际效果。

CircleCi 中关于环境变量的文档


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接