改めてDockerを理解する⑧[Docker Composeについて]

## はじめに
こんにちは！ITスクールRareTECHにてCS（Customer Support）を担当している池村です。今回の記事はDocker Composeについてです。連続した記事ですので、まだDockerの基本の記事を読んでいない方はそちらから先に読んでいただけますと幸いです。

①はこちら

https://qiita.com/ikemura-ren/items/dae9f599254b90167b06


前回の記事はこちら

https://qiita.com/ikemura-ren/items/3debbe2ba8997a95e6b5

![bb53937f-cf16-442c-9080-14defbe54afe_720.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798971/2353ff9a-b2e2-c704-7ca0-43a6ef72d847.png)


## Docker Composeとは
Docker Composeとは、複数のコンテナを一括管理・実行してくれる便利なツールです。
前回の記事ではDockerfileを作成しましたが、あれは一つのコンテナのイメージを作るための仕組みでした。今度はもう必要なコンテナを全部まとめちゃえ！という考え方です。

:::note info
エンジニアというのはめんどくさがりですね。大事な要素ですが。
:::

#### YAMLファイル
Docker Composeを動かすためにはYAMLファイルを作成する必要があります。
YAMLファイルは様々な設定ファイルに使われています。Dockerfileとはまた書き方が違うので注意して細かく見ていきましょう。

YAMLファイルの基本的な構文を見ていきましょう。
```YAML:基本構文
# キーと値の関係
key: value

# リスト（複数の値に順序をつけて表現しているもの）
# 以下のような形
fruits:
  - apple
  - peach
  - banana

# ネスト（インデントで階層を表現し、関連したデータをグループ化する）
# 以下のような形
customor:
  name: ikemura
  age: unknown
  address:
    city: tokyo
```

:::note info
基本的には上記の書き方を覚えておきましょう。
インデント（空白）は2文字分で下の階層に降りるイメージです。
:::


## 簡単なYAMLファイルを書いて、実際に動かしてみよう！

まずはものすごく簡単なサンプルを使ってみましょう。
どのディレクトリでもいいので（ホーム以外）、`docker-compose.yml`というファイルを作成して、以下のサンプル内容を書き込んでください。
#### サンプル
```YAML:サンプル
version: "3.9"
services:
  web:
    image: nginx:latest
    ports:
      - "8080:80"
```
各項目を見ていく前に動かしてみましょうか。
```Bash:YAMLファイルを実行
docker compose up
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798971/764e0cef-388a-c8ea-d175-aac7d07c1085.png)

ではブラウザで検証してみましょう。

http://localhost:8080/

以下のような実行結果になっていればOKです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798971/f980d0fe-412b-aa77-0a6a-a9f31575020e.png)

:::note warn
サーバーをストップする際は`Ctrl + c`(Win)、`control + c`（Mac）をご利用ください。
:::


### YAMLファイルの中身をみていこう
では早速中身の書き方と要素を見ていきましょう。
#### 1. `version`
こちらはDocker Composeファイルのバージョンになります。Composeを動かすためのファイルにはバージョンがあり、少しずつ改良されてきています。
- バージョン1系列：非推奨（使わない）
- バージョン2系列：このバージョンも使われてはいる
- バージョン3系統：**基本的にここを使っているファイルが多め**

### と、ちょっと説明しましたが、実はこの記述いらなくなりました（笑）

:::note warn
なんで説明したのかというと、後方互換がしっかり残っているからです。
というかまだ世の中の`docker-compose.yml`ファイルにはこの記述が残っているので、業務上見る機会も多いかな？と思って紹介しました。
:::

実は`up`した時にも警告は出ているはずです。
```Bash:警告文
WARN[0000] /Users/ren/Training/Linux/docker-compose.yml: the attribute `version` is obsolete, it will be ignored, please remove it to avoid potential confusion
```
内容は

:::note warn
WARN[0000] /Users/ren/Training/Linux/docker-compose.yml: 属性 `version` は廃止されました。
:::
というものです。先ほどのサンプルからバージョン指定を消すと、この警告は現れなくなります。お時間があったらお試しください。

#### 2. `services`
この記述はコンテナで定義する各種サービスを定義しています。
今回のサンプルには`web`と書かれていますが、特に決まった記述が必要なわけではありません。ただ、わかりやすい名前をつけるのが基本になります。
今回はwebサーバーなので、`web`とつけました。
一応命名のルールはあります。
- サービス名は任意だが、英数字とハイフン（-）を使うのが一般的
- サービス名は同じYAMLファイル内で一意である必要がある（名前被っちゃだめ）

```YAML:こんな書き方でも大丈夫です
services:
  frontend:
    image: nginx:latest
  backend:
    build: ./backend
  database:
    image: mysql:latest
```

**image**：コンテナイメージのことです。
**build**：後述します。

#### 3. `build`
ご自身で作成したDockerfileを指定できるものです。
```YAML:基本的な要素
build:
  context: ./backend
  dockerfile: Dockerfile
```

:::note warn
ここでいう `.` ですが、要するにdocker-compose.ymlファイルがある場所を指しています。
:::

想定するディレクトリ構成は以下のような形です。
```Bash:ディレクトリ構成
project/
├── backend/
│   ├── Dockerfile
│   ├── app.py
│   └── requirements.txt
├── docker-compose.yml
```

#### 4. `ports`
次は`ports`ですが、これは名前の通りポート番号を指定できるところですね。
今まで直接コマンドで打ち込んでいたポートフォワーディング部分です。
```YAML:基本的な書き方
ports:
  - "ホストポート:コンテナポート"

# Nginxなら
"8080:80"

# Flaskなら
"5000:5000"
```
もうコマンドから解放されてスッキリです。


#### 5. `volumes`
ここはボリュームですね。覚えていますか？ボリューム。
忘れいている方は以下のリンクから復習しましょう。

https://qiita.com/ikemura-ren/items/d9de3d767bdeca3bf089

```YAML:基本的な書き方
volumes:
  - "ホストパス:コンテナパス"

# Flaskの場合
services:
  flask:
    build:
      context: .
    ports:
      - "5000:5000"
    volumes:
      - ./src:/app
```

これは以下のディレクトリ構成を考えています。
```Bash:ディレクトリ構成
flask_project/
├── src/
│   ├── app.py
│   ├── requirements.txt
├── docker-compose.yml
├── Dockerfile
```
1. Dockerfileはdocker-compose.ymlファイルと同じディレクトリにあるので `.`
1. Flaskのデフォルトポート番号なので`5000`をマッピング
1. volumesはapp.pyがあるディレクトリと、バインドマウントしている

:::note info
一旦ここまでの要素だけで、ひとつのコンテナをComposeで動かせるようになりました。では実際にこのディレクトリを作成してみて動かしてみましょう！
:::



```Bash:環境構築
mkdir -p flask_project/src && touch flask_project/src/app.py flask_project/src/requirements.txt flask_project/docker-compose.yml flask_project/Dockerfile
```

Dockerfileの中身は以下を記述してみて下さい。
```Dockerfile:Dockerfile
FROM python:3.9-slim

WORKDIR /app

COPY ./src /app

RUN pip install --no-cache-dir -r requirements.txt

CMD ["python", "app.py"]
```

次にdocker-compose.ymlファイルは以下です。
```YAML:docker-compose.yml
services:
  flask:
    build:
      context: .
    ports:
      - "5001:5000"
    volumes:
      - ./src:/app
```

srcディレクトリの中のapp.pyは以下を記述しましょう。
```Python:app.py
from flask import Flask

app = Flask(__name__)

@app.route("/")
def home():
    return "Hello Qiita!!"

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)
```

requirements.txtはFlaskだけ記述お願いします。
```Text:requirements.txt
Flask
```

これで準備は整ったので、動かしていきましょう。
```Bash:いざ実行
docker compose up
```

以下のような結果になりましたか？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798971/9a28548f-fd1f-c969-9c98-e0a532e37370.png)

この状態でコンテナは動いていますので、また以下のリンクからブラウザにアクセスしてみて下さい。

http://localhost:5000/

画面にHello Qiita!と出ていれば成功です！

## おわりに
まずはここまで、Composeの基礎は学べたかと思います。
記事がかなり長くなりそうだったので、複数コンテナの連携は省きました。
Docker Composeは複数コンテナを繋いでこそ本領発揮です。次回の記事ではそちらをじっくりみていきましょう。

次の記事はこちら👇

https://qiita.com/ikemura-ren/items/2140694831149324b258

まとめ記事に戻るにはこちら👇

https://qiita.com/ikemura-ren/items/b961642d55e4e6515203

## 余談
最近グミをよく食べています。美味しい