AWS EC2とDjango を使いたい未経験者へのtip

# AWS EC2 と Django を使って駆け出しエンジニアを目指す方へ

##自己紹介
初めまして、ぴくむんといいます。色々あってwebエンジニアになることになりました。
そこで、Djangoを学ぶ事になったので、忘れない様にメモしときます。誰かの役に立てれば幸いです。

この記事は、
【Docker(Docker-Compose)】Python,Djangoの開発・本番環境構築【Postgres,Gunicorn,Nginx利用】
https://tomato-develop.com/docker-dockercompose-python-django-postgresql-gunicorn-nginx-how-to-build-development-and-production-environment/

Get Started With Django Part 1: Build a Portfolio App
https://realpython.com/get-started-with-django-1/
に沿って、自分の知見を混ぜ合わせながら解説しようと思います。

PC: Mac book Air 
OS: Catalina
Docker:4.1.0
を使っております。

##読者想定
私は、Djangoを使って掲示板みたいなwebサービスを作りAWSEC2でデプロイしたぐらいの経験者です。
いろんな背景を持った方が見てくれてるかもしれませんが、ゲームでチュートリアルが終わった人が初めてゲームをプレイする人に向けたぐらいのレベルぐらいの記事だと思っていただけると助かります。
間違いも多いと思うので、もっといい記事にするためにもコメントよろしくお願いします。

##はじめに
とにかく覚えることが多すぎて、吐きそうになると思いますが自分なり一言でまとめてみました。

Djangoはpythonのwebフレームワークであり、あり得ないぐらい簡単にwebサービスを作ることができる。他にはPHPを使ったLaravel、Rubyを使ったRuby on Railsなどが有名である。立ち位置としては、会社などは昔からあるPHPを使ったものが多い。一方でRubyは日本人が開発したこともあり、日本語のテキストが多い。Pythonは世界的によく使われているため、ライブラリーが充実しており、特に機械学習と組み合わせたwebサービスには強いという印象。

一応WordPressにも言及しておくが、WordPressはPHPで書かれており、ブログに特化したアプリケーションになっている。おそらくPHPで書かれている以上、如何様にも好きな様にもwebページを書き換えることができると思うが、おそらくそれは一般的ではない。

ブログとwebサービスは、全くの別物である。webサービスというのは、twitterの動画URLを入力し、ダウンロードできるサイトであったり、Twitterそのものであったりする。
よって、ブログが始めたければDjangoから始めるのは非効率であるため、推奨しない。

Djangoは、ローカルPCでrunserverと呼ばれるデバッグ用のコマンドを使用することにより、開発用のサーバーを立ち上げることができるが、これはあくまでデバッグ様なので、別にサーバー用意する必要がある。

>サーバーとは、サービスを利用者のリクエストに応じて提供するソフトウェアのことを指す(wikipedia)
注意：サーバーは、データを提供するコンピューターにも使われる。サーバーを借りるという表現をしている時は、コンピュータを借りると意味で使用している。サーバー(ソフトウェア)とサーバー(PC)の2パターンあるので、読む時は注意したい。

Djangoは、超強力なwebフレームワーク といえども、

>フレームワークとは アプリケーションを開発するとき、その土台として機能させるソフトウェアのこと。

あくまで土台であるので、デプロイまでのツールが全て完璧に揃っているわけではないので、ネットに公開するときは、必要に応じて自分でサーバー(ソフトウェア)を用意する(他のアプリケーションと組み合わせる)必要がある。

>runserverで世界中に公開することも可能ではあるが、セキュリティの観点と速度の観点から公式かのお達しで推奨されてない。

サーバーにも3種類がある。
・webサーバー: HTMLとCSSとjavascriptをユーザーに出す人。Nginx等
・アプリケーションサーバー: webサーバーとDBサーバーの仲介をする人。Gnuicorn等
・DBサーバー: DBにアクセスして、データを引っ張ってくる人。Django、Laravel、Ruby on Rails。
これらをうまく組み合わせて、サーバーを構築する必要があるが、残念ながらこの構築には、大きくPCの環境に依存してしまう。(あの人のPCでは動いたけど、この人のPCではうまく動かない。)
これでは困るので、仮想環境という概念を使ったアプリケーションを駆使する。

>仮想環境というのは、PC上にPCを立ち上げるという発想である。

Djangoを開発するときは、pythonのvenvという仮想環境を使うのが一般的。
サーバーを動かすときには、Dockerというアプリケーションを使って、一式新たに仮想環境を構築し、Dockerのpythonをvenvの仮想環境と同じ設定にして、Nginx、Gnuicorn、Django動かす。

>注意：あくまで開発するときは、Gnuicorn、Nginxを使わずに、runserverでデバッグした方がいい。毎回Docker立ち上げてやるのは開発スピードがかなり遅くなると思う。本番環境でのみ、Gnuicorn、Nginxを使ってサーバーを立ち上げたほうがいい。

うまく、Dockerを使ってGnuicorn、Nginx、Djangoを使ってサーバーを構築できたら、次はサーバーを借りなければならなない。昔はサーバーを借りるのは今みたいに簡単ではないので、自分のPCを使ってサーバーとして使っていた。この様な手法をとっている人たちは、ネットワークインフラをちゃんと学ぶ必要があるが、現代では、超簡単にサーバーを借りられる(AWS、さくらサーバー)ので、ここら辺の手間がかなり省けた。

サーバー(PC)を借りたら、もちろんサーバー(PC)は空なので、サーバー(PC)に自分が作ったプログラムをアップロードしなけれなならない。友達のPCにデータを送るからUSBメモリを挿す世界と全く違う。そこで、自宅のPCからsshを使ってリモートアクセスし、githubなどのサービスを使って、サーバー(PC)に自分が作ったプログラムを入れる。

そののちに、そのサーバー(PC)で仮想環境を立ち上げる事により、自分が開発した同じ環境で、サーバー(アプリケーション)を構築することができる。

サーバー(PC)には自動的にIPアドレスが振り分けられているので、そこに全世界のネットワークからアクセスすることが可能になる。しかし、ただ数字だけのURLだと不気味なので、ドメインを取得し、IPアドレスを○○.com,○○.jp,といったURLに紐付けする必要がある。

ちなみに、ドメインは早い者勝ちで、わかりやすいのは高い。
この一連の作業をこなして、初めてwebサービスを世界に公開することができる。

# 実際にコードを書いていきます。
##これからの方針

・venv仮想環境を構築し、Djangoでプロジェクト作成。Dockerで立ち上げ。
・Djangoのチュートリアル
・本番環境構築(Nginx,Gnuicorn追加)、AWSEC2にデプロイ

で書き進めていきたいと思います。

##venv仮想環境まで

ディレクトリを作成。

```
.
└── Docker-Django
    └── django_project
```


```perl:Pip3のインストールとアップデート
$ sudo -H pip3 install --upgrade pip
```

```perl:virtualenvのインストール
$ sudo -H pip3 install virtualenv
```

django_project上で

```perl:仮想環境立ち上げ、仮想環境の有効化
virtualenv venv
source venv/bin/activate
```

ユーザー表示の前に(venv)が付いたら、有効化完了。
もし、無効化したい場合は


```perl:仮想環境の無効化
$ deactivate
```

##Djangoを仮想環境にインストール、初期画面確認。
```perl:djangoインストール、Djangoのプロジェクトを作成
(venv)$ pip3 install django
(venv)$ django-admin startproject project .
```
.を忘れない様に。
ディレクトリを確認してください。

```perl:ディレクトリ
Docker-Django
└── django_project
    ├── manage.py
    ├── project
    │   ├── __init__.py
    │   ├── asgi.py
    │   ├── settings.py
    │   ├── urls.py
    │   └── wsgi.py
    └── venv
```

実際に動かしてみる。

```perl:
(venv)$ python manage.py runserver
```

ブラウザで確認。

```
http://localhost:8000/
```

![スクリーンショット 2021-12-09 14.34.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2363430/3f415cc2-4313-0d4e-7b5a-e490aed20e22.png)


##Dockerで立ち上げ。

Dockerのインストールがまだの場合は、下記のサイトからインストール。
Install Docker Desktop on Mac
https://matsuand.github.io/docs.docker.jp.onthefly/desktop/mac/install/

ここからちょっと情報量が多いが、頑張りましょう。

まずは、全体像から。ファイル作成するときはこの表を確認しながら以下のやつをコピペして走らせてください。

```
Docker-Django
├── django_project
│   ├── Dockerfile
│   ├──.env
│   ├── db.sqlite3
│   ├── manage.py
│   ├── project
│   │   ├── __init__.py
│   │   ├── __pycache__
│   │   ├── asgi.py
│   │   ├── settings.py
│   │   ├── urls.py
│   │   └── wsgi.py
│   ├── requirements.txt
│   └── venv
└── docker-compose.yml
```


###環境ファイルの設定
環境ファイルをDocker-Django上に作成。開発する環境によっては変更しなければならないものもあるので、環境ファイルを使って一律で管理した方が、環境が変化したときに対応しやすい。なくでもできるが、めんどくさいと言ってサボると、環境が変わったときに悲しい気持ちになる(実体験)。
一般的にこれは非表示のファイルになるので、Finderで作業するときは、command+shift+.を押して隠しフォルダ表示モードで作業した方が良い。

```perl:.env
DEBUG=True
SECRET_KEY='セキュリティの面で書きません。'
ALLOWED_HOSTS=localhost 127.0.0.1 [::1]
```

環境ファイル(.env)の中には、djangoでのmanage.pyの設定を写す。
特に、ALLOWED_HOSTSはちょっとセキュリティが絡むので、勉強した方がいい

>【Django】settings.py：ALLOWED_HOSTSとは（開発・本番環境）
https://office54.net/python/django/settings-allowed-hosts

一般的にこの環境ファイル(.env)をgit管理から外して開発を行う。各々開発環境に合わせて書き換える。

```perl:manage.py
import os
import environ

env = environ.Env()
env.read_env(os.path.join(BASE_DIR, '.env'))

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.environ.get("SECRET_KEY")

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = os.environ.get("DEBUG")

ALLOWED_HOSTS = os.environ.get("ALLOWED_HOSTS").split(" ")
```

今回は、この３つを環境ファイルに移したので、osライブラリのos.environ.get関数を使う事により、外部のファイルから抜き出せる。

import osを忘れずに。

###docker-composeの設定。
docker-composeを使う事により、まとめてコンテナ化できる。
今回は、webだけだが、DBでpostgresを使うときは、ここに追加される。nginxも同様。


```perl:docker-compose.yml
version: '3.7'
 
services:
  web:
    build: ./django_project
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - ./django_project/:/usr/src/app/
    ports:
      - 8000:8000
    env_file:
      - ./django_project/.env
```

webというコンテナを作ります。
一個つ下層のdjango_projectのDockerfileのデータをもとにビルドします。
追加で動かすコマンドは、python manage.py runserver 0.0.0.0:8000　です。
追加で使うvolumesは、./django_project/:/usr/src/app/　です。
追加でportsは、8000:8000　です。
追加でenv_fileは　./.env　です。
という様な意味。詳しくは、ちゃんと勉強したら解説します。

>runserverで0.0.0.0:8000がある理由は、
docker上のアプリにlocalhostでアクセスしたらERR_EMPTY_RESPONSEが出る
https://qiita.com/amuyikam/items/01a8c16e3ddbcc734a46

んで、そのDockerfileは、

```perl:Dockerfile
FROM python:3.8.3-slim
 
WORKDIR /usr/src/app
 
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
 
RUN pip install --upgrade pip
COPY ./requirements.txt .
RUN pip install -r requirements.txt
 
COPY . .
```
python:3.8.3-slimを使って、コンテナを立ち上げます。(他にも種類あるが、ここではslimを使っている。他のやつで動かないものあるが、おそらくライブラリが足りない。)
環境変数を設定して(よくわからん)、
pipをインストールして、
requirements.txtを持ってきて、

```perl:requirements.txt
Django
django-environ
```

Djangoとdjango-environをインストールします。

ん？さっきインストールした気がすると言いたくなるかもしれないが、ここではDocker上にインストールしている。
イメージとしては、
最初の仮想環境は、PC上にvenvを使って、pythonの仮想環境を作って、Djangoをインストール。
今回の場合は、PC上にDockerを使ってコンテナを立ち上げて、その中にpythonをインストールして、そのpythonにDjangoをインストールした。という流れである。

>DockerでPythonの実装環境を作る方法を現役エンジニアが解説【初心者向け】
https://techacademy.jp/magazine/47408

コンテナというのは仮想環境なので、別にpythonであろうがソフトウェアであろうが実行可能である。

Q.は？なら、最初の工程いらねーじゃん。いきなりコンテナ立ち上げてやればいいじゃん。
A.最初に「django-admin startproject project .」を実行しないといけないので、必要な工程である。

Q.でもさ、PC上にvenvのpythonの仮想環境を作って、モジュールインストールしまくって開発したとするよ。そんときは、Docker上のpythonでDjango走らせるときは困るだろ。
A.はい困ります。そのときは、Dockerfileの中身に「RUN apt-get -y install python3-numpy python3-scipy 」とか追加して、Dcokerのpythonにnumpyとかscipyとかインストールしてください。他のモジュールは、requirements.txtに書き込めばいいです。
先人として注意したいのは、モジュールインストールしまくって開発すると後でDockerを使ってコンテナ立ち上げるときに、めちゃくちゃ遅くなります。開発時点では問題ないが、コンテナ立ち上げて本番環境を試したいときに、めちゃくちゃイライラしました(実体験)。
なので、開発環境がめちゃくちゃな人は、ちゃんとvenvで仮想環境を立てて、必要最低限のモジュールをインストールしてから、runserverでデバッグしながらコーディング。いい感じに開発できたら、コンテナを立てて、Dcoker必要なモジュールを調べながら、コンテナを立ち上げる努力をする。そうしなければ、悲しい気持ちになります(実体験)。

###docker-composeを使ってコンテナ上でDjangoを起動してみる。
Docker-Django上で

```
(venv)$ docker-compose up -d --build
```
をして、

ブラウザで確認。

```
http://localhost:8000/
```

もしも、ロケットが飛んでなかったら

```
(venv)$ docker-compose logs -f
```
をみてエラーメッセージを読んで、頑張ってください。

満足したら

```
(venv)$ docker-compose down -v
```
でコンテナを立ち下げてください。
とりあえず、これで、開発環境と本番環境の骨組みを手に入れた事になります。
あとは、ある程度開発して、本番環境の骨組みにnginxとGnuicornを組み合わせれば、デプロイです。

次回から、そのある程度の開発を行なっていきます。


##おわりに

お疲れ様でした。次回からは、Djangoのチュートリアルをやっていきたいと思います。
色々間違っているところもあると思いますが、ぜひコメントで教えていただけると助かります。
なるべく正確な記事が書きたいので。よろしくお願いします。