uwsgi(ついでにdjango+MySQL)の初期設定

前回はpython3.9.1のインストールまで行いました。
https://qiita.com/Tetsuya_abori/items/1bfd5e7060d187dec92c


今回はその続きの環境構築を行います。
下記サイトを参照しました。
https://www.digitalocean.com/community/tutorials/how-to-set-up-uwsgi-and-nginx-to-serve-python-apps-on-centos-7
https://qiita.com/Ningensei848/items/e91fbeef5f03685a7a0b

##事前準備　コンポーネントのインストール
まずEPELレポジトリをインストールします。
これは多くのパッケージにアクセスするために必要になります。

```
$ sudo yum install epel-release
```

次に、python開発用のライブラリ、ヘッダーなどをインストールします。
ちょっと原文よくわからなかったので一部転記します。
We need to get the Python development libraries and headers, the pip Python package manager, and the Nginx web server and reverse proxy. We will also need a compiler to build the uWSGI binary momentarily:

```
$ sudo yum install python-pip python-devel nginx gcc
```


```
#pipのバージョンが古いという警告が出た方は事前に下記を実行
$ pip install --upgrade pip
```

##アプリ用ディレクトリと仮想環境の構築
```
#任意の場所にアプリ用ディレクトリを作成
$ mkdir /home/admin/myapp/
#作成したディレクトリに移動
$ cd /home/admin/myapp/
#参照サイトにはvirtualenvとありましたが、python3.3以降はvenv推奨なので書き換えました
$ python -m venv myappenv
#仮想環境を起動
$ source myappenv/bin/activate
⇒(myappenv)と出ていれば成功
#終了するときは
$ deactivate

```
##uwsgiのインストール
仮想環境内にuwsgiをインストールします。
###uwsgiを理解する
pythonのアプリケーションサーバです。
uwsgiを理解するにはwsgiを理解する必要があります。

###wsgiとは
Web Server Gateway Interdaceの略です。
pythonのwebアプリケーションとwebサーバのやり取りを行うプロトコルです。


###uwsgiとは
uwsgiはwsgiに対応したpythonのアプリケーションサーバの1つです。

###各用語の整理
####webサーバ
#####具体例
nginx,Apache
#####役割
ユーザからリクエストを受け取り、何らかの処理を加えるプログラム
####アプリケーションサーバ
#####具体例
uwsgi,puma
#####役割
アプリケーションを動かす。
リクエスト/レスポンスの受け渡しを行う。

```
$ pip install uwsgi
$ uwsgi --version
2.0.19.1
$ vi ~/myapp/wsgi.py
def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return [b"Hello world"]
```

uwsgiを起動して、接続テストしてみます。

```
# uWSGI 起動　ポート番号は任意
$ uwsgi --http :8000 --wsgi-file wsgi.py

*** Starting uWSGI 2.0.19.1 (64bit) on [Sat Dec 12 21:29:39 2020] ***
compiled with version: 4.8.5 20150623 (Red Hat 4.8.5-44) on 12 December 2020 03:40:30
os: Linux-3.10.0-693.el7.x86_64 #1 SMP Tue Aug 22 21:09:27 UTC 2017
nodename: f5les1se
machine: x86_64
clock source: unix
pcre jit disabled
detected number of CPU cores: 1
current working directory: /home/admin/myapp
detected binary path: /home/admin/myapp/myappenv/bin/uwsgi
*** WARNING: you are running uWSGI without its master process manager ***
your processes number limit is 3883
your memory page size is 4096 bytes
detected max file descriptor number: 1024
lock engine: pthread robust mutexes
thunder lock: disabled (you can enable it with --thunder-lock)
uWSGI http bound on :8000 fd 4
spawned uWSGI http 1 (pid: 25114)
uwsgi socket 0 bound to TCP address 127.0.0.1:45435 (port auto-assigned) fd 3
Python version: 3.9.1 (default, Dec 12 2020, 11:59:59)  [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]
*** Python threads support is disabled. You can enable it with --enable-threads ***
Python main interpreter initialized at 0x12a9b70
your server socket listen backlog is limited to 100 connections
your mercy for graceful operations on workers is 60 seconds
mapped 72920 bytes (71 KB) for 1 cores
*** Operational MODE: single process ***
WSGI app 0 (mountpoint='') ready in 0 seconds on interpreter 0x12a9b70 pid: 25113 (default app)
*** uWSGI is running in multiple interpreter mode ***
spawned uWSGI worker 1 (and the only) (pid: 25113, cores: 1)
```

これでつながるはず。
が、繋がらない。。。

別ポートでも実験

```
$ uwsgi --http :8888 --wsgi-file wsgi.py
```

変わらず。
そもそも接続拒否されているからブラウザの設定を見直す必要あり？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/764778/9aa3acaf-d002-5005-c6c6-17d20edcfed4.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/764778/71a9b43c-ea08-5f94-0cc4-30df87c2d9bf.png)

今回はVPSだからそもそもローカルではないのでは？と思い、以下を実行しても変わらず。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/764778/f0049415-1830-aefd-bc5c-3db8b8df86d2.png)

繋がらない原因究明が必要ですね。
uwsgi.iniファイルの設定が怪しいのではないかと考えられました。

ここからは以下のサイトを参考にしました。
https://www.saintsouth.net/blog/setup-django-app-with-uwsgi-and-nginx/

####iniファイルとは
そもそもiniファイルとはなんなのでしょうか。自分は知らなかったので調べました。

* 設定ファイルの種類を表す俗称の1つ
* 拡張子の1つ
* プログラムを使っていくうえで変更するかもしれない設定値を記載しておくファイル
* プログラムが動く時は設定ファイルを読み込む
* 設定ファイルを変えることでプログラムを書き換えないで、動きを変更できる

設定ファイルの拡張子は慣例的に、「.ini」や「.conf」が多いです。

###uwsgiコマンドによるwsgiサーバの動作確認
uwsgi.iniファイルではdjangoに関する設定も行うため、先にdjangoをインストールしておきます。

```
# pip3 install django
```

デプロイ用webアプリのディレクトリ構成を整理します。
最終的に以下のようになるようにします。

```
home/
    admin/
         myapp/
             uwsgi-webapp.service ← systemctl コマンドで WSGI サーバーを操作するためのサービス設定ファイル
             uwsgi.ini ← Web アプリケーションを WSGI サーバーとして起動する際に指定する設定ファイル
             myappenv/ ← 本番環境用の myappenv を格納するディレクトリ
             webapp/ ← django のプロジェクトルート
                 webapp/
                 main/
                 static/
```

djangoのプロジェクトルートを作成します。

```
$ django-admin startproject webapp
```

次にdjangoのメインアプリケーションを作成します。

```
python manage.py startapp main

Traceback (most recent call last):
  File "/home/admin/myapp/webapp/manage.py", line 22, in <module>
    execute_from_command_line(sys.argv)
  File "/home/admin/.pyenv/versions/3.9.1/lib/python3.9/site-packages/django/core/management/__init__.py", line 401, in execute_from_command_line
    utility.execute()
  File "/home/admin/.pyenv/versions/3.9.1/lib/python3.9/site-packages/django/core/management/__init__.py", line 377, in execute
    django.setup()
  File "/home/admin/.pyenv/versions/3.9.1/lib/python3.9/site-packages/django/__init__.py", line 24, in setup
    apps.populate(settings.INSTALLED_APPS)
  File "/home/admin/.pyenv/versions/3.9.1/lib/python3.9/site-packages/django/apps/registry.py", line 114, in populate
    app_config.import_models()
  File "/home/admin/.pyenv/versions/3.9.1/lib/python3.9/site-packages/django/apps/config.py", line 211, in import_models
    self.models_module = import_module(models_module_name)
  File "/home/admin/.pyenv/versions/3.9.1/lib/python3.9/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1030, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
  File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 790, in exec_module
  File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
  File "/home/admin/.pyenv/versions/3.9.1/lib/python3.9/site-packages/django/contrib/auth/models.py", line 2, in <module>
    from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
  File "/home/admin/.pyenv/versions/3.9.1/lib/python3.9/site-packages/django/contrib/auth/base_user.py", line 48, in <module>
    class AbstractBaseUser(models.Model):
  File "/home/admin/.pyenv/versions/3.9.1/lib/python3.9/site-packages/django/db/models/base.py", line 122, in __new__
    new_class.add_to_class('_meta', Options(meta, app_label))
  File "/home/admin/.pyenv/versions/3.9.1/lib/python3.9/site-packages/django/db/models/base.py", line 326, in add_to_class
    value.contribute_to_class(cls, name)
  File "/home/admin/.pyenv/versions/3.9.1/lib/python3.9/site-packages/django/db/models/options.py", line 206, in contribute_to_class
    self.db_table = truncate_name(self.db_table, connection.ops.max_name_length())
  File "/home/admin/.pyenv/versions/3.9.1/lib/python3.9/site-packages/django/db/__init__.py", line 28, in __getattr__
    return getattr(connections[DEFAULT_DB_ALIAS], item)
  File "/home/admin/.pyenv/versions/3.9.1/lib/python3.9/site-packages/django/db/utils.py", line 214, in __getitem__
    backend = load_backend(db['ENGINE'])
  File "/home/admin/.pyenv/versions/3.9.1/lib/python3.9/site-packages/django/db/utils.py", line 111, in load_backend
    return import_module('%s.base' % backend_name)
  File "/home/admin/.pyenv/versions/3.9.1/lib/python3.9/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "/home/admin/.pyenv/versions/3.9.1/lib/python3.9/site-packages/django/db/backends/sqlite3/base.py", line 70, in <module>
    check_sqlite_version()
  File "/home/admin/.pyenv/versions/3.9.1/lib/python3.9/site-packages/django/db/backends/sqlite3/base.py", line 67, in check_sqlite_version
    raise ImproperlyConfigured('SQLite 3.8.3 or later is required (found %s).' % Database.sqlite_version)
django.core.exceptions.ImproperlyConfigured: SQLite 3.8.3 or later is required (found 3.7.17).
```

エラーが出ました。
データベースとして指定しているsqliteのバージョンが古いためです。
今回データベースはMySQLを使う予定でしたので(情報量が多いため)、これを機にMySQLの設定を行います。

###MySQLの設定

以下の記事を参考にしました。
https://qiita.com/nooboolean/items/7efc5c35b2e95637d8c1
※Mac環境でやっているため、centOSに読み替えました。

###レポジトリの追加
まずレポジトリなんなのか曖昧だったので調べました。
「ファイル、プログラム、設定情報の保管場所」
を指します。

ということでレポジトリを追加します。

```
#MySQLの公式サイトを参考に環境にあったレポジトリをインストール
# yum localinstall http://dev.mysql.com/get/mysql80-community-rele
ase-el7-3.noarch.rpm
```

###レポジトリの確認
/etc/yum.repos.d配下に
* mysql-community-source.repo
* mysql-community.repo
が作成されているはずです。

```
# cd /etc/yum.repos.d/
# ls
CentOS-Base.repo       CentOS-Sources.repo        mysql-community.repo
CentOS-CR.repo         CentOS-Vault.repo          mysql-community-source.repo
CentOS-Debuginfo.repo  CentOS-x86_64-kernel.repo  nginx.repo
CentOS-fasttrack.repo  epel.repo
CentOS-Media.repo      epel-testing.repo
```

###レポジトリのインストール
まずはレポジトリの情報の確認をします。

```
# yum info mysql-community-server
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * base: ty1.mirror.newmediaexpress.com
 * epel: ftp.iij.ad.jp
 * extras: ty1.mirror.newmediaexpress.com
 * updates: ty1.mirror.newmediaexpress.com
mysql-connectors-community                                  | 2.6 kB  00:00:00
mysql-tools-community                                       | 2.6 kB  00:00:00
mysql80-community                                           | 2.6 kB  00:00:00
(1/3): mysql-connectors-community/x86_64/primary_db         |  68 kB  00:00:00
(2/3): mysql80-community/x86_64/primary_db                  | 128 kB  00:00:00
(3/3): mysql-tools-community/x86_64/primary_db              |  83 kB  00:00:00
Available Packages
Name        : mysql-community-server
Arch        : x86_64
Version     : 8.0.22
Release     : 1.el7
Size        : 510 M
Repo        : mysql80-community/x86_64
Summary     : A very fast and reliable SQL database server
URL         : http://www.mysql.com/
License     : Copyright (c) 2000, 2020, Oracle and/or its affiliates. Under GPLv2
            : license as shown in the Description field.
Description : The MySQL(TM) software delivers a very fast, multi-threaded,
            : multi-user, and robust SQL (Structured Query Language) database
            : server. MySQL Server is intended for mission-critical, heavy-load
            : production systems as well as for embedding into mass-deployed
            : software. MySQL is a trademark of Oracle and/or its affiliates
            :
            : The MySQL software has Dual Licensing, which means you can use the
            : MySQL software free of charge under the GNU General Public License
            : (http://www.gnu.org/licenses/). You can also purchase commercial
            : MySQL licenses from Oracle and/or its affiliates if you do not wish
            : to be bound by the terms of the GPL. See the chapter "Licensing and
            : Support" in the manual for further info.
            :
            : The MySQL web site (http://www.mysql.com/) provides the latest news
            : and information about the MySQL software.  Also please see the
            : documentation and the manual for more information.
            :
            : This package includes the MySQL server binary as well as related
            : utilities to run and administer a MySQL server.
```

パッケージ情報が出てきたらOK。
実際にインストールします。

```
# yum install -y mysql-community-server
```

###MySQLが入っているかの確認
ここではmysqldというコマンドを使います。
用語が分からなかったので調べました。

####mysqldとは
* MySQLとして働くデーモン
デーモンとは??

まずMySQLとは「Webシステムでよく使われるデータベース」です。

そしてデーモンとは
「UNIX系OS(LinuxやMac)における常駐プログラムの呼び名。」
Windowsでいうところのサービスです。

つまりデーモンは常に待機状態であり、指令が下されたときにいつでも動くプログラムです。

そしてMySQLの代理プログラムがmysqldです。

それでは本題に戻ります。

####MySQLが入っているか

```
# mysqld --version
/usr/sbin/mysqld  Ver 8.0.22 for Linux on x86_64 (MySQL Community Server - GPL)
```

####MySQLの起動

```
# systemctl start mysqld
```

少し時間がかかりました。

####起動の確認

```
# systemctl status mysqld
● mysqld.service - MySQL Server
   Loaded: loaded (/usr/lib/systemd/system/mysqld.service; enabled; vendor preset: disabled)
   Active: active (running) since Sun 2020-12-13 11:37:39 JST; 16s ago
     Docs: man:mysqld(8)
           http://dev.mysql.com/doc/refman/en/using-systemd.html
  Process: 31850 ExecStartPre=/usr/bin/mysqld_pre_systemd (code=exited, status=0/SUCCESS)
 Main PID: 31921 (mysqld)
   Status: "Server is operational"
   CGroup: /system.slice/mysqld.service
           mq31921 /usr/sbin/mysqld

Dec 13 11:37:10 f5les1se systemd[1]: Starting MySQL Server...
Dec 13 11:37:39 f5les1se systemd[1]: Started MySQL Server.
```

正常に動いていました。

####停止するとき

```
# systemctl stop mysqld
```

####自動起動の設定
centOSの起動時にMySQLも起動するように設定しておきます。
自動起動はenableコマンドを使います。

```
# systemctl enable mysqld
```

###MySQLの初期設定
インストールが完了したので、初期設定を行います。

最初はrootユーザしかいないため、異端rootで入ります。

```
# mysql -u root
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)
```

エラーが出ました。
パスワードが求められました。

調べてところ、初期パスワードはmysqlのログに記載されているようです。

```
# cat /var/log/mysqld.log | grep root
```

記載してあったパスワードでログインしなおします。

```
# mysql -u root -p
Enter password:[パスワード]
```

入れました。
パスワードは変更しておきます。

```
mysql> SET PASSWORD = '任意のパスワード';
```
※パスワードは8文字以上かつ、大文字・小文字・記号入り

一度ログアウトしてログインしてみます。

```
mysql> quit
Bye
# mysql -u root -p
Enter password:
```

行けました。

####文字コードの確認と変更
設定されている文字コードの確認は以下で行えます。

```
mysql> show variables like "chara%";
+--------------------------+--------------------------------+
| Variable_name            | Value                          |
+--------------------------+--------------------------------+
| character_set_client     | utf8mb4                        |
| character_set_connection | utf8mb4                        |
| character_set_database   | utf8mb4                        |
| character_set_filesystem | binary                         |
| character_set_results    | utf8mb4                        |
| character_set_server     | utf8mb4                        |
| character_set_system     | utf8                           |
| character_sets_dir       | /usr/share/mysql-8.0/charsets/ |
+--------------------------+--------------------------------+
8 rows in set (0.00 sec)
```

それぞれの意味は以下のようです。
```
character_set_client : クライアント側で発行したsql文はこの文字コードになる
character_set_connection : クライアントから受け取った文字をこの文字コードへ変換する
character_set_database : 現在参照しているDBの文字コード
character_set_results : クライアントへ送信する検索結果はこの文字コードになる
character_set_server : DB作成時のデフォルトの文字コード
character_set_system : システムの使用する文字セットで常にutf8が使用されている
```

全部utf-8にしておきます。
(統一しておくことでエラーを防ぐため？)

```
# vi /etc/my.cnf
#以下を追記しました。
character_set_server=utf8
skip-character-set-client-handshake
```

変更されているか確認します。

```
# systemctl restart mysqld
# mysql -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.22 MySQL Community Server - GPL

Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show variables like "chara%";
+--------------------------+--------------------------------+
| Variable_name            | Value                          |
+--------------------------+--------------------------------+
| character_set_client     | utf8                           |
| character_set_connection | utf8                           |
| character_set_database   | utf8                           |
| character_set_filesystem | binary                         |
| character_set_results    | utf8                           |
| character_set_server     | utf8                           |
| character_set_system     | utf8                           |
| character_sets_dir       | /usr/share/mysql-8.0/charsets/ |
+--------------------------+--------------------------------+
8 rows in set (0.01 sec)
```

###ユーザの追加

```
CREATE USER '[ユーザ名]'@'[IP]' IDENTIFIED BY '[パスワード]'
```




無事変更されていました。
以上で初期設定完了です。