Dockerで動くJenkinsから他のコンテナを操作する（Docker outside of Docker）

Dockerコンテナ内で動くJenkinsから、ホスト側のDockerを使って他のDockerコンテナを動かす、いわゆる**Docker outside of Docker(DooD)**に必要な設定のメモです。

## 前提

- JenkinsもDockerコンテナで動く
- Jenkinsコンテナのユーザーはjenkins（root以外）とする
- 各Dockerコンテナは同一ホスト内で動く
- 複数のDockerコンテナが動くためdocker-composeを利用する

## 環境
- ホストOS：Oracle Linux 7.7（Red Hat 7.7）
- docker 18.09.1
- docker-compose 1.24.1
- Jenkins(Dockerイメージ）2.60.3

ホスト側のSELinuxはオフにしています。

## ファイル構成
docker-composeを使うのでこのような構成になります。

```console
docker
├─ .env
├─ docker-compose.yml
├─ jenkins
|   ├─ Dockerfile
……
```

## ファイル定義
### JenkinsのDockerfile
JenkinsのDockerfileです。

```docker:Dockerfile
FROM jenkins/jenkins:lts

USER root

# add jenkins user
RUN mkdir /home/jenkins && chown jenkins:jenkins /home/jenkins && usermod -d /home/jenkins jenkins

# add docker group
ARG DOCKER_GROUP_ID
RUN groupadd -g ${DOCKER_GROUP_ID} docker && usermod -aG ${DOCKER_GROUP_ID} jenkins

# install docker, docker-compose
ENV DOCKER_VERSION 18.09.1
RUN curl -fL -o docker.tgz "https://download.docker.com/linux/static/test/x86_64/docker-$DOCKER_VERSION.tgz" && \
    tar --strip-component=1 -xvaf docker.tgz -C /usr/bin

RUN curl -L https://github.com/docker/compose/releases/download/1.24.1/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose && chmod +x /usr/local/bin/docker-compose

USER jenkins
```

ポイントとしてはコンテナユーザーをjenkinsとしており、コンテナ内でsudoせずに済むようにホスト側のdockerグループID（`DOCKER_GROUP_ID`）を追加しています。`DOCKER_GROUP_ID`は後述する`.env`→`docker-compose.yml`という流れでJenkinsのDockerfileに渡されます。

### docker-compose
`docker-compose.yml`（Jenkins部分抜粋）です。

```yaml:docker-compose.yml
version: '2'
services:
  jenkins:
    build:
        context: ./jenkins
        args:
           - DOCKER_GROUP_ID=${DOCKER_GROUP_ID}
    ports:
        - 8080:8080
    volumes:
        - /var/jenkins:/var/jenkins_home
        - /var/run/docker.sock:/var/run/docker.sock
```

`build`の引数として`DOCKER_GROUP_ID`を渡します。これはホスト側のdockerグループIDで、後述の`.env`ファイル内に定義します。

`volumes`で`/var/run/docker.socket:/var/run/docker.sock`を指定することにより、ホスト側のdockerソケットをJenkinsコンテナ内にマウントします。これでJenkinsコンテナ内のdockerコマンドで同じホストで動く他のコンテナを操作できます。

### .env
`docker-compose.yml`と同じ階層に`.env`を置くことで外部パラメーターとして値を渡すことができます。

```config:.env
DOCKER_GROUP_ID=992
```

`DOCKER_GROUP_ID`にホスト側のdockerグループIDを指定します。

## 確認
JenkinsのDockerコンテナに入って`docker`コマンドが実行できれば完了です。

```console
[docker@host]$ sudo docker exec -it docker_jenkins_1 /bin/bash
jenkins@6a642404e172:/$ docker version
Client: Docker Engine - Community
 Version:           18.09.1
 API version:       1.39
 Go version:        go1.10.6
 Git commit:        4c52b90
 Built:             Wed Jan  9 19:33:22 2019
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
 Version:          18.09.1-ol
 API version:      1.39 (minimum version 1.12)
 Go version:       go1.10.8
 Git commit:       e32a1bd
 Built:            Thu Jun  6 14:47:41 2019
 OS/Arch:          linux/amd64
 Experimental:     false
```

今回はdocker-compose.ymlで構成しましたが単独コンテナで動かす場合でも、構成は大きく変わらないはずです。


### 参考

[docker上のjenkinsでdockerを実行](https://qiita.com/uni-3/items/62f072954edb67a1e58d)
[dockerでvolumeをマウントしたときのファイルのowner問題](https://qiita.com/yohm/items/047b2e68d008ebb0f001)
[Dockerfile ARG入門](https://qiita.com/nacika_ins/items/cf8ceb20711bd077f770)
[jenkinsのdockerイメージからホストのdockerが使えるようにするDockerfile（docker in docker）](https://miya15.hatenablog.com/entry/2018/09/08/161253)
[DockerのVolumeのアクセス権限の問題について](https://qiita.com/mrk_21/items/137b0c39e09c3ed6c95a)