Dockerについて

# なぜ使うか
**環境をキレイに保つため．**　

Dockerがないと，ローカル環境でpython3.7やらpython3.8やら混在したり，もうごっちゃごっちゃ．カオス．
また，開発環境と本番環境を合わせられるのも大きい．デプロイの度に環境が違うせいでエラーが生じることは多々あるが，これを防ぐことができる．
Virtual BoxよりもDockerはかなり高速で立ち上がるので，Dockerが良い．
自分はDockerを使い始めてから，かなり開発時の健康状態が良くなりました．整理された机で勉強した方が気持ちがイイのと同じ感覚．

# Docker 基本編
本番環境を意識せずに，sandbox内で色々弄るだけならこれで十分ではという内容．最初はこれだけでよいと思う．慣れてきたら応用編へと進みたい．

```
# ベースとなるイメージを引っ張ってくる．大本の環境を構築する感じ．この上にパッケージなどを乗せていく．
$ docker pull イメージ名

# anaconda -> pandasなど大体機械学習に必要なパッケージがインストール済みだが重い．本番環境では軽さが大事だが，ローカル開発ではこれでいいと思う．
$ docker pull continuumio/anaconda3

# -itコマンドでDockerを起動し続ける．ないと一度起動するだけで切れてしまい，その中で作業できない．また末尾に/bin/bashを付けることで，バッシュの中で作業できる．コマンドラインを使えるイメージ．ないとpythonの対話モードになる．
$ docker run -it continuumio/anaconda3 /bin/bash

# コンテナ内でパッケージをインストールするなどの変更を行ったら，コンテナを抜けた後，その変更を保存しておく．しないと，初期の環境のままになる．
# 起動したコンテナの履歴
$ docker ps -a
# コンテナをイメージとして保存する
$ docker commit container_id container_name

# 保存したイメージの一覧を確認する
$ docker images

# 保存したコンテナを起動する
$ docker run -it container_name /bin/bash

# ローカルディレクトリをマウント（Dockerと共有）する. -vの後に「ローカルディレクトリ：Dockerディレクトリ」を記述．
docker run -it -v /c/Users/user/Python:/home container_name /bin/bash
```

# Docker 応用編
　少し難しいかもしれないが，慣れるとより快適にかつ効率的に開発できる．自分はここで時間がかかった記憶がある．


基本的な利用の流れは以下．

1. Dockerfileとrequirements.txtを作成する
2. VSCodeに拡張機能Remote-Containersを入れる
3. VSCode左下コードボタンからre-open in containerを実行&Dockerfileを実行
4. Docker環境下でインストールしたパッケージを, requirements.txtに追加で記述
5. 次回，再びビルド．


ここでは，Dockerfile単体・docker-compose利用本・番環境用Dockerfileの3つに分けて話したい．
最終的には，docker-composeを利用しての開発に慣れていきたい．また，本番環境用のDockerfileまで作れるようになると良いだろう．

## 1. Dockerfile単体

```Dockerfile
# 上部に記述したものほどキャッシュを利用しやすくなっているので，よく変更を加えるものは下の方に記述しよう．
# python-buster -> pythonを動かすための最小限のパッケージ．OSはdebian. 自分はこれで開発している．
FROM python:3.8-buster

#　パスは絶対パスを使用する．ローカルとコンテナでディレクトリ構造が異なるから．
WORKDIR /app

# パッケージマネージャの更新とパッケージの取得はまとめる. aptの方がapt-getよりも良い．
RUN apt update -y && apt upgrade -y && \
    apt install -y ffmpeg

# ADDよりCOPYの方が良い．appディレクトリにファイルをコピー．ローカルからコンテナへとファイルをコピーしている．
COPY requirements.txt /app
# requirements.txtを参照してpip install. python3ではpip3を利用したい．
RUN pip3 install --upgrade pip && \
    pip3 install -r requirements.txt

# 指定したディレクトリを各環境で共有できる．
# VOLUME /data

# コピーするディレクトリは明示的に指定．変更部のみ反映させるため．自分は面倒なので「.」で済ませてしまっている．
# COPY src /app/src
# COPY data /app/data
COPY . /app

# CMD ["/bin/bash"]
```

## 2. Docker-Compose利用
Docker-composeを利用することで，複数のサーバーを同時に使うことができる．例えば，python実行用だけでなく，postgresなどデータベースやjupyterなど．資源を共有できるのも良い．
コード例は以下．
```docker-compose.yml
version: '3'
services: 
  notebook:
    # image: jupyter/datascience-notebook -> Dockerfileでベースイメージ記述しているから不要．
    #  container_nameを指定しないと，自動で生成されて後で確認しづらくなる．
    container_name: vad-sandbox
    ports: 
      - "8888:8888"
    # 「.」で同じディレクトリにあるDockerfileを実行してくれる．
    build: .
    # マウントするディレクトリを指定．
    volumes: 
      - .:/app
    working_dir: /app
    # 自動でコマンドを実行してくれる．僕は自分で打った方が分かりやすいので自分で打っている．
    # command: jupyter lab --ip=0.0.0.0 --allow-root
```
　そして，こちらがdocker-compose利用時のdockerfile

```Dockerfile
FROM python:3.8-buster

WORKDIR /app

RUN apt update -y && apt upgrade -y && \
    apt install -y ffmpeg

COPY requirements.txt /app

RUN pip3 install --upgrade pip && \
    pip3 install -r requirements.txt

# ipywidgetsを利用. jupyterをインタラクティブに使える．
RUN jupyter nbextension enable --py widgetsnbextension --sys-prefix

COPY . /app

# CMD ["/bin/bash"]
```

## 3. Docker本番環境用
本番環境では極力容量を削減することが肝要である．そのために，マルチステージビルドを採用する（ビルドと実行で環境を分ける）．

```Dockerfile
# pythonではalpineよりbusterの方が良い．slimではc拡張が使えない
# マルチステージビルドでビルドと実行でイメージを分け，極力容量を小さくする
# キャッシュを利用したいものほど上部に記述．変更があるとそれ以降破棄されるため．

# ビルド用．busterはgccが利用できる．webrtcvadのインストールに必要．
FROM python:3.8-buster as builder

#　パスは絶対パスを使用する
WORKDIR /app

# pytorchはインストールに時間がかかるため，キャッシュを再利用しやすく．
RUN pip3 install --upgrade pip && \
    pip3 install torch

# ADDよりCOPYの方が良い．appディレクトリにファイルをコピー．
COPY requirements.txt /app
RUN pip3 install --upgrade pip && \
    pip3 install -r requirements.txt

#実行用コンテナ
FROM python:3.8-slim-buster as runner

# インストールしたpythonパッケージを実行用へとコピー. 1GBほど削減できた．
COPY --from=builder /usr/local/lib/python3.8/site-packages /usr/local/lib/python3.8/site-packages

# パッケージマネージャの更新とパッケージの取得はまとめる. aptの方がapt-getよりも良い．
RUN apt update -y && apt upgrade -y && \
    apt install -y ffmpeg

COPY . /app
```


# 最後に
　抽象度が高いため，初見では戸惑うこと間違いなしだが，慣れれば単なる作業と化す．最初はストレスを感じるかもしれないが，がんばろう．就活でもアピれるはずだ．