Webアプリ開発においてよく使うDockerの基礎概念とコマンドのまとめ

## 概略
たまにしかDockerを触らずに忘れちゃうので備忘録として残しておくものです。
Webアプリ開発時によく使う項目を自分用にまとめました。

## 基本のコマンドと図解

```
docker run -it ubuntu bash
```
ubuntuのコンテナを起動して、そのコンテナの中のbashを起動する

流れとしては
ホストにubuntuのイメージがなければdockerhubから持ってくる
そのubuntuのイメージからコンテナを起動
コンテナの中のbashを起動する

-itオプションによって、コンテナの中に入って作業できる
コンテナから出るときは'exit'

runはイメージからコンテナを起動してコマンドを実行する
execは既存のコンテナでコマンドを実行する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3480176/99b3431c-7470-526b-a872-9c2cdedc8207.png)


## Dockerfileについて

Dockerfileとイメージとコンテナの相関図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3480176/b2ce8586-dff4-aaba-f67e-893acae141c8.png)

PythonアプリケーションのルートにあるDockerfileの例

```Dockerfile
# コンテナのベースとなるイメージを指定している。ローカルになければpullしてbuildする
FROM python:3.11.3-buster

# ENV 環境変数の設定。
ENV PYTHONDONTWRITEBYTECODE=1

# RUN　コンテナの中でコマンドを実行
RUN mkdir /code

# WORKDIR　作業ディレクトリの設定。以降のコマンドはcodeにて実行される
WORKDIR /code

# Dockerはbuildを実行するときに、ホストマシンのファイルシステムを参照することができる。
# ホストマシンのDokcerfileがあるディレクトリがルート(./)となる。これをcontextという(composeに直接記載がある)
# context(ホストマシンの今のディレクトリ)の中にあるrequirements.txtを、コンテナの中のcodeディレクトリにコピーしている
COPY ./requirements.txt /code/

# RUN　コンテナの中でコマンドを実行。&&\で先のコマンドが成功した場合のみ次のコマンドを実行
RUN pip install -U pip && \
    pip install -r requirements.txt

# context(ホストマシンの今のディレクトリ)のルートディレクトリに存在するappディレクトリをコンテナ内のcodeディレクトリにコピー
COPY ./app /code/
```

これらのFROMや、COPY、RUNなどはDockerfileの命令「instruction」と呼ばれる。
COPY ./requirements.txt /code/ は画像のようなことをしている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3480176/f0d56292-a08b-d21a-86fc-e0c9d02e631f.png)




# -v ボリュームの概念について
```
docker run -it -v ~/hogedir/mountedfolder:/containerdir イメージ名
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3480176/a375b8fa-9f95-b12f-11f8-b5f25698dfbe.png)


-v host:container オプションによって、ホストのファイルなどをコンテナにマウントすることができる。
-v にも何個か種類があって今回の手法はバインドマウントと呼ばれるもの。
開発中のコードの変更が双方向に即時反映される。

-vはvolumeという概念の略。下の記事が非常にわかりやすかった。

https://qiita.com/aki_55p/items/63c47214cab7bcb027e0


# docker compose について
docker run コマンドが長いときや、複数のコンテナを起動する際に使う。
Dockerfileがコンテナの定義、docker-compose.ymlはコンテナをどう起動するかという感じ。

docker-compose.yml
```YAML

# docker-composeのバージョンを指定
version: "3.9"

# サービス = コンテナ。db(MySQL),app(Flask)のコンテナを作成
services:
  app:
    container_name: Flask # コンテナ名をFlaskに設定
    build: # FlaskのDockerfileをビルドする。dockercompose.ymlがあるディレクトリがコンテキストのルートとなる。
      context: .
      dockerfile: Docker/Flask/Dockerfile
    volumes: # ローカルのカレントディレクトリにあるChatAPPをコンテナの/codeにマウントする
      - ./ChatApp:/code
    ports: # ローカルの5000番ポートとコンテナの5000番ポートをつなぐ
      - "5000:5000"
    command:  bash -c "python app.py"
    # 先にdbコンテナを起動してからappを起動する
    depends_on:
      db:

  db: # dbコンテナの設定を定義
    container_name: MySQL # コンテナ名をmysqlに設定
    build: # MySQLのDockerfileをビルドする。ビルドコンテキストはこの場合だとdockercompose.ymlのあるディレクトリ
    context: .
    dockerfile: Docker/MySQL/Dockerfile
    volumes: # 命名ボリューム。ホスト側に直接mysql_dataというディレクトリが作成されるわけではないが、Dockerが管理する領域（例: /var/lib/docker/volumes/mysql_data/_data）にデータが保存される。この命名ボリュームmysql_dataを、コンテナの/var/lib/mysqlにマウントしている。
      - mysql_data:/var/lib/mysql
    environment: # コンテナ内の環境変数を設定
      - MYSQL_ROOT_PASSWORD=hoge
      - MYSQL_DATABASE=hogeapp
      - MYSQL_USER=hogeuser
      - MYSQL_PASSWORD=hogeuserpass

volumes: # 命名ボリュームを定義。命名ボリュームはコンテナを停止・削除してもデータが保持されるようにするための永続化ストレージのこと
  mysql_data: # 名前は任意。
  
```

命名ボリュームとバインドマウントの違いについて、

https://zenn.dev/hyoil/articles/d91119cb51c53c




# よく使うコマンドまとめ
## コンテナ起動から停止まで
.(カレントディレクトリ)にあるDockerfileから my-appという名前イメージをlatestタグをつけてビルド
```
docker build -t my-app .
```
-tはタグ付け。
何も指定しなければlatestとなり、my-app:hoge とすれば指定したタグをつけられる


<br>

イメージからコンテナの起動
```
docker run イメージ名
```

例1。Ruby on RailsアプリのデフォルトのDockerfileに記載されたコマンド
```
docker run -d -p 80:80 -p 443:443 --name my-app -e RAILS_MASTER_KEY=$(cat config/master.key) my-app
```
-d バックグラウンド(デタッチ)モード
-p ポートマッピング。ホストマシンの80とコンテナの80、ホストマシンの443とコンテナの443を接続。
--name 起動するコンテナにmy-appという名前をつける。
-e コンテナ環境内の環境変数を定義。config/master.key ファイルの内容を直接指定している。



<br>
コンテナ一覧。-aで停止中のものも一覧できる。

```
docker ps -a
```

<br>


コンテナ名を指定してコンテナを停止。my-appの部分はIDでも良い。

```
docker stop my-app
```

停止したコンテナを再度起動

```
docker start my-app
```

停止したコンテナを削除

```
docker rm my-app
```



<br>

## イメージ関連

イメージ一覧
```
docker images
```

イメージ一覧を整形して出力
```
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.ID}}\t{{.Size}}"
```

指定したイメージを削除 (xyz789ghi012はIMAGE ID)
```
docker rmi xyz789ghi012
```

どのコンテナでも使っていないイメージの一斉削除(プロンプトが出るのでy)
```
docker image prune -a
```

<br>

## compose 

composeでコンテナを(イメージがなければ)ビルドしてrunする

```
docker-compose up
```
<br>

composeでコンテナをビルドしてrunする。(imageを最新にできる)
```
docker-compose up --build
```
<br>

composeに定義されたコンテナの状態を確認
```
docker-compose ps
```

<br>


composeで起動したコンテナをstopしてrm
```
docker-compose down
```


<br>






# 参考リンク集
公式

https://matsuand.github.io/docs.docker.jp.onthefly/storage/

https://qiita.com/aki_55p/items/63c47214cab7bcb027e0

https://zenn.dev/hyoil/articles/d91119cb51c53c