docker-compose×Django×VScodeを用いた開発環境構築

#ゴール
VScodeのRemote Developmentを実行した際、自動でDockerコンテナが立ち上がり、
さらに指定したポートでrunserverを行い、Djangoの開発環境がVScode上で完結するという
夢のような環境を構築する。

#メリット
開発環境を開くたびにdocker-compose execコマンドを打つ必要がない。

コンテナ内の環境でVScodeが使えるため、VScodeのcode runnerや補完を使うことができる。

#前提条件
・Dockerをインストールしていること
・VScodeをインストールしていること
・VScodeのextentionである[RemoteDevelopment](https://code.visualstudio.com/docs/remote/remote-overview)をインストールしていること


#環境
Mac OS Catalina(10.15.7)
Docker 20.10.0


#手順
まず、今回コンテナ環境を構築する対象のディレクトリ構成は下記の通りである。

###最終ディレクトリ構成
![スクリーンショット 2021-02-06 14.54.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332317/d1309ef7-a23a-fb25-964c-d8f7a3411e2b.png)

今回は上記のようなMyProjectというアプリケーションを作成することを考える。

用意をするファイルは、以下の4つである。ファイルの中身に関しては手順を参照。

|file名  |概要  |
|---|---|
|Dockerfile|アプリケーションのimageの設計図|
|docker-compose.yml|アプリケーションを作り出すサービスを記述するもの|
|requirements.txt|Dockerfileをbuildする際に必要になる、pythonのライブラリ一覧|
|.devcontainer.json|VScodeでリモート環境を構築するための設定ファイル|


ここからは、
・ローカル上にコンテナ作成
・コンテナをVScodeから開く
の大きく二つに分けて手順を書いていく。

###【ローカル上にコンテナ作成】
[https://docs.docker.jp/compose/django.html](https://docs.docker.jp/compose/django.html)を参考にして、ローカルにコンテナを作成する。

####1.ローカルの任意の箇所にディレクトリを作成
今回は、MyProjectというディレクトリを作成。

####2.MyProject内に下記のDockerfileを作成
```dockerfile:Dockerfile
FROM python:3.8.5
ENV PYTHONUNBUFFERED 1
RUN mkdir /code
WORKDIR /code
ADD requirements.txt /code/
RUN pip install -r requirements.txt
```
１行目でDockerHubからpythonのイメージを引用する。
３行目でコンテナ内にcodeというディレクトリを作成する。
（ディレクトリ名は任意で決めて良い。）
５行目でローカルのrequirements.txtをコンテナ内のcodeディレクトリにコピーする。
６行目でrequirements.txtに記載されているライブラリをコンテナ内にインストールする。

####3. MyProject内に下記のrequirements.txtを作成
```text:requirements.txt
argon2-cffi==20.1.0
asgiref==3.3.1
certifi==2020.11.8
cffi==1.14.4
Django==3.1.3
Pillow==8.1.0
pycparser==2.20
pytz==2020.4
six==1.15.0
sqlparse==0.4.1
```
最低限必要なのは、Djangoのみである。
pip freeze > requirements.txt というコマンドを打てば、ローカル環境のライブラリが一覧を上記のように得ることができる。



####4. MyProject内に下記のdocker-compose.ymlを作成
```yml:docker-compose.yml
version: '3'

services:
  web:
    build: .
    command: python3 manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/code
    ports:
      - "8000:8000"
```
docker-composeは、複数のコンテナをまとめて管理することができる仕組みである。

それをservicesの下にサービス名を書いて、管理していく。

上記の例の場合、webと呼ばれるサービス一つしかない。

（[https://docs.docker.jp/compose/django.html](https://docs.docker.jp/compose/django.html)の9.の例では、dbというサービスも追記されている。これは、postgresを利用するために、そのimageファイルをDockerHubから持ってきている。）

build . でDockerfileをbuildして、コンテナを作成する。
commandでコンテナが起動したときに自動で実行されるコマンドを指定している。ここでDjnagoのサーバーを立ち上げている。
volumesでは、コンテナ内にマウントするローカルのディレクトリを指定している。（ローカル）：（コンテナ）の順に記載する。
上記の例では、ローカルのMyProjectディレクトリをコンテナのcodeディレクトリにマウントしている。つまり、ローカル上のMyProject内のフォルダがcode上でみれる。


####5. Djangoプロジェクトを生成するために、MyProjectディレクトリに移動してから下記コマンドを実施
```terminal
 docker-compose run web django-admin.py startproject sample .
```
これは2つのコマンドを連続で実行している。

①docker-compose run web
ここは、docker-composeのコマンドで、4で言及したwebサービスをrunする。
このタイミングでコンテナが生成される。

②django-admin.py startproject sample .
ここは、Djangoのコマンドで、①で立ち上げたコンテナ内で実行することができる。
これにより、sampleというDjangoの初期フォルダと、manage.pyというファイルが作成される。
sampleは任意の名前で良い。

###【コンテナをVScodeから開く】
後半はそのコンテナをVScodeから開く。（正確にはVScodeからコンテナにアクセスする。）

####6.  MyProject内に下記の内容の.devcontainer.jsonを作成する。
```json:.devcontainer.json
{
	"dockerComposeFile": "docker-compose.yml",
	"service": "web",
	"workspaceFolder": "/code",
	"extensions": []
}
```
これは、VScodeのRemoteDevelopmentでローカルのファイルをコンテナ内で開く際の設定画面である。隠しファイルなので、touchコマンドで作成する。

２行目でMyProject内のdocker-compose.ymlを指定しexecさせる。
３行目でdocker-compose.yml内で指定したwebサービスを指定。対応させる必要がある。
４行目でこのVScodeで開くルートディレクトリを指定する。手順4で説明した通り、コンテナ内のcodeディレクトリはローカルのMyProjectディレクトリのマウント先なので、このcodeをルートディレクトリにするのがベストである。
５行目ではVScodeのextensionsで使いたいものを配列内に記入していく。今回の例は空欄。

####7. VScodeでMyProjectを開き、Reopen in Containerをクリック

![スクリーンショット 2021-02-06 11.42.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332317/fecaf4dd-905a-2655-d504-1ed7c219eef1.png)

.devcontainer.jsonがある状態でVScodeを開くと、RemoteDevelopmentが反応し、右下に「コンテナで開きなおしますか？」というポップが表示されるので、「Reopen in Container」を選択する。すると、下記のように画面が遷移し、コンテナ内に入れたことが確認できる。

![スクリーンショット 2021-02-06 11.47.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332317/1b2034f5-332b-b0ec-cbbf-b3800ffcbc91.png)

そして、コンテナ立ち上げ時のコマンドであるrunserverも実行されたことも確認できる。
（docker-compose.ymlの6行目に記載した、python3 manage.py runserver 0.0.0.0:8000が実行されているので、localhost:8000にサーバーが立ち上がっている。）

![スクリーンショット 2021-02-06 11.50.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332317/f5e06699-7f54-6080-23ef-92b0cbb19e36.png)


##[以降の開発手順について] 
これ以降開発をしていく際、もしrequirements.txtを上書きした場合は、
開発プロジェクトのrootディレクトリ(Dockerfileがある階層)
に行って、docker system pruneをターミナルで実行し、一度コンテナを削除する。
そして、7を行えば、変更箇所のみimageファイルを追記し、新たなコンテナを作成してくれる。