Docker outside of Docker (DooD) で GitLab-CI する

更新
2020/04/24 ソースコードを置いてるURLが間違っていたので修正
2020/05/01 感想とコマンド修正

- - -
- 
このポストは、
 [やん事ない理由で Git*.com を使えない日々をオンプレ版 GitLab で乗り切る](https://qiita.com/hykisk/items/18dfa12ecac41f995e99#%E7%92%B0%E5%A2%83) の後続記事です。

## ゴール

1. DOODでCI環境を構築
[公式 -- Use Docker socket binding](https://docs.gitlab.com/ee/ci/docker/using_docker_build.html#use-docker-socket-binding)

2. 下図参照
  **(Start)** http&#58;//192.168.100.201:80/kubolab/tms の master のコミットを契機にCI実行し
  **(End)** http&#58;//192.168.100.201:10080 でアプリ初期画面を見れること。
  ※とりあえず慣れてる CakePHP3 を使いました。

## 感想
先に感想。試行錯誤しながらやったけど、果たしてこの方法が正しいのか自信が無い...。
テストとか動かせるようになったら、次は
コンテナのボリュームマウントをやめてソースコードを入れた状態のコンテナを `Docker Hub` 経由で (Amazon ECS か Azure に...) デプロイしたい。

## 構成図

ソースコード: https://gitlab.com/kubolab/tms/-/tree/gitlab-ci-dood

グループ名、プロジェクト名をブログ投稿用に変更しようかと思ったのですが、手間だったのでそのままです、すんません。

| GitLab グループ名                        | GitLab プロジェクト名              |
| --------------------------- | ---------------- |
|   kubolab        |    tms      |

![GItLab-dood.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134761/650e1259-3241-b7b2-fa7f-e203af9c7d09.png)


## tree

👀: `本来は gitignore に含めるべき`

```bash
.
├── .build
│   ├── build.cmd
│   ├── docker-compose.yml
│   ├── .env
│   └── .project-items 👀
│       ├── app.php # DB接続情報等
│       └── createdb.sql
│
├── app.src
│   ├── config
│   │   └── app.php 👀
│   └── webroot
├── docker
│   ├── build
│   │   ├── cake_app
│   │   │   └── Dockerfile
│   │   └── cake_nginx
│   │       └── Dockerfile
│   ├── config
│   │   └── nginx
│   │       └── default.conf
│   ├── postgres-dump
│   └── sh
│       └── postgres
│           └── docker-entrypoint-initdb.d
│               └── init.sh # docker-compose up 時に実行される
│
└── shared_サーバ配置用 # CI実行前に GitLab サーバに配置しておく。
```

| 項目                        | 内容              |
| --------------------------- | ---------------- |
| オンプレ GitLab の IP          | 192.168.100.201 |
| Host OS                     | Windows 10 Pro 1909      |
| VirtualBox 上の Guest OS      | [前記事参照](https://qiita.com/hykisk/items/18dfa12ecac41f995e99#%E7%92%B0%E5%A2%83)  |
| Guest OS上で動く GitLab ver | [前記事参照](https://qiita.com/hykisk/items/18dfa12ecac41f995e99#%E7%92%B0%E5%A2%83)  |
| GitLab Runner              | 12.9.0          |

| Docker コンテナ名(任意)           | image            | 備考            |
| --------------------------- | ---------------- | ---------------- |
| cake_nginx                  | nginx:1.13.5-alpine | ports: 10080:80 [^1] |
| cake_php                    | php:7-fpm             |   |
| cake_postgres               | postgres:10.3-alpine | ports: 5432:5432  |


## 準備 (GitLab が動くサーバ上で)

1. CI実行時に使用するファイル (バージョン管理に含めないファイル) を手動で配置しておく。
   ※SCP か何かで `/shared_サーバ配置用` を GitLab サーバに配置

    ```
/shared
   └── kubolab
       └── tms
           └── .project-items
               └── app.php      #DB接続情報等
               └── createdb.sql #DB初期データ
    ```

1. GitLab-Runner (gitlab-runner-dd) コンテナ起動

    ⅰ. CentOS に Docker をインストール
      [https://qiita.com/ymasaoka/items/b6c3ffea060bcd237478 -- Install Docker on CentOS 7](https://qiita.com/ymasaoka/items/b6c3ffea060bcd237478)

    ⅱ. GitLab-Runner コンテナ起動

    ```bash
    $ docker run -d --name gitlab-runner-dd --restart always \
        -v /srv/gitlab-runner-dd/config:/etc/gitlab-runner \
        -v /var/run/docker.sock:/var/run/docker.sock \
        gitlab/gitlab-runner:latest

    # GitLab-Runner コンテナに入って実行
    $ docker exec -it gitlab-runner-dd bash

    # docker をインストール
    $ curl -sSL https://get.docker.com/ | sh
    # docker グループに追加
    $ usermod -aG docker gitlab-runner
    ```

1. ジョブを実行する Runner を登録

    ⅰ. 登録

    ★メモしたToken
    参考: https://qiita.com/hykisk/items/ebff2f7cd2e8100a6bbe -- ジョブを実行する Runner を登録

    ```bash
    $ gitlab-runner register -n \
        --url http://172.17.0.1/ \
        --registration-token ★メモしたToken \
        --executor docker \
        --docker-image "docker:stable" \
        --docker-volumes /var/run/docker.sock:/var/run/docker.sock \
        --docker-volumes /shared-builds/kubolab/tms:/builds/kubolab/tms \
        --docker-volumes /shared/kubolab/tms/.project-items:/gitlab-runner-dd/.project-items \
        --tag-list app-build \
        --clone-url = "http://192.168.100.201"
    ```

    >  memo: GitLab にホスト名を割り当ててる場合はクローンに失敗する。オプション `--clone-url` をやめて名前解決を指定する以下を追加。
    > `--docker-extra-hosts "gitlab.private.hykisk.com:172.17.0.1"`

## gitlab-ci.yml

- $CI_PROJECT_PATHは GitLab の既定値によって決まっている。
- 定義した変数(SHARED_BUILDS_DOCKER_DIR)は docker-compose.yml で使用できる。

```/gitlab-ci.yml
stages:
  - doodbuild
variables:
  GIT_STRATEGY: fetch
doodbuild:
  stage: doodbuild
  variables:
    SHARED_BUILDS_DOCKER_DIR: /shared-builds/$CI_PROJECT_PATH
    SHARED_DATA_DIR: /shared/$CI_PROJECT_PATH
  image: docker:stable
  script:
    - cp -pf /gitlab-runner-dd/.project-items/app.php $CI_PROJECT_DIR/app.src/config
    # このコンテナ (gitlab-runner) に docker-compose をインストール
    - apk update && apk add docker-compose
    - docker-compose -f ./.build/docker-compose.yml down
    # Dockerfile に手を加えたら build しなおす
    #- docker-compose -f ./.build/docker-compose.yml down --rmi all --volumes
    #- docker-compose -f ./.build/docker-compose.yml build --no-cache
    - docker-compose -f ./.build/docker-compose.yml up -d
    # アプリに必要なパッケージをインストール
    - docker exec cake_app sh -c "cd /var/www/app && composer install"
  #only:
    #- master
  tags:
    - app-build


```

## docker-compose.yml

```/.build/docker-compose.yml
version: '3'
services:
  web:
    container_name: cake_nginx
    build:
      context: ..
      dockerfile: docker/build/cake_nginx/Dockerfile
    volumes:
      - $SHARED_BUILDS_DOCKER_DIR/app.src:/var/www/app
      - $SHARED_BUILDS_DOCKER_DIR/docker/config/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
      - $SHARED_DATA_DIR/nginx_log:/var/log/nginx
    depends_on:
      - app
    ports:
      - 10080:80
    networks:
      vpcbr:
        ipv4_address: 172.26.0.2
  app:
    container_name: cake_app
    build:
      context: ..
      dockerfile: docker/build/cake_app/Dockerfile
    volumes:
      - $SHARED_BUILDS_DOCKER_DIR/app.src:/var/www/app
    networks:
      vpcbr:
        ipv4_address: 172.26.0.3
  db:
    container_name: cake_postgres
    image: postgres:10.3-alpine
    ports:
      - 5432:5432
    volumes:
      - $SHARED_BUILDS_DOCKER_DIR/docker/data/postgres:/var/lib/postgresql
      # DB作成スクリプトを配置
      - $SHARED_BUILDS_DOCKER_DIR/docker/sh/postgres/docker-entrypoint-initdb.d/init.sh:/docker-entrypoint-initdb.d/init.sh
      - $SHARED_DATA_DIR/.project-items/createdb.sql:/tmp/createdb.sql:ro
    environment:
      POSTGRES_USER: $TMS_POSTGRES_USER
      POSTGRES_PASSWORD: $TMS_POSTGRES_PASSWORD
      POSTGRES_DUMP_FILE_DIR: /tmp
    networks:
      vpcbr:
        ipv4_address: 172.26.0.4
networks:
  vpcbr:
    ipam:
      driver: default
      config:
      - subnet: 172.26.0.0/24

```

> memo: 公開してはいけない情報はブラウザ上 (GitLab のGUI) で設定する環境変数を使用

>```yml
    environment:
      POSTGRES_USER: $TMS_POSTGRES_USER
      POSTGRES_PASSWORD: $TMS_POSTGRES_PASS
>```

http&#58;//192.168.100.201/kubolab/tms/-/settings/ci_cd

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134761/f0645ada-bcc5-96b4-9bef-79e1fceee46d.png" width="650">

## 他ファイル (Dockerfile等) 

ソースコード: https://gitlab.com/kubolab/tms/-/tree/gitlab-ci-dood 参照

## 確認

PUSHしてCIジョブが `created -> running -> passed` になればOK

## 再び構成図 (詳細版)

![GItLab-dood.detail.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134761/afe7c99c-37d6-1f61-9a92-d7f4249742df.png)

- - -

## おまけ

ローカルPC (Docker for Windows インストール済) の開発環境を `/build/build.cmd` **ダブルクリック**で構築。ソース割愛

## 環境構築時に困ったこと

- 問題: コンテナ内で実行するシェルが `Permission denied` で実行できない。
  <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134761/6e611f34-2cfd-0180-1fa8-1d10428ee577.png" width="650">
- 解法: 実行権限を付与する

  ```
  $ git update-index --add --chmod=+x {filepath}
  ```
- - -

- 問題: 試行錯誤中に (CI環境・ローカルPC問わず) Docker の挙動がおかしくなった場合
- 解法: 全消しする

CI環境の場合

```bash
# GitLab サーバで (設定ファイルが残るので削除しておく)
docker exec -it gitlab-runner-dd bash
rm -f /etc/gitlab-runner/config.toml
exit

docker ps -aq | xargs docker rm -f
docker images -aq | xargs docker rmi
docker volume rm $(docker volume ls -qf dangling=true)
docker network rm XXX_vpcbr
```

ローカルPCの場合 (cmd)

```cmd
for /f "usebackq" %x in (`docker ps -aq`) do docker rm -f %x
for /f "usebackq" %x in (`docker images -q`) do docker rmi %x
for /f "usebackq" %x in (`docker volume ls -q`) do docker volume rm %x
docker network rm XXX_vpcbr
```

ローカルPCの場合 (powershell)

```powershell
cd .build
docker-compose down --rmi all --volumes
docker rm -f $(docker ps -aq)
docker rmi -f $(docker images -aq)
docker network rm XXX_vpcbr
```

[^1]: ports: 10080:80<br>Dockerホストにあたる GitLab が80番を使っているため10080番を使う。
   アクセスの流れ:
   1.ブラウザでGitLabサーバに `10080` でアクセス
   2.VirtualBox の[ポートフォワーディングルール](https://qiita.com/hykisk/items/18dfa12ecac41f995e99)で `10080 -> 10080` にマッピング
   3.nginxの設定で `10080 -> 80` にマッピング
    <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134761/0d92a33a-1ddc-ed65-0540-fa39e47cde66.png" width="650">