1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

備忘録: Django×React×AWS×firebase[デプロイ 手順編]

Last updated at Posted at 2021-11-16

本記事でのデプロイ環境の完成図

portfolder drawio
間違っている部分があれば是非指摘してください!!!!

EC2を使用する際の注意点

  • 2022/5/2現在 1〜4までの工程が簡略化できるようになっている
作成するリソース 名前タグの自動生成
VPCなど 任意(ここではfp)

他の設定は任意。
本記事では上記の2点のみ変更して作成

スクリーンショット 2022-05-02 14.38.52.png

  • 2021/9/30現在 EC2インスタンス(8GB)を4つ作成した時点で無料枠(30GB)を超えるので課金対象になる
  • 2つのインスタンスが1ヶ月フル稼働をした時点で課金対象になる
  • また稼働していないインスタンスに対してElasticIPが有効になっている場合も課金対象になる
  • 2021年10月26日時点ではRDSの無料枠にPostgresQLがなかったのでMySQLを使用しています。(DjangoはPostgresQLの使用を推奨しています。)

firebaseでプロジェクトを作成し、Firebase Hosting の設定通りに進める

フロントエンド側

buildする

$ npm run build

firebase CLIのインストール

$ npm install -g firebase-tools
$ firebase login
$ firebase projects:list

上記のコマンドでログインとプロジェクト一覧を確認できればOK
firebase公式ドキュメント

firebaseプロジェクトの初期化

$ firebase init hosting
以降は下記の内容で選択
Use an existing project

firebaseで作成したプロジェクトを選択

? What do you want to use as your public directory? (public)build

? Configure as a single-page app (rewrite all urls to /index.html)? (y/N) y

? Set up automatic builds and deploys with GitHub? Y

? File build/index.html already exists. Overwrite? (y/N) N

? For which GitHub repository would you like to set up a GitHub workflow? (fo
rmat: user/repository) enuii3/portfolder_api

? Set up the workflow to run a build script before every deploy? (y/N) y

? What script should be run before every deploy? npm ci && npm run build

? Set up automatic deployment to your site's live channel when a PR is merged
? (Y/n) Y
? What is the name of the GitHub branch associated with your site's live chan
nel? master

環境変数を再設定する

後日作成内容
create-react-appで独自の環境変数を読み込む

deployする

$ firebase deploy

バックエンド側

デプロイ用ライブラリの導入

$ pip install django-environ
$ pip instlal dj-database-url
  • 環境変数自体は.env(jira_api直下に新規作成する必要がある)に記述し、django-environは環境変数を簡単に扱える様にする
  • dj-dabase-urlはデーターベースを簡単に扱える様にする
settings.py
# 下記の2行を追加
import os
import environ

# BASE_DIRの定義箇所以下に以下の2行を追加
env = environ.Env()
env.read_env(os.path.join(BASE_DIR, '.env'))
# 以下省略

# 以下の3項目をそれぞれ編集
SECRET_KEY = env('SECRET_KEY')

DEBUG = env('DEBUG')

DATABASES = {
    'default': env.db(),
}
CORS_ORIGIN_WHITELIST = env.list('CORS_ORIGIN_WHITELIST')

STATIC_URL = '/static/'
# 下記の1行を追加
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
  • .envファイルの読み込ませるためにsettings.pyに編集
  • djangoには複数のstaticファイル(adminダッシュボードなど)があり、 djangoアプリのデプロイ時にはcollect staticコマンドを実行して、散らばったstaticファイルを一つのstaticフォルダ(新規作成する必要がある)に統合する必要があるのでプロジェクトディレクトリ直下に空のstaticディレクトリを作成する
.env
SECRET_KEY=settings.pyで設定されていたシングルクォートの中身
DEBUG=False
DATABASE_URL=sqlite:///db.sqlite3
CORS_ORIGIN_WHITELIST=http://localhost:3000
$ pip freeze > requirements-dev.txt
  • 開発時にimportしたライブラリをpip freeze > requirements-dev.txtコマンドで読み取って依存関係を吐き出す
requirements.txt
-r requirements-dev.txt
gunicorn
psycopg2
  • 本番環境用にrequirements.txtを作成し、requirements-dev.txtを読み込むのと、本番環境でgunicornとPostgreSQLを使用するので上記の2行を追加

以下AWS操作

1. VPCの作成

名前タグ CIDRブロック
portfolder-vpc 10.0.0.0/16

2. サブネットの作成

VPC ID サブネット名 アベイラビリティーゾーン CIDRブロック
portfolder-vpc pf-public-sn1 ap-notheast-1a 10.0.1.0/24
portfolder-vpc pf-public-sn2 ap-notheast-1d 10.0.2.0/24
portfolder-vpc pf-private-sn1 ap-notheast-1a 10.0.3.0/24
portfolder-vpc pf-private-sn1 ap-notheast-1d 10.0.4.0/24

3. インターネットゲートウェイを作成し、アタッチする

名前タグ
pf-igw

4 ルートテーブルの作成

4.1 ルートテーブルに下記のルートの追加

送信先 ターゲット
0.0.0.0/0 pf-igw

4.2 サブネットの関連付けタブから2つのパブリックサブネットの関連付け

5. EC2インスタンスの作成

異なるアベイラビリティーゾーンのEC2インスタンスを2つ作成

名前 アプリケーションおよびOSイメージ キーペア VPC サブネット
任意(本記事ではfp-ec2-1a) Ubuntu 任意(推奨) fp-vpc アベイラビリティーゾーン1a(もしくは1c)のpublicサブネット
パブリックIPの自動割り当て セキュリティーグループ セキュリティーグループ名 インバウンドセキュリティールール
有効化 作成 任意(本記事ではfp-public-sg) ルールは以下のスクショを参照

スクリーンショット 2023-01-29 13.14.16.png

6. ElasticIPアドレスを紐付け

ネットワークボーダーグループ
任意(本記事ではデフォルトのap-northeast-1)

作成完了後は一覧画面に戻り、アクション内のElastic IPアドレスの関連付けを選択し、先ほど作成したEC2インスタンスに紐付け(紐付け完了後は)

デフォルトでは起動する度にインスタンスのIPアドレスは変更されるが、こうする事によって、IPアドレスを固定化できる

6. RDSの作成

6.1 データベース(MySQL)の作成

データベースの作成時の選択項目

DB作成方法 エンジンオプション テンプレート マスターユーザー マスターパスワード
標準作成 MySQL 無料利用枠 admin 任意
コンピューティングリソース EC2インスタンス ネットワークタイプ VPC サブネットグループ
EC2 コンピューティングリソースに接続 作成済のもの IPv4 自動選択 自動選択
VPC SG 新しいSG名 AZ
一旦defaultを選択し、後に自動生成されたec2-rds-1に変更 pf-db-sg 自動選択

作成が完了すると、データベースとサブネットグループ(1a, 1c, 1dのそれぞれ異なるアベイラビリティーゾーン毎のサブネットと付随するルートテーブルなど)が作成される

6.2 サブネットグループの作成
(RDS作成時に自動生成されるようになってました。 一応下記は残しておきます。)

名前 説明 VPC アベイラビリティーゾーン マスターユーザー サブネット
fp-db-sngroup(任意) 何かしらの入力が必須 friends-phrase-vpc ap-notheast-1aと1c admin 1aと1c一つずつ

7. Route53にてホストゾーンの作成

8. お名前.comにてネームサーバーの設定

設定ができたかの確認

#Linux or Mac
$ dig NS ドメイン名

# windows
$ nslookup
> set type=ns
> ドメイン名

9. ACMにてSSL証明書を発行

ドメイン名
任意のドメイン名

9.1 証明書を選択し、Route53でレコードを作成ボタンを押下し、レコード作成

9.2 Route53にて作成したホストゾーンにCNAMEレコードの登録

10. ターゲットグループを作成

インスタンスを選択し、Include as pending belowボタンを押下

ターゲットタイプ ターゲットグループ名 VPC
Instance pf-target-group porfolder-vpc

11. Application LoadBalancerの作成

ロードバランサー名 VPC マッピング セキュリティーグループ  HTTPリスナーのデフォルトアクション
pf-loadbalancer portfolder-vpc pf-public-sn1, pf-public-sn2 pf-db-sg pf-targetgroup

11.1 既存のHTTPリスナーのルールを編集

スクリーンショット 2021-11-11 21.28.23.png

11.2 HTTPSリスナーの追加

プロトコル ポート デフォルトアクション デフォルトSSL
HTTPS 443 Foward to(pf-target-group) 作成したACM

12. route53にて、トラフィック先をALBにしたAレコードの作成

スクリーンショット 2021-11-11 22.24.42.png

13. 本番環境を構築

14.1 sshでEC2にアクセス

コマンドは作成したEC2インスタンスの接続ボタンから確認できる

ちなみに

..ssh/config
Host *
  ServerAliveInterval 60 
  TCPKeepAlive yes
  IPQoS=throughput  

上記の設定はubuntuに接続時に強制ログアウトになるのを防ぐ

13.2 各ライブラリ(データベースクライアント、gunicorn, nginxなど)をインストール

//EC2インスタンスに各ライブラリを導入
ubuntu@ip-00-0-0-000:~$ sudo apt-get update
ubuntu@ip-00-0-0-000:~$ sudo apt-get install python3-pip python3-dev mysql-server libmysqlclient-dev nginx

13.3 仮想環境の構築

ubuntu@ip-00-0-0-000:~$ sudo -H pip3 install --upgrade pip
ubuntu@ip-00-0-0-000:~$ sudo -H pip3 install virtualenv
ubuntu@ip-00-0-0-000:~$ virtualenv 仮想環境名
ubuntu@ip-00-0-0-000:~$ source 仮想環境名/bin/activate
(仮想環境名) ubuntu@ip-00-0-0-000:~$ git clone レポジトリ
(仮想環境名) ubuntu@ip-00-0-0-000:~$ cd リポジトリ名
(仮想環境名) ubuntu@ip-00-0-0-000:~/リポジトリ名$ pip install -r requirements.txt

ちなみに私用

requirements.txt
-r requirements-dev.txt
gunicorn
mysqlclient

13.4 本番環境用の環境変数を作成

EC2内の.env
SECRET_KEY=ローカル環境で初めに設定されていたシークレットキー
DEBUG=False
DATABASE_URL=mysql://ユーザー名:パスワード@RDSのエンドポイント:/データベース名
ALLOWED_HOSTS=EC2インスタンスの独自ドメイン
CORS_ORIGIN_WHITELIST=firebase側のURLを設定する
AWS_ACCESS_KEY_ID=各自設定が必要
AWS_SECRET_ACCESS_KEY=各自設定が必要
AWS_STORAGE_BUCKET_NAME=各自設定が必要
アプリ名/settings.py
ALLOWED_HOSTS = env.list('ALLOWED_HOSTS')

13.5 RDSにアクセスし、データベースを作成

//データベースの作成
$ mysql -h RDSのエンドポイント -u admin -p
mysql> CREATE DATABASE データベース名;
(仮想環境名) ubuntu@ip-00-0-0-000:~/リポジトリ名$ python3 manage.py migrate
(仮想環境名) ubuntu@ip-00-0-0-000:~/リポジトリ名$ python3 manage.py collectstatic
(仮想環境名) ubuntu@ip-00-0-0-000:~/リポジトリ名$ python3 manage.py createsuperuser
  • 本番環境用にpostgresqlのデーターベースを作成したので、models.pyのデータベース構造を再度展開するためにmigrateする必要がある
  • プロジェクト内に散らばったstaticファイルをstaticフォルダに統合する

14.6 gunicornの設定

$ sudo vi /etc/systemd/system/gunicorn.service
gunicorn.service
[Unit]
Description=gunicorn daemon
After=network.target

[Service]
User=ubuntu
Group=www-data
WorkingDirectory=/home/ubuntu/プロジェクト名
ExecStart=/home/ubuntu/仮想環境名/bin/gunicorn --access-logfile - --workers 3 --bind unix:/home/ubuntu/プロジェクト名/アプリ名.sock アプリ名.wsgi:application

[Install]
WantedBy=multi-user.target
  • WorkingDirectoryは[/ から Django Project Root までパス]/[Django Project Root(git cloneならリポジトリ名)]
  • ExecStartは[/ から gunicorn コマンドまでのパス]/gunicorn --access-logfile - --workers 3 --bind unix: (wsgiが入ってるディレクトリ).wsgi:application
  • gunicornの設定ファイルは公式ドキュメントを参考にしております。

gunicornの起動

$ sudo systemctl restart gunicorn
$ sudo systemctl enable gunicorn

13.7 nginxの設定

$ sudo vi /etc/nginx/sites-available/プロジェクト名
server {
        listen 80;
        server_name EC2のパブリックIPアドレス;

        location = /favicon.ico {access_log off; log_not_found off;}
        location /static/ {
                root /home/ubuntu/プロジェクト名;
        }
        location / {
                include proxy_params;
                proxy_pass http://unix:/home/ubuntu/プロジェクト名/アプリ名.sock;
        }
}
  • プロジェクト名(git clone)はリポジトリ名

nginxの起動

//シンボリックリンクを作成
$ sudo ln -s /etc/nginx/sites-available/プロジェクト名 /etc/nginx/sites-enabled/

//nginxの起動
$ sudo systemctl restart nginx

//80ポートを解放
$ sudo ufw allow 'Nginx Full'
  • 上記で作成した設定ファイルに対してシンボリックリンクを作成する(こうすることによって実態のファイルを削除しなくてもリンクを切ることで、新しくリンクさせることができる)
  • ec2コンソールに戻り、先ほど作成したセキュリティーグループのインバウンドルールにhttpタイプ0.0.0.0/0ソースを追加した後にgunicornを起動

ちなみにnginx status確認コマンド

$ sudo systemctl status nginx.service

14. 本番環境用の設定

(フロントエンド).env.production
REACT_APP_API_URL=EC2のパブリックIPアドレスもしくは独自ドメイン
(バックエンド)settings.py
CORS_ORIGIN_WHITELIST = [
    "firebase側のURLを設定する"
]

Route53とACMについての参考記事

おまけ

ssh: connect to host ec2-00-00-000-00.ap-northeast-1.compute.amazonaws.com port 22: Connection refusedのチェックポイント

  • EC2インスタンスに付随しているセキュリティーグループのインバウンドルールにsshが追加されているか
  • EC2インスタンスに付随しているサブネットグループは適正かどうか(publicのサブネットグループになっているかなど)
  • publicルートテーブルの関連付けに上記のサブネットグループが追加されているかどうか

削除したくなった場合のRDSの削除手順

  1. RDSインスタンスを削除
  2. RDS用のサブネットグループの削除
  3. RDS用セキュリティーグループのインバウンドとアウトバウンドを空にしてから削除(空にしないと削除出来ない)もしくはセキュリティーグループ関連づけを削除

ERR_CONNECTION_TIMED_OUTのエラー

ALBのアクセスログに関してはこちら

ちなみに私用

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::バケット名/*"
        },
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::東京リージョンの場合h582318560864:root"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::バケット名/*"
        },
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "delivery.logs.amazonaws.com"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::バケット名/*",
            "Condition": {
                "StringEquals": {
                    "s3:x-amz-acl": "bucket-owner-full-control"
                }
            }
        },
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "delivery.logs.amazonaws.com"
            },
            "Action": "s3:GetBucketAcl",
            "Resource": "arn:aws:s3:::バケット名"
        }
    ]
}

参考文献

スクリーンショット 2021-10-03 21 11 10

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?