Docker+Django+Next+TypeScript+ECSでWebアプリを作った話(1) ~ 準備編 ~

# はじめに
私自身の就活でDocker, Django(graphene-django), Next.js, TypeScript, ECSを使い、ポートフォリオを作成しましたが、
それぞれの技術に関して、独学で実装するのに苦戦したため、自身の記録用として、機能の一部(ユーザー認証のみ)の制作過程を書きました。
長くなるため、何回かに分けて書いていこうと思います。

次の記事：　[Docker+Django+Next+TypeScript+ECSでアプリを作った話(2) ~ Djangoの初期設定からModel作成編 ~](https://qiita.com/rys0707/items/512d4bcf04e6b2d7f972)

実際に作成したWebアプリのURLです。
トレサポ：http://ryo-training-management.com/
![トレサポのメインページ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634526/c010a95f-5caa-a6c4-f1f2-63b5abc72b1b.png)

# それぞれの技術を採用した理由　　

- Docker: ローカル開発環境の統一のため
- Django(graphene-django): バックエンドとして、単一のエンドポイントでクエリを実行して、データを絞って取得できるため
- Next.js: フロントエンドとして、ライブラリが豊富であり、簡単におしゃれなUI構築ができ、 SSG方式を取ることで、SEO対策になるため
- TypeScript: コンパイル時点でエラーが分かるため
- ECS: Dockerのプロジェクトをそのままデプロイできるため

# 開発環境

- macOS Big Sur 11.2.1 (M1)
- frontend
    - node 16.3.0
    - next 11.0.1
    - typescript 4.3.4
    - recoil 0.3.1
    - formik 2.2.9
    - jest 26.6.3
    - apollo-client
- backend
    - Python 3.7.10
    - Django 3.1.2
    - graphene-django 2.13.0
- Postgres 10

# 1.プロジェクト直下にファイル、フォルダを作成

フォルダ構成は以下の通り

```
myProject/
    app/
    frontend/
    Dockerfile
    Dockerfile-node
    docker-compose.yml
    requirements.txt
    Makefile
```

- Dockerfile  
バックエンド用のDockerfile。ECSにデプロイする都合上、dockerhubからpythonのイメージをpullする際にM1のMacだとamd64ではないアーキテクチャをデフォルトで取得してしまうため、アーキテクチャを指定しています。<br/>
CMDに関しては、本番用に記載しており、djangoのsettingsを本番用と開発環境用に分けている。開発環境ではdocker-composeにてコマンドを上書きしています。


```Dockerfile:Dockerfile
FROM python@sha256:73c7d5d218ff9e2d76f41edcc1bd4f71961f7551ea7b2e39ab8b4793cede21b4

ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

COPY ./requirements.txt /requirements.txt
RUN apk add --update --no-cache postgresql-client jpeg-dev
RUN apk add --update --no-cache --virtual .tmp-build-deps \
    gcc libc-dev linux-headers postgresql-dev musl-dev zlib zlib-dev
RUN pip install -r /requirements.txt
RUN apk del .tmp-build-deps

RUN mkdir /app
WORKDIR /app
COPY ./app /app

RUN mkdir -p /vol/web/media
RUN mkdir -p /vol/web/static
RUN adduser -D user
RUN chown -R user:user /vol/
RUN chmod -R 755 /vol/web
USER user

CMD sh -c "python manage.py migrate --settings app.prod_settings && python manage.py runserver 0.0.0.0:8000 --settings app.prod_settings"

```

- Dockerfile-nodejs  
フロントエンド用のDockerfile。こちらも同様に、node.jsのイメージを取得するのにアーキテクチャを指定しています。

```dockerfile:Dockerfile-nodejs
FROM node@sha256:f5079a4f93c8e4fd07ffa93fc95f6484d7f4f40abd126c11810cb282483ab599
MAINTAINER kanagawa App Developer Ltd

RUN npm config set unsafe-perm true
RUN npm install -g npm
RUN npm install -g create-next-app
RUN mkdir /frontend

WORKDIR /frontend
COPY ./frontend /frontend

CMD sh -c "npm run start"

```

- docker-compose.yml  
フロントエンド、バックエンド、DBのコンテナを起動するように作成しています。

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

services:
  app:
    build:
      context: .
    ports:
      - "8000:8000"
    volumes:
      - ./app:/app
    command: sh -c "python manage.py migrate &&
      python manage.py runserver 0.0.0.0:8000"
    environment:
      - FRONT_URI=http://localhost:3000
      - ALLOWED_HOST=localhost
      - DB_HOST=db
      - DB_NAME=app
      - DB_USER=postgres
      - DB_PASS=supersecretpassword
    depends_on:
      - db

  db:
    image: postgres:10-alpine
    environment:
      - POSTGRES_DB=app
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=supersecretpassword
      - POSTGRES_HOST_AUTH_METHOD=trust

  next:
    build:
      context: .
      dockerfile: "./Dockerfile-nodejs"
    volumes:
      - ./frontend:/frontend
    command: sh -c "npm run dev"
    ports:
      - "3000:3000"

```

- requirements.txt  
djangoにインストールするパッケージを記載しています。

```requirements.txt
Django==3.1.2
graphene-django==2.13.0
django-filter==2.4.0
django-graphql-jwt==0.3.1
PyJWT==1.7.1
django-cors-headers==3.5.0
psycopg2
factory-boy
pytz
django-environ
gunicorn==20.0.4
```
- Makefile

```makefile:Makefile
.PHONY:
	app test migrate pro admin django react 

app:
	docker-compose run --rm app sh -c "python manage.py startapp api"

migrate:
	docker-compose run --rm app sh -c "python manage.py makemigrations --settings app.dev_settings"
	docker-compose run --rm app sh -c "python manage.py migrate --settings app.dev_settings"

admin:
	docker-compose run --rm app sh -c "python manage.py createsuperuser --settings app.dev_settings"

django:
	docker-compose run --rm app sh -c "django-admin startproject app ."

next:
	docker-compose run --rm next sh -c "npx create-next-app . --ts"

django-test:
	docker-compose run --rm app sh -c "python manage.py test --settings app.dev_settings"

```

以下のコマンドにてフロントエンド、バックエンドのイメージを作成

```
$ docker-compose build
```

# 2.Next.jsのプロジェクトを作成  

以下のコマンドにてnext.jsのプロジェクトを作成 

```
$ make next
```

# 3.Djangoのプロジェクトを作成

以下のコマンドにてDjangoのプロジェクトを作成 

```
$ make django
```

以下のコマンドにてDjangoにアプリケーションを追加

```
$ make app
```

# 4.動作確認
一度コンテナを全て止め、コンテナを起動してみます。

```
$ docker-compose stop
$ docker-compose up
```

localhost:3000にアクセスすれば以下の画面が表示され、
![next.jsのトップ画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634526/c14db384-ad8a-0972-cd78-dd3b7a6be92f.png)


localhost:8000にアクセスすれば以下の画面が表示されます。
![スクリーンショット 2021-07-09 20.33.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634526/bbf8ed8d-5232-3a98-0c91-adf9cfde917c.png)

# まとめ
今回はDodkerでの環境構築とNext.js、Djangoのプロジェクトを作成し、起動確認する所まで書きました。
次回はDjangoプロジェクトの初期設定からModel作成までの所を書きたいと思います。

次の記事：　[Docker+Django+Next+TypeScript+ECSでアプリを作った話(2) ~ Djangoの初期設定からModel作成編 ~]
(https://qiita.com/rys0707/items/512d4bcf04e6b2d7f972)

# 参考
https://qiita.com/greenteabiscuit/items/c40ba038703c9f33499b