Posted at

CircleCI Local で setup_remote_docker を使えるようにする

More than 1 year has passed since last update.

CircleCI 2.0 は docker ネイティブなので、setup_remote_docker をすることで docker を使ったテストやビルド等の様々なジョブが実行できます。

しかしながら、例えば docker volume create をやっている場合は、CLI だとそのままでは以下のようなエラーが出てしまいます。

Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Post http://%2Fvar%2Frun%2Fdocker.sock/v1.38/volumes/create: dial unix /var/run/docker.sock: connect: permission denied

いろいろと不便なので、なんとかしてみた結果がこちら。


結論

config.yml の steps の序盤で以下の処理を実行すれば解決。

if [[ $CIRCLE_SHELL_ENV =~ "localbuild" ]]; then

sudo chown root /usr/bin/docker
sudo chmod u+s /usr/bin/docker
fi


調査内容メモ

とりあえず setup_remote_docker した後、sleep をかますだけの config を用意。(10分で強制的に切れるようです)


circleci/config.yml

version: 2

jobs:
build:
working_directory: ~/app
docker:
- image: circleci/python:3.6
steps:
- setup_remote_docker
- run:
name: test
command: sleep 600

circleci local execute で実行。

% circleci local execute

Docker image digest: sha256:525c91e01875050fbf65cdb4bc83a45744c54f9027fa05f76f88713f3d37f4e3
====>> Spin up Environment
Build-agent version 0.0.7725-9681bc36 (2018-08-09T15:10:50+0000)
Starting container circleci/python:3.6
using image circleci/python@sha256:3d2fcd53ad4b75c4e7cdeb0bbf18264ffa708c4a9216dbbe419df786c9c8310e

Using build environment variables:
BASH_ENV=/tmp/.bash_env-localbuild-1536222453
CI=true
CIRCLECI=true
CIRCLE_BRANCH=xxxxxxxx
CIRCLE_BUILD_NUM=
CIRCLE_JOB=build
CIRCLE_NODE_INDEX=0
CIRCLE_NODE_TOTAL=1
CIRCLE_REPOSITORY_URL=git@github.com:xxxxxxxx.git
CIRCLE_SHA1=2760e26695363d6497c2c236709a705db92d0009
CIRCLE_SHELL_ENV=/tmp/.bash_env-localbuild-1536222453
CIRCLE_WORKING_DIRECTORY=~/app

====>> Setup a remote Docker engine
Using local docker engine bind-mounted
====>> test
#!/bin/bash -eo pipefail
sleep 600

Using local docker engine bind-mounted と言ってます。

sleep したところで、別ターミナルで docker ps してみると、circleci/picard(CLI 本体)と circleci/python:3.6(メインコンテナ)が動いてます。

% docker ps

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e1ebbeccc823 circleci/python:3.6 "/bin/sh" 7 seconds ago Up 5 seconds vigorous_brattain
16ba46868114 circleci/picard "circleci build" 9 seconds ago Up 7 seconds hardcore_murdock

docker inspect してみると、circleci コマンドが動かすコンテナはどうやら /var/run/docker.sock を /var/run/docker-temp.sock としてマウントしており、docker コマンドが入っているイメージ(circleci/python:3.6 等)を使えばそのまま接続できそうです。

% docker inspect vigorous_brattain

...snip...
"Mounts": [
{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Destination": "/var/run/docker-temp.sock",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
},
...snip...

docker exec で覗いてみます。

% docker exec -it vigorous_brattain bash

circleci@e1ebbeccc823:/$ ls -al /var/run
lrwxrwxrwx 1 root root 4 Aug 31 00:00 /var/run -> /run
circleci@e1ebbeccc823:/$ ls -al /run
total 16
drwxr-xr-x 1 root root 4096 Sep 6 08:33 .
drwxr-xr-x 1 root root 4096 Sep 6 08:33 ..
srw-rw---- 1 root root 0 Sep 5 02:54 docker-temp.sock
lrwxrwxrwx 1 root root 25 Sep 6 08:33 docker.sock -> /var/run/docker-temp.sock
drwxr-x--- 2 Debian-exim Debian-exim 4096 Sep 6 00:06 exim4
drwxrwxrwt 2 root root 4096 Aug 31 00:00 lock
-rw-rw-r-- 1 root utmp 0 Aug 31 00:00 utmp

/var/run/run への symlink、さらに /run/docker.sock/var/run/docker-temp.sock になっています。

普通に docker run すると、件のエラーが出ます。

circleci@e1ebbeccc823:/$ docker run --rm -it busybox

docker: Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Post http://%2Fvar%2Frun%2Fdocker.sock/v1.38/containers/create: dial unix /var/run/docker.sock: connect: permission denied.
See 'docker run --help'.

せっかくローカルでは Docker for Mac が動いているのに permission denied とは惜しい感じですが、sudo かますと繋がります。

circleci@e1ebbeccc823:/$ sudo docker run --rm -it busybox

/ #

ただ、config.yml の docker コマンドに sudo をつけてしまうと変更箇所が多いのと、circleci.com 上で動かなくなってしまうので、コマンド自体は変更せずに setuid でやってみます。

circleci@e1ebbeccc823:/$ which docker

/usr/bin/docker
circleci@e1ebbeccc823:/$ ls -al /usr/bin/docker
-rwxr-xr-x 1 1000 1000 37589867 Aug 21 17:29 /usr/bin/docker

オーナーが root ではなく uid:1000 になっているので、chown と chmod のコンボで。

circleci@e1ebbeccc823:/$ sudo chown root /usr/bin/docker

circleci@e1ebbeccc823:/$ sudo chmod u+s /usr/bin/docker
circleci@e1ebbeccc823:/$ ls -al /usr/bin/docker
-rwsr-xr-x 1 root 1000 37589867 Aug 21 17:29 /usr/bin/docker

sudo なしで動くかどうか確認してみます。

circleci@e1ebbeccc823:/$ docker run --rm -it busybox

/ #

無事 setuid した状態で動きました。

後は、circleci.com と local の切り分けですが、circleci local execute した際には CIRCLE_SHELL_ENV に localbuild という文字が含まれるので、これを検知して chown/chmod するように、config.yml の序盤の step に仕掛ければ良いことになります。