Dockerのコマンドラインからdocker-compose.ymlまでの使い方

どうもこんにちは、たくびー(@takubii)です。

今回はDockerの理解を順序立てて行えるようにDockerコマンドからdocker composeまでを解説していこうと思います。
さまざまなサイトで、よくdocker composeを使って環境構築がされています。
Dockerの知識が不足している状態で利用すると、ついていけなくなる感じがします。
そうならないように、docker composeが何をやっているのか、分かりやすく説明していきたいと思います。


# 開発環境について

今回は以下のような前提で行なっています。

- Mac OS
- Docker
- Macのterminal操作が少しできる
- Dockerの用語について少しの知識がある(コンテナやイメージなど)


# Dockerコンテナの構築をCLIのコマンドのみで行う

まずはDockerコンテナを作成するために愚直にterminalから行っていきます。
最初にコマンドで環境構築することはコンテナの理解が深まるのでおすすめです。

とりあえず今回はDjangoの開発環境を構築すると仮定し、以下のようなディレクトリ構成で行います。

```docker-python
.
└── requirements.txt
```

`requirements.txt`はシンプルにDjangoのみでいいでしょう。

```txt:requirements.txt
Django
```

## コンテナの作成
以下、コマンドを一つずつ見ていきます。

`docker hub`というところからDockerイメージを取得します。
今回はDjangoの環境を作りたいので、Pythonの最新(2023/10/2現在)のイメージを取得します。

```zsh:terminal
docker pull python:3.11.5
```

少し、長いですが以下のコマンドでコンテナを作成します。
各オプションについてはこの後すぐに解説します。

```zsh:terminal
docker run -it -d --name docker-python -p 8000:8000 -e TZ=Asia/Tokyo -e LANG=C.UTF-8 -v ~/work/playground/docker-python:/docker-python python:3.11.5
```

`docker run`コマンドのオプションについて、上記で設定したものを以下の表にまとめました。

| オプション | 説明 |
|:-:|:-:|
| -it | コンテナで出入力を行うためのオプション |
| -d | デタッチモードで作成するオプション、これをつけるとバックグラウンドで作成します |
| --name docker-python | コンテナ名を指定するオプション、「docker-python」の部分を任意の名前に変更できます |
| -p 8000:8000 | ポートを指定し、コンテナを外部に公開するオプション、左がホスト側のポートで、右側がコンテナ側のポート |
| -e TZ=Asia/Tokyo -e LANG=C.UTF-8 | `-e`でそれぞれの環境変数を設定するオプション |
| -v ~/work/playground/docker-python:/docker-python | ホストマシンとコンテナで指定したフォルダをマウントするオプション、それぞれの環境で編集すると変更内容が反映されます |

作成したコンテナに入るためのコマンドです。

```zsh:terminal
docker exec -it docker-python bash
```

## コンテナ内での作業

コンテナ内でアプリを作成するためのフォルダへ移動します。
Macのコマンドと同じなので普段terminalを触っているとお馴染みかもしれません。

```bash
cd docker-python/
```

Djangoをインストールします。

```bash
pip install --upgrade pip
pip install -r requirements.txt
```

Djangoが正常にインストールされていれば、以下のコマンドでバージョンが確認できます。

```bash
python -m django --version
```

お疲れ様です。
これでコンテナにDjangoの開発環境を構築することができました。
コンテナから抜ける場合は以下の通りです。

```bash
ctrl + p + q
または
exit
```

## 後始末

最後に作成したコンテナの削除方法です。
`-f`オプションを指定してコンテナが動いていても削除できるようになっています。

```zsh
docker rm -f docker-python
```

## ここまで

コマンドで作成する場合、コンテナの作成、コンテナ内での環境構築、後始末といった一連の作業が必要になります。
これらの作業が今後どんどん楽になっていきますので、続けてみていきましょう。

# Dockerfileを使って構築を行う

先ほどと少しディレクトリ構成を変えました。
`django-app`というディレクトリを作成し、その中に`requirements.txt`を入れます。
`django-app`と同じ階層に`Dockerfile`というファイルも作成しています。

```docker-python
.
├── Dockerfile
└── django-app
    └── requirements.txt
```

`Dockerfile`は以下のように書いてください。

```Dockerfile
FROM python:3.11.5

ENV TZ=Asia/Tokyo
ENV LANG=C.UTF-8

WORKDIR /django-app

COPY ./django-app/requirements.txt /django-app/
RUN pip install --upgrade pip && pip install -r requirements.txt
```

## コンテナの作成

まずは先ほど作成した`Dockerfile`のイメージを作成します。
`docker build`コマンドを使用します。
イメージ名は次のようにできます。`-t [image名]`
最後の`.`は現在のディレクトリを指定しているので忘れないようにしてください。

```zsh:terminal
docker build -t python-django .
```

先ほどコンテナを作成した時と同じように`docker run`コマンドを使います。
最後のイメージの指定だけ、今作成したイメージに変更してください。

```zsh:terminal
docker run -it -d --name docker-python -p 8000:8000 -v ~/work/playground/docker-python/django-app/:/django-app python-django
```

コンテナの中に入ります。

```zsh:terminal
docker exec -it docker-python bash
```

## コンテナ内での作業

`Dockerfile`に作業内容を書いていたので、再度のディレクトリ変更やDjangoのインストールの手順は省略できます。

```bash
pwd (現在のディレクトリの確認)
python -m django --version
```

## 後始末

先ほどと同じ手順でコンテナから抜けて、以下のコマンドでコンテナを削除しておきましょう。
この手順は一緒ですね。

```zsh:terminal
docker rm -f docker-python
```

## ここまで

CLIのみで行っていた時に比べてコンテナ内での作業が減っていることが分かります。
Dockerfileではコンテナを作成する時に行っておきたい事前準備を書くことで初期構築のスピードを上げ、同じ環境の作成に役立ちます。

# docker-compose.ymlを使って構築を行う

今回は以下のようなディレクトリ構成になっています。
`docker-compose.yml`が追加されています。

```docker-python
.
├── Dockerfile
├── django-app
│   └── requirements.txt
└── docker-compose.yml
```

`docker-compose.yml`は以下のように記載してください。

```yml:docker-compose.yml
version: '3'

services:
  app:
    build: .
    volumes:
      - ./django-app:/django-app
    ports:
      - '8000:8000'
    tty: true
```

## コンテナの作成

まずはコンテナ作成を行います。

```zsh:terminal
docker compose up -d
docker ps (作成したコンテナの名前を確認)
docker exec -it docker-python-app-1 bash
```

通常コンテナ名は`{docker-compose.ymlのあるディレクトリ}-{servicesの名前}-{1}`という命名になっていると思います。
`docker compose up -d`の`-d`はデタッチモードで作成というオプションなので、バックグラウンドで作成を行います。

## コンテナ内での作業

コンテナ内で現在のディレクトリとDjangoがインストールされているか確認します。

```bash
pwd (現在のディレクトリの確認)
python -m django --version
```

## 後始末

コンテナから出たら、最後にコンテナを削除します。

```zsh:terminal
docker compose down
```

## ここまで

今まで書いていた`docker run`コマンドが無くなり、コマンドを打つ量が圧倒的に減りました。
そして、後始末もコマンド一発で終わるようになりました。現在はコンテナ1つのみなので恩恵は薄いかもしれませんが、コンテナが増えていくにつれて`docker-compose.yml`の便利さは増していきます。

# 終わりに
Dockerコンテナの作成方法を段階的に3つ見てきました。
順番に見ていくと`Dockerfile`、`docker-compose.yml`がコンテナ作成の際に何を楽にしてくれるのかわかると思います。
さらに作成するコンテナを増やしていくと便利さが際立ってくるので、DB用のコンテナなども追加していろいろといじってみると理解が深まるでしょう。

この記事がDockerやDockerfile、docker-compose.ymlなどの理解を助けになれば幸いです。

それでは今回はこの辺りで締めたいと思います。
ここまで読んでいただきありがとうございます。
また機会があればお会いしましょう。