今更ですが Docker Compose を理解したい！


# はじめに
`docker-compose` を使ってみて、自分なりの理解を備忘としてまとめてみました。

良記事がすでにたくさんありますが、自分でまとめるってやっぱり大事ですよね。

## 本記事の達成目標
* Docker Compose の雰囲気を掴むぞ！
* 環境構築手順は把握したい！
* docker-composeのコマンド、構文をうっすらと理解するぞ！
* 複数のデータベース(PostgreSQL）を扱う場合にどうすべきかは、知っておきたいね

なお、Dockerってなぁに？という部分はあまり書きません（眠気に勝てない…）

<img width="400" alt="IMG_0330.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439602/6866cba0-b950-1abc-4f54-f4b714ac6006.png">


## と言いつつ、まずはDockerをざっくり理解
Dockerとは、コンテナ仮想化環境でアプリケーションを管理・実行するためのオープンソースのプラットフォームです。（眠いから細かい話はGoogle先生にお任せいたします）

Dockerの機能としては、大きく３つに分かれます。

* Dockerイメージを作る機能
* Dockerコンテナを作る機能
* Dockerイメージを公開したり、共有する機能
  * 公式は[Docker Hub](https://hub.docker.com/)
  * 公式以外にも個人で公開しているものも多いですね

この３つの機能を行えるように、 Dockerにはコンポーネントと呼ばれるものががいくつか存在します。

* Docker Engine : イメージ作成、コンテナ起動、コマンド実行など
* Docker Kitematic : GUIツール
* Docker Machine : 実行環境の構築
* Docker Registry : イメージの公開
* Docker Swarm : クラスタ化
* **Docker Compose** : 複数のコンテナを一元管理

このようにたくさんありますが、今回は特に **Docker Compose** というコンポーネントについて理解したいと思います。

一元管理のメリット ： コンテナごとにファイルを作成＆コマンドを実行する…という手順を踏まなくても、１つのファイルと１つのコマンドで全部起動し管理できること

## 環境構築

* Docker
* Docker Compose

上記２つのインストールが必要です。

### Dockerのインストール
Dockerはインストール済みだったので、バージョンのみ確認します。

* Mac OS X 10.14.1 x86_64

```
$ docker -v
Docker version 19.03.5, build 633a0ea
```

### Docker Composeのインストール

確認できたところで、Docker Compose（複数のコンテナを実行・管理するためのツール）をインストールしていきましょー！  
[公式 Install Docker Compose](https://docs.docker.com/compose/install/)　に従って進めていきます。

```
# docker composeのインストール
$ sudo curl -L "https://github.com/docker/compose/releases/download/1.25.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

# 実行権限付与
$ sudo chmod +x /usr/local/bin/docker-compose
```

コマンド実行前の権限が気になったので確認してみると、インストール直前は644でした。

```
# 権限変更前(644で実行権限なし)
$ ls -l
合計 16636
-rw-r--r-- 1 root root 17031320 12月  7 11:27 docker-compose

# 権限変更後(755)
$ ls -l
合計 16636
-rwxr-xr-x 1 root root 17031320 12月  7 11:27 docker-compose
```

最後に、以下コマンドでバージョンが確認できれば環境構築はOKです。

```
$ docker-compose -v
docker-compose version 1.24.1, build 4667896b
```

`docker -v` , `docker-compose -v` で確認したバージョンは、[どの形式で書くか](https://docs.docker.com/compose/compose-file/) に関わってきます。

## docker-compose.ymlを作成

Docker Composeのインストールが終わったので、以下２つのツールが動かせるように `docker-compose.yml` を作っていきたいと思います。

* Concourse CI 
* SonarQube

それぞれ、GitHubに公開されているイメージを使っていきます。

* [concourse/concourse-docker](https://github.com/concourse/concourse-docker)
* [SonarSource/docker-sonarqube](https://github.com/SonarSource/docker-sonarqube/blob/master/recipes/docker-compose-postgres-example.yml)

### 【Concourse CI】 sshキーの作成
 [concourse/concourse-docker](https://github.com/concourse/concourse-docker)のREADME.mdには、`docker-compose` を使うならキー作っとけ！と書かれているので、作りましょう。

> The docker-compose.yml in this repo will get you up and running with the latest version Concourse. To use it you'll first need to execute ./keys/generate - this will generate credentials used to authorize the Concourse components with each-other:

リポジトリごとCloneしてもいいですが、必要最低限だけあればいいかなと思ってローカルで作成してます。

[generateファイル](https://github.com/concourse/concourse-docker/blob/master/keys/generate)はコピーして新規作成

```
# 任意の階層で
$ mkdir keys
$ cd keys
$ mkdir web
$ mkdir worker

# ファイル作成
$ vi generate
#!/usr/bin/env bash

set -e -u

cd $(dirname $0)

docker run --rm -v $PWD/web:/keys concourse/concourse \
  generate-key -t rsa -f /keys/session_signing_key

docker run --rm -v $PWD/web:/keys concourse/concourse \
  generate-key -t ssh -f /keys/tsa_host_key

docker run --rm -v $PWD/worker:/keys concourse/concourse \
  generate-key -t ssh -f /keys/worker_key

cp ./worker/worker_key.pub ./web/authorized_worker_keys
cp ./web/tsa_host_key.pub ./worker
```

sshキーを作成するために、 [generateファイル](https://github.com/concourse/concourse-docker/blob/master/keys/generate)を実行。

```
# generateを実行
$ ./keys/generate
```

[docker-compose-postgres-example.yml](https://github.com/SonarSource/docker-sonarqube/blob/master/recipes/docker-compose-postgres-example.yml)や[concourse-docker/docker-compose.yml](https://github.com/concourse/concourse-docker/blob/master/docker-compose.yml)を参考に、必要な箇所は修正しながら `docker-compose.yml`を作っていきます。

完成したymlはこちら。

```ruby:docker-compose.yml
version: '3.7'  #'3'でも可
services:

  concourse-db:
    image: postgres
    environment:
      POSTGRES_DB: concourse
      POSTGRES_USER: concourse_user
      POSTGRES_PASSWORD: concourse_pass
    logging:
      driver: "json-file"
      options:
        max-file: "5"
        max-size: "10m"

  concourse-web:
    image: concourse/concourse
    command: web
    depends_on: [concourse-db]
    ports: ["8080:8080","2222:2222"]
    volumes: ["./keys/web:/concourse-keys"]
    environment:
      CONCOURSE_EXTERNAL_URL: http://localhost:8080
      CONCOURSE_POSTGRES_HOST: concourse-db
      CONCOURSE_POSTGRES_USER: concourse_user
      CONCOURSE_POSTGRES_PASSWORD: concourse_pass
      CONCOURSE_POSTGRES_DATABASE: concourse
      CONCOURSE_ADD_LOCAL_USER: test:test
      CONCOURSE_MAIN_TEAM_LOCAL_USER: test
    logging:
      driver: "json-file"
      options:
        max-file: "5"
        max-size: "10m"

  concourse-worker:
    image: concourse/concourse
    command: worker
    privileged: true
    depends_on: [concourse-web]
    volumes: ["./keys/worker:/concourse-keys"]
    stop_signal: SIGUSR2
    environment:
      CONCOURSE_TSA_HOST: concourse-web:2222
    logging:
      driver: "json-file"
      options:
        max-file: "5"
        max-size: "10m"

  sonarqube:
    image: sonarqube
    depends_on: [sonarqube-db]
    ports:
      - "9000:9000"
    networks:
      - sonarnet
    environment:
      - sonar.jdbc.url=jdbc:postgresql://sonarqube-db:5432/sonar
    volumes:
      - sonarqube_conf:/opt/sonarqube/conf
      - sonarqube_data:/opt/sonarqube/data
      - sonarqube_extensions:/opt/sonarqube/extensions
      
  sonarqube-db:
    image: postgres
    networks:
      - sonarnet
    ports:
      - 5433:5432
    environment:
      - POSTGRES_DB=sonar
      - POSTGRES_USER=sonar
      - POSTGRES_PASSWORD=sonar
    volumes:
      - postgresql:/var/lib/postgresql
      # This needs explicit mapping due to https://github.com/docker-library/postgres/blob/4e48e3228a30763913ece952c611e5e9b95c8759/Dockerfile.template#L52
      - postgresql_data:/var/lib/postgresql/data
      
networks:
  sonarnet:
    driver: bridge

volumes:
  sonarqube_conf:
  sonarqube_data:
  sonarqube_extensions:
  postgresql:
  postgresql_data:
```

## Docker Compose 起動

```
# docker-compose.ymlのあるディレクトリで実行
$ docker-compose up -d

# 無事に起動したか確認
$ docker-compose ps
           Name                          Command              State              Ports            
--------------------------------------------------------------------------------------------------
xxx_concourse-db_1       docker-entrypoint.sh postgres   Up      5432/tcp                    
xxx_concourse-web_1      dumb-init /usr/local/conco      Up      0.0.0.0:2222->2222/tcp,     
                              ...                                     0.0.0.0:8080->8080/tcp      
xxx_concourse-worker_1   dumb-init /usr/local/conco      Up                                  
                              ...                                                                 
xxx_sonarqube-db_1       docker-entrypoint.sh postgres   Up      0.0.0.0:5433->5432/tcp      
xxx_sonarqube_1          ./bin/run.sh                    Up      0.0.0.0:9000->9000/tcp 
```

全て `up` になっていれば、OKです。

以下ポートでアクセスして、Concourse CIやSonarQubeの初期画面が表示されます。
ログインもちゃんとできますよ！

* SonarQube ： [http://localhost:9000](http://localhost:9000)
  * login： `admin` , password： `admin`
* Concourse CI ： [http://localhost:8080](http://localhost:8080)
  * username： `test` , password： `test`

### 実際どうなっているの？
`docker-compose.yml` では、全部で5つのコンテナを管理するように書きました。

* **concourse-db** ： Concourse CIのデータベース（ポート：5432）
* **concourse-web** ： Concourse CIのWebサーバ（ポート：8080)
* **concourse-worker** ： ジョブの実行を行うWorker(おそらく任意）
* **sonarqube** ： SonarQubeのWebサーバ（ポート：9000)
* **sonarqube-db** ： SonarQubeのデータベース(ポート：5433）

ちょっとわかりにくいのでお絵描きすると、こんなイメージ。（手書きが好きなので、汚いですがお許しください！）

<img width="500" alt="IMG_0330.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439602/6866cba0-b950-1abc-4f54-f4b714ac6006.png">

### 起動開始順
 `depends_on` を使って、各コンテナが起動する順番を指定しています。
**こいつは〇〇のあとで起動始めるよ！**と設定できる…ということです。

以下が今回の起動順です。

* Concourse CI
  * concourse-db ⇨ concourse-web ⇨ concourse-worker  

* SonarQube
 * sonarqube-db ⇨ sonarqube

データベースを一番最初に起動するのは、Webサーバがデータベースの起動前にアクセスしに行って落ちるのを出来るだけ防ぐためです。

なお、 `depends_on` で指定できるのはあくまでも起動開始順であって、起動が終わるのを待って次に…というわけではないので注意すること。


## 最後に
細かい設定や構文の話が長くなりそうだったので、分割して書くことにしました。

1. `docker-compose.yml` の構文やコマンド、各コンテナの連携の話
2. Concourse CI + SonarQube + GitLabを使って、ソースコードレビューの自動化についての話

を続編として書きます。

書き始めてはいるものの、まだ途中までしか書けていないので完成次第リンクを貼ります。

参考文献：プログラマのためのDocker教科書