【Python/Django】よく使うコマンドのまとめ(4)-前編- <本番運用：Amazon EC2 (Amazon Linux 2)>

#### 背景
Python/Djangoで開発をすすめるにあたり、よく使うコマンドをまとめておきます。

先人たちの知恵をお借りするなどして解決できたことを、この場をお借りして感謝するとともに、大変恐縮ですが自分のメモとしても、こちらへまとめておきます。

#### 環境
（本番環境）

- AWS EC2 (Amazon Linux 2)
- Python 3.7.9　　　　※2020/12/10時点のAmazon Linux2でのデフォルト
- Django 3.1.3
- PostgreSQL 11.5　　※同上
- Nginx 1.12　　　　　※同上
- Gunicorn
- Putty 0.74


（開発環境）

- Windwos 10 Pro
- Python 3.9.0
- Django 3.1.3
- PostgreSQL 13.1
- Nginx 1.19.5
- Gunicorn
- Putty 0.74


#### 前提

WEBサーバー、APサーバー、DBサーバーを、Amazon EC2(Elastic Computing Cloud) : Amazon Linux 2 で構築します。

(構成図)
![構成図_基本形.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/902793/788877be-c361-f7e1-e1a3-33257395f350.png)



- EC2インスタンスへSSH接続した状態で、以降のコマンドを実行します。

※ PuTTY を利用して、Amazon EC2(Elastic Compute Cloud)へ接続する際は、「[PuTTY を使用した Windows から Linux インスタンスへの接続](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/putty.html)」をご参照ください。

## 1. Amazon Linux 2 のパッケージを更新する

```:ターミナル
$ sudo yum update -y
```

## 2. 日本仕様へ変更する

デフォルトはUTC（協定世界時）となっているため、日本標準時(JST)へ変更します。

#### 2-1. タイムゾーン

```:ターミナル
$ sudo timedatectl set-timezone Asia/Tokyo

$ date

2020年 12月 10日 木曜日 11:23:45 JST
```
「date」コマンドは、現在の日付時刻を取得します。日本標準時(JST)に変更されていれば、末尾に「JST」と表示されます。

#### 2-2. 言語設定

デフォルトはUS仕様となっているため、日本語文字コード(jz_JP.UTF-8)へ変更します。

```:ターミナル
$ sudo localectl set-locale LANG=ja_JP.UTF-8

$ localectl status

  System Locale: LANG=ja_JP.UTF-8
    VC Keymap: n/a
   X11 Layout: n/a
```

## 3. 作業用ユーザーを作成し、ec2-userを削除する

デフォルトユーザー（ec2-user）は周知されているユーザー名のため、このまま使い続けるのはセキュリティ面のリスクが高過ぎます。
このため、作業用ユーザーを任意のユーザー名で新たに作成し、ec2-userを削除してしまいます。

#### 3-1. 作業用ユーザーを作成します。

```:ターミナル
$ sudo useradd ＜任意のユーザー名＞
```

#### 3-2. ec2-userのホームディレクトリにあるSSH用ディレクトリ(.ssh)を、＜任意のユーザー名＞のホームディレクトリへコピーします。

```:ターミナル
$ sudo cp -arp /home/ec2-user/.ssh /home/＜任意のユーザー名＞
```

#### 3-3. SSH用ディレクトリとその中身のすべての所有者を＜任意のユーザー名＞へ変更します。

```:ターミナル
$ sudo chown -R ＜任意のユーザー名＞ /home/＜任意のユーザー名＞/.ssh
```

#### 3-4. ＜任意のユーザー名＞へsudo権限を付与するために、 sudoer (sudo権限を管理するファイル) を編集します。

```:ターミナル
$ sudo visudo -f /etc/sudoers.d/90-cloud-init-users
```

```:/etc/sudoers.d/90-cloud-init-users
# User rules for ec2-user
# ec2-user ALL=(ALL) NOPASSWD:ALL            コメントアウト
＜任意のユーザー名＞ ALL=(ALL) NOPASSWD:ALL     追加
```

#### 3-5. ＜任意のユーザー名＞でEC2へSSH接続し直します。

＜任意のユーザー名＞でSSH接続し、Roor(ルート)に切り替わるかを確認します。

```:ターミナル
$ sudo su -

root #
```

「root #」と表示が切り替われば、成功です。
確認が済みましたら、「exit」と入力して、Rootからログアウトします。

```:ターミナル
root # exit

ログアウト
$
```

#### 3-6. ec2-userを削除します。

ec2-user のホームディレクトリも削除するために、「-r」オプションも付けます。

```:ターミナル
$ sudo userdel -r ec2-user
```

## 4. Python をインストールし、バージョンを確認する。

```:ターミナル
$ sudo yum install python3

$ python3 --version

Python 3.7.9
```

## 5. pip管理モジュールを一括してインストールする。

#### 5-0. 予め、開発環境でpipインストールしていたモジュールを「requirements.txt」に出力しておきます。

```:ターミナル（開発環境）
(venv_＜プロジェクト名＞)$ pip freeze > requirements.txt
```

#### 5-1. 出力された「requirements.txt」を、本番運用環境の作業用ユーザー（上述の＜任意のユーザー名＞）のホームディレクトリへ転送しておきます。

#### 5-2. ＜任意のユーザー＞のホームディレクトリにPython仮想環境を作成します。

```:ターミナル
$ python3 -m venv venv_＜プロジェクト名＞
```

#### 5-3.Python仮想環境へ入ります。

```:ターミナル
$ source venv_＜プロジェクト名＞/bin/activate
```

#### 5-4. 「requirements.txt」を読み込み、モジュールをインストールします。

```:ターミナル
$ pip install -r requirements.txt
```

#### 5-5. Amazon SES(Simple Email Service)用モジュールをインストールします。

ユーザー認証を介したり問い合わせフォームを設置したりするWEBサイトやWEBアプリケーションを作成する際は、必ずお世話になるモジュールです。

```:ターミナル
$ pip install boto django-ses
```

#### 5-6. Gunicorn用モジュールをインストールします。

```:ターミナル
$ pip install gunicorn
```

## 6. PostgreSQLをインストールし、初期設定をします。

#### 6-1. PostgreSQLをインストールします。

```:ターミナル
$ amazon-linux-extras list | grep postgresql

  5  postgresql9.6            available    \
  6  postgresql10             available    [ =10  =stable ]
 41  postgresql11=latest      enabled      [ =11  =stable ]
```

ver.11 がインストール可能な最も高いバージョンであることが分かりました。
下記を実行してインストールします。

```:ターミナル
$ sudo amazon-linux-extras install postgresql11
```

バージョンを確認します。

```:ターミナル
$ psql --version

psql (Postgres) 11.5
```

#### 6-2. DBサーバーとして動作させるためのパッケージをインストールする。

```:ターミナル
$ sudo yum install postgresql-server
```

#### 6-3. PostgreSQLの初期設定を行ないます。

##### 6-3-1. データベースの初期化

```:ターミナル
$ sudo postgresql-setup initdb
```

以下のWARNINGメッセージが表示される場合があります。
これは、PostgreSQLが自動でオプションを最適化したためによるもので、初期化の処理自体に問題はありません。

```:ターミナル
WARNING: using obsoleted argument syntax, try --help
WARNING: arguments transformed to: postgresql-setup --initdb --unit postgresql
```

##### 6-3-2. PostgreSQLサービスを自動起動させる設定

```:ターミナル
$ sudo systemctl enable postgresql
```

##### 6-3-5. PostgreSQLサービスを起動させる

```:ターミナル
$ sudo systemctl start postgresql
```

##### 6-3-6. PostgreSQL環境へログインし、データベース用のユーザーと、データベースをそれぞれ作成します。

```:ターミナル
$ sudo -u postgres -i psql

psql (11.5)
"help" でヘルプを表示します。
postgres=# create user ＜任意のユーザー名＞ with password '＜任意のパスワード＞';
CREATE ROLE
postgres=# create database ＜データベース名＞ owner ＜任意のユーザー名＞;
CREATE DATABASE
```

##### 6-3-7. PostgreSQL環境からログアウトします。

```:ターミナル
postgres=# \q
```



## 7. 本番運用環境にソースコードを配置する。

#### 7-1. gitをインストールします。

```:ターミナル
$ sudo yum install git
```

#### 7-2. 初回（全量をコピーする場合）

##### 7-2-1. Python仮想環境へ移動します。

```:ターミナル
$ cd ~/venv_＜プロジェクト名＞
```

##### 7-2-2. 下記を実行します。　※筆者の環境では途中BitBucketのパスワード入力が必要です。

```:ターミナル
$ git clone https://＜bitbucketのアカウント＞@bitbucket.org/＜bitbucketのアカウント＞/＜bitbucketのリモートリポジトリ名＞.git

Cloning into '＜リモートリポジトリ名＞'...
Password for 'https://＜bitbucketのアカウント＞@bitbucket.org':                 
remote: Counting objects: 123, done.
remote: Compressing objects: 100% (123/123), done.
remote: Total 123 (delta 25), reused 0 (delta 0)
Unpacking objects: 100% (123/123), done.
```

#### 7-3. 二回目以降（差分のみを更新する場合）

##### 7-3-1. Python仮想環境へ移動します。（manage.pyの存在するディレクトリまで移動します。）

```:ターミナル
$ cd ~/venv_＜プロジェクト名＞/＜プロジェクト名＞
```

##### 7-3-2. 下記を実行します。　※筆者の環境では途中BitBucketのパスワード入力が必要です。

```:ターミナル
$ git pull

Password for 'https://＜bitbucketのアカウント＞@bitbucket.org':                 
remote: Counting objects: 8, done.
remote: Compressing objects: 100% (8/8), done.
remote: Total 8 (delta 2), reused 0 (delta 0)
Unpacking objects: 100% (123/123), done.
From https://bitbucket.org/＜bitbucketのアカウント＞/＜bitbucketのリモートリポジトリ名＞
  29912a3..c5aac44 master    -> origin/master
fatal: refusing to merge unrelated histories
```


## 8. ログの出力先ディレクトリを作成する。

```:ターミナル
$ mkdir ~/venv_＜プロジェクト名＞/＜プロジェクト名＞/logs
```

---
#### (関連)
[【Python/Django】よく使うコマンドのまとめ(1) ＜仮想環境、プロジェクト、アプリケーションの作成＞](https://qiita.com/_whitecat_22/items/6a35200ba958a63eb683)
[【Python/Django】よく使うコマンドのまとめ(2) ＜パッケージのインストール＞](https://qiita.com/_whitecat_22/items/d1d06ea1e280c1665482)
[【Python/Django】よく使うコマンドのまとめ(3) ＜PostgreSQLの操作＞](https://qiita.com/_whitecat_22/items/264b13f9d7c2f020a7ad)
[【Python/Django】よく使うコマンドのまとめ(4)-後編- ＜本番運用：Amazon EC2 (Amazon Linux 2)＞](https://qiita.com/_whitecat_22/items/351d2ac5963c770284cb)

---
#### (編集後記)
本番運用時のみならず、開発環境としてEC2を利用することもできますので、Dockerの利用も併せて検討していきたいです。