RのWeb制作

Webサービス制作のための技術情報を。データ分析(Python、機械学習コンペ他)や自作野球ゲームMeisyoのこと中心。

Web制作 Python SQL VPS

(VPSでつくる) Socket通信を使ったモダンなチャットアプリをFlaskで作ろう

投稿日:

連載第十三回目です。

今回は、チャットアプリを作っていきたいと思います。
チャットの想定としては、会員制、socket通信で滑らかにチャットできる、データベースにログを残すにしましょう。

ただのチャットとは言え、使いやすさも考えて構築を行います。
そのため、HTML、JavaScript(jQuery含む)、CSSなどでの記載も行います。
ただし、理解が簡単になるよう、コメントを多めに書いています。

この記事は、VPSで作るPythonでのWebアプリ運用環境の連載記事です。
その他については上記ページをお読みください。

作業予定

まず、テストアプリプログラムファイルのダウンロードが必要です。
Github(https://github.com/R2002/flask_chat)
テストアプリフォルダ(app/flask_chat)は、VPS上の/usr/share/nginx/app/flask_chatにアップロードします。

作業予定としては以下を想定しています。
・Gunicorn+eventletの設定
・CentOS7日本語対応
・チャットアプリのsystemd上でのサービス化
・Nginxの設定
・公開(デプロイ)

socket通信には、Gunicornやeventletなどのサービスが必要になります。Webサーバー兼リバースプロキシのNginxだけでは対応できません。
そのため、いろいろと設定が必要になります。

続いて、どのような思考でそれぞれのプログラムが書かれているのか確認します。

構成


このアプリは、チャットアプリです。
滑らかなチャットを行うためにsocket通信を使います。

socket通信の担い手はWSGIサーバーであるGunicorn、その一機能のeventletです。
前回のアプリまで使っていたNginx Unitは、eventletに関する資料がなかったので使いませんでした。

ファイル構成


ファイルごとに関係を示します。

前回と比べconfig.pyなどが増えましたが、設計思考は同じです。
viewsとmodelsをディレクトリ化したのは、機能の増加を何度か行い記載量が増えた際に、コーディングの状況が一人開発ですら分かり辛くなるからです。例えば、app.pyにviewsの記載をべた書きしていると、複数人での開発は困難になります。

ディレクトリを分けることによって、機能の一時停止判断や、バージョンアップ・ダウンの切り替え作業が非常に簡単になります。

なお、Flaskアプリの起動にはrun.pyを利用しています。
すべてのファイルは、run.pyから見た絶対的または相対的な記述が必要です。
例えば、importやfromで指定するディレクトリはどこか、パスはどう記載しなければ動かないか等です。

Gunicorn+eventletの設定

flask-socketioの公式を参考にします。

まずは、仮想環境(/usr/share/nginx/venv/flask_chat)を作り、その環境上でgunicornなどをインストールします。
gunicorn以外は、テストアプリに含まれるrequirements.txtをご利用ください。

pip install gunicorn==20.1.0

※バージョンは変更して問題ありません。

最後に、アプリフォルダ(/usr/share/nginx/app/flask_chat)に移動して、gunicornでflask_chatを起動します。

gunicorn -k eventlet -w 1 run:application

ちなみに、Windows上ではgunicornは動きませんのでご注意ください。

CentOS7、Windowsどちらでも動く下記コマンドは優秀ですね!

python run.py

何度かテスト立ち上げをしていると、ポートはもう使われているというエラーが出ます。
その場合はポートを開けるために、プロセスを停止させる必要があります。

プロセスの検索は下記コマンドを利用します。

ps ax

pythonのプロセスを探して、PIDを指定します。

kill -9 [該当のPID]

CentOS7日本語対応

CentOS7はそのままの設定だと言語が英語になっています。
チャットでは日本語を使うのですが、チャット内容に日本語を含む場合エラーが発生します。
エラーが起こらないよう、言語設定を変更していきます。

まずは、環境変数(LANG)を確認します。
LANG=C(英語)となっていると思います。

env

設定ファイルも確認しておきましょう。

less  /etc/locale.conf

次に、使える言語を確認します。
ja_JP.utf8があるか確認してください。

locale -a

最後に、下記コマンドで設定を書き換えます。

localectl set-locale LANG=ja_JP.utf8

これで日本語入力ができるようになりました。

失敗例

下記ファイル群を書き換えても意味がありません。
~/.bash_profile
~/.bashrc
~/.profile

下記コマンドもシェル上だけで有効で、systemd上のサービスにすると日本語にエラーが出ます。

export LANG=ja_JP.utf8

チャットアプリのsystemd上でのサービス化

それでは、デプロイのために色々と設定を行っていきましょう。

Gunicorn

gunicorn.conf.pyを下記の通りに作成します。

workers = 1
worker_class = 'eventlet'
bind = 'unix:/run/flask_chat.socket'

上記のファイルは、以下のようにコマンド上で利用します。

gunicorn run:application --config gunicorn.conf.py

worker_classは、eventletかgeventを指定します。
bindは、どこのポートまたはソケットで立ち上げるかを設定します。今回はソケットを使います。
workerについては、CPU1個あたりworkerを2~4個用意するのがいいようです。1個だとたまにチャットのメッセージが消えます。

CPU数を出力するには下記コードをpythonインタプリンタ上で使用してください。

import multiprocessing
print(multiprocessing.cpu_count())

serviceおよびsocketの準備

flask_chat.serviceflask_chat.socketを用意します。
※settings_envフォルダに入っているのでアップロードしていただいてもかまいません。

flask_chat.serviceの内容は下記の通りです。

[Unit]
Description=flask_chat daemon
Requires=flask_chat.socket
After=network.target

[Service]
User=root
Group=root
RuntimeDirectory=gunicorn
WorkingDirectory=/usr/share/nginx/app/flask_chat/
ExecStart=/usr/share/nginx/venv/flask_chat/bin/gunicorn --config /usr/share/nginx/app/flask_chat/gunicorn.conf.py run:application
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID
KillMode=mixed
PrivateTmp=true
Restart=always

[Install]
WantedBy=multi-user.target

注意すべき点は、ExecStartを仮想環境上のgunicornに指定することです。
venvを直接指定しなくても、勝手に良い感じに読み込みをしてくれます。

flask_chat.socketの内容は下記の通りです。

[Unit]
Description=flask_chat socket

[Socket]
ListenStream=/run/flask_chat.socket

[Install]
WantedBy=sockets.target

2つのファイルをアップロードして、下記コマンドで指定位置にコピーします。

cp flask_chat.service /etc/systemd/system/flask_chat.service
cp flask_chat.socket /etc/systemd/system/flask_chat.socket

サービス起動

下記コマンドでサービスを自動開始設定・開始します。

systemctl enable flask_chat.socket
systemctl start flask_chat.socket

※socketを起動すると、自動的にflask_chat.serviceが起動するのでコマンドは不要です。

最後に、動作確認を行います。

curl --unix-socket /run/flask_chat.socket localhost

エラーが出ずに、HTMLが返ってくれば設定は完了です。

Nginxの設定

Nginx Unit設定ファイル(/usr/share/nginx/conf.json)を下記の通りに変更します。
使わないので空にしましょう。

{
    "listeners": {
    },

    "applications": {
    }
}

設定を反映します。

sudo curl -X PUT --data-binary @/usr/share/nginx/conf.json --unix-socket /var/run/unit/control.sock http://localhost/config
systemctl restart unit

Nginx設定ファイル(/etc/nginx/conf.d/default.conf)のlocationを変更します。

location / {
    proxy_set_header Host $host;
    proxy_pass http://unix:/run/flask_chat.socket;
}

再起動させましょう。

systemctl restart nginx

公開(デプロイ)

上記の手続きが問題なければアプリが起動すると思います。
おつかれさまでした。

あとは、前回と同様にデータベース(flask_chat)を用意しておく必要がありますが、今回は説明を割愛します。

問題がなければ、下記のように別ブラウザおよび別IPからで滑らかなチャットを行えます。

socket通信で問題となる、ブラウザ上では通信確立が上手くできたかわからないについても、通信が確立されるまではチャットを表示しないようにしています。

おわりに

今回は、socket通信を使った滑らかなチャットが可能なアプリをデプロイまで持っていきました。

次回以降は、これまで全く考えられていなかったセキュリティ設定等を行っていきます。
アプリをデプロイしても、頻繁に落ちたり、個人情報が取られたり・・・可能性は十分あり得ます。
そのため、HTTPS(SSL)接続などの設定も行います。

この記事は、VPSで作るPythonでのWebアプリ運用環境の連載記事です。
次回以降は上記記事からご覧ください。

-Web制作, Python, SQL, VPS

執筆者:


comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

関連記事

[Meisyo]野手起用法設定の導入検討

コメントいただきました。 面白いなこれは・・・一人で開発してもいいもんじゃないですね。ありがたいです。 導入は時間が出来たらします!

no image

iPhoneアプリを開発してみよう

最近ずっとiPhoneアプリで遊んでて、 「なんか頭使うゲームないな?」と思い(”本質的には育成ゲー”が多すぎてゲンナリ) 「複数人でのRTS」があればな~と。 「他ゲーに文句 …

no image

[PHP]まとめ読みをPSRで改良する(3)

(2)の記事から「PDO」を使い、データの通信をオブジェクト化しました。 password_hashを使い、パスワード処理の暗号化も行いました。 PDOを導入する一番の理由は「mysql_query」 …

no image

PHPのコーディング規則、PSRを学ぶ(4)

PHPのコーディング規則、PSRを学ぶ(3)の続きです。 今回は実際にクラス名定義を自宅サーバーで試してみます。 1.「SplClassLoader.php」を手に入れる 「ダウンロード」または「直接 …

Flask-Babelを使って、Pythonアプリで多言語対応を行う

Pythonで多言語対応してみたいなーと思っていました。 思っていましたが、実際になかなか使うタイミングがない・・・。 今回自作ゲームでユーザー数の増加がみられ、かつ海外からのアクセスも複数確認できた …