バルーンポケモンが好きな人のブログ

つまらない はなしで あいてをねむらせるのが とくいだぞ

Djangoをgunicornとnginx使って公開するまでの手順

もう完全に備忘録です。

前提条件

djangoのインストールはできていて、ローカル内でアプリの立ち上げはできていることを前提とします。
つまり、以下のことができているという前提で進めます。

cd /home/<username>/myworkspace  # <username>は各々の設定に応じて適時変えてください
django-admin startproject myproject .
python manage.py runserver 0.0.0.0:8000

これで、localhost:8000にアクセスしてサーバが立ち上がっていることを確認できればOK。
とはいえ、djangoについてくるデプロイの機能はシングルスレッドだから大量のアクセスには対応できないし、セキュリティも強固じゃないしということで、公開する場合はgunicornやnginxが必要になってきます。

gunicornのインストール

今回、pipenvを使っていたので、それ前提で進めます。

pipenv install gunicorn

gunicorn経由でサーバを起動

gunicorn --bind 0.0.0.0:8000 myproject.wsgi:application

これで、localhost:8000にアクセスしてサーバが立ち上がっていることを確認できればOK。
外部のサーバを借りている場合は、IPアドレスをそのサーバに合わせてください。

nginxのインストールと連携

nginxをインストールし、これをgunicornと連携させます。

sudo apt install nginx

gunicornの自動起動設定

/etc/systemd/system/gunicorn_app.socket を作成し、以下を貼り付けます。

[Unit]
Description=gunicorn socket

[Socket]
ListenStream=/home/<username>/myworkspace/gunicorn.sock
SocketUser=<username>

[Install]
WantedBy=sockets.target

<username> は各々の設定に応じて適時変えてください。
gunicornでsockファイルを生成し、それをnginxで読み込むことで連携させています。
以下のようにして、/etc/systemd/system/gunicorn_app.service を作成してsystemctlコマンド登録を行います。これにより、gunicornが自動起動するようになります。

[Unit]
Description=Django app service.
Requires=gunicorn_app.socket
After=network.target

[Service]
User=<username>
Group=<groupname>

WorkingDirectory=/home/<username>/myworkspace
PIDFile = /home/<username>/myworkspace/gunicorn.pid

ExecStart=/home/<username>/.pyenv/shims/pipenv run gunicorn \
          --workers 3 \
          --pid /home/<username>/myworkspace/gunicorn.pid \
          --bind unix:/home/<username>/myworkspace/gunicorn.sock \
          myproject.wsgi:application

[Install]
WantedBy=multi-user.target

ファイルの作成が終わったら、gunicornを起動します。

sudo systemctl daemon-reload
sudo systemctl start gunicorn_app.service

/home/<username>/myworkspace/ にgunicorn.sockが生成されていることが確認できればOKです。
次に、このsockファイルをnginxと紐づます。

nginxとの連携

設定ファイルを作成します。hogehogeという名前は各自好きな名前をつけてあげてください。

sudo vim /etc/nginx/conf.d/hogehoge.conf

ファイルの中身は以下のようにします。

server {
  listen 80;
  server_name <server_name>;

 location / {
  proxy_pass http://unix:/home/<username>/myworkspace/gunicorn.sock;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header Host $http_host;
  proxy_redirect off;
  proxy_set_header X-Forwarded-Proto $scheme;
 }
}

proxyまわりの設定は以下の記事を見ると少しわかった気になれます。
一目見て完全理解の境地に至りたいですが、私の頭はそこまで優秀ではなかったようです。まあ、こういうのは経験を重ねていく中で理解が深まっていくものでしょう。

memo.willnet.in

www.fenet.jp

nginxの設定ファイルにミスがないかチェックします。こういうの便利ですね。

sudo nginx -t

nginxの再起動をします。

sudo systemctl reload nginx

適当なブラウザからアクセスできることが確認できればOKです。
なんか上手く動作しない場合は、以下のログファイルなどを見ると解決の糸口が見えてくるかもしれません。

sudo vim /var/log/nginx/error.log

ちなみに、同ディレクトリには access.log もあって、この中にはアクセス履歴が保存されています。

その他

私はさくらのVPSでサーバーを借りて環境を構築しました。管理画面から[パケットフィルタを設定]をクリックし、接続可能ポートの項で、80番ポートを開放することを忘れずにしておきましょう。

ロード時間の短縮も考慮してちゃんとデプロイする上では静的ファイルの処理も必要になります。

私はソフトウェアエンジニアを生業としてご飯を食べている人間ですが、webアプリの構築に明るい人間ではないので間違いであったり抜け漏れがあったりするかもしれません。その点についてはご了承願います。

参考URL

www.digitalocean.com

view-s.co.jp

Photonでマルチプレイを実装・事始め

動機

今までUnityで簡単なアプリを作ってはunity roomで公開してきましたが、一人用ではなくみんなで集まってゲームをしたりコミュニケーションをとれたりできるようなものを作りたいと思い、Unityでマルチプレイを実装してみました!

ちなみにこういうのを作ってました↓

unityroom.com

マルチプレイの実装に必要なエンジン

Photonを使います。Unityでマルチプレイを実装するなら、これが最有力候補に上がるみたいですね。
ネットでググってみても記事が多くヒットするのでこれを採用してみます。

というか、この記事が入門として素晴らしい出来です。これ無料で読んでいいんですか...?

zenn.dev

この記事では2Dのゲーム開発をテーマにチュートリアルが進んでいますが、私は3Dで作りたかったので、3Dの環境で開発をしています。
進め方に大きな差はほとんどないです。

ヒエラルキーのウィンドウ内で適当なEmpty Objectを作成し、以下のスクリプトをアタッチします。

// SampleScene.cs

using Photon.Pun;
using Photon.Realtime;
using UnityEngine;

// MonoBehaviourPunCallbacksを継承して、PUNのコールバックを受け取れるようにする
public class SampleScene : MonoBehaviourPunCallbacks
{
    private void Start() {
        // PhotonServerSettingsの設定内容を使ってマスターサーバーへ接続する
        PhotonNetwork.ConnectUsingSettings();
    }

    // マスターサーバーへの接続が成功した時に呼ばれるコールバック
    public override void OnConnectedToMaster() {
        // "Room"という名前のルームに参加する(ルームが存在しなければ作成して参加する)
        PhotonNetwork.JoinOrCreateRoom("Room", new RoomOptions(), TypedLobby.Default);
    }

    // ゲームサーバーへの接続が成功した時に呼ばれるコールバック
    public override void OnJoinedRoom() {
        // ランダムな座標に自身のアバター(ネットワークオブジェクト)を生成する
        var position = new Vector3(Random.Range(-3f, 3f), 5f, Random.Range(-3f, 3f));
        GameObject fixedMaleDummy = PhotonNetwork.Instantiate("FixedRobotKyle", position, Quaternion.identity);
    }
}

FixedRobotKyleは読み込んだPhotonの中に含まれているAssets/Photon/PhotonUnityNetworking/Demos/Shared Assets/Models/Robot Kyle.fbxをもとにprefabをコピーし、そこに以下のコンポーネントを追加したものになります。

  • Animator

個々のアニメーション(Idle状態やWalk状態等)はAssets/Photon/PhotonUnityNetworking/Demos/Shared Assets/Animationsにあるので、それを流用し、Controllerだけ自作しました。
単純にスピードによってIdleとWalkのアニメーションを切り替えるだけです。

f:id:slowsingle:20210808003936p:plain

  • Photon View
  • Photon Transform View
  • Photon Animator View

f:id:slowsingle:20210808003834p:plain

  • Rigidbody
  • Box Collider

RigidbodyのConstraintでX軸とZ軸中心の回転に制約を与えています。これで、キャラクター同士がぶつかった際に倒れてしまって身動きが取れなくなる、という問題を防ぐことができます。

f:id:slowsingle:20210808004305p:plain

最後にキャラクターを操作するためのControllerのスクリプトを作成してアタッチします。

// PlayerController.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;


public class PlayerController : MonoBehaviourPunCallbacks
{
    [SerializeField] private GameObject cameraObj;
    [SerializeField] private Animator animator;
    [SerializeField] private float speed;
    [SerializeField] private float rorationSpeed;

    private Vector3 moveVelocity;
 
    private void Start()
    {
        if (!photonView.IsMine)
        {
            cameraObj.SetActive(false);
        }

        moveVelocity = Vector3.zero;
    }

    private void Update()
    {
        if (photonView.IsMine)
        {
            float h = Input.GetAxis("Horizontal");
            float v = Input.GetAxis("Vertical");

            transform.Rotate(new Vector3 (0, rorationSpeed * h, 0));
            moveVelocity = speed * v * transform.forward;
            transform.position += moveVelocity * Time.deltaTime;

            animator.SetFloat("MoveSpeed", new Vector3(moveVelocity.x, 0, moveVelocity.z).magnitude * v);
        }
    }
}

マルチプレイなので当然キャラクターは複数いて、キャラクターの数だけカメラがあります。
どのキャラクターを操作するか、どのカメラを追従させるかを設定するために、Start関数で自分のキャラクターではないカメラを非アクティブにし、Update関数では自分のキャラクターの動きに対してのみキー入力による速度変化を適用させています。

カメラはこんな感じでキャラクターの中に同梱させています。

f:id:slowsingle:20210808005332p:plain

ビルドしてアプリを実行するともにUnity内でも起動し2パターンで起動すると、それぞれでキャラクターが生成されるので、フィールド上には以下のようにキャラクターが2人出現します。
それぞれの画面でキャラクターを操作すると、その位置や向き、アニメーションがもう片方のアプリにも反映されます。

f:id:slowsingle:20210808005856p:plain

楽しい!

Windowsでディープラーニングをするための環境構築手順

参考になったサイトをまとめます。
記事を書いてくださった皆様に大変感謝しています。

構築の大まかな流れを把握する

【2019年版】Windowsで始めるDeep Learning環境構築

CUDAを迎え入れるところまで目指してみます。
そこから先のPython環境の構築は別の記事を参照します。
わたしはTensorflowを入れたいので、ChainerやPytorchのインストールはスキップします。

Visual Studio 2019 のダウンロードとインストール

Visual Studioのダウンロード

無料で使えるコミュニティでOKです。
インストール時にC++Python環境のダウンロードもするようにチェックをつけておきましょう。

CUDAのインストール

その前にGeForce Experienceを起動して、ドライバをアップデートしました。
3年くらい放置気味だったので大丈夫か心配でしたが問題ありませんでした。
GeForce ExperienceはWindows画面の下のほうにあるメニューバーで検索すれば出てきます。

CUDA Toolkit 10.1 original Archive

わたしはCUDA10.1をダウンロードしました。
使いたいライブラリのバージョンで、ダウンロードすべきCUDAのバージョンも変わるかと思うのでここは気をつけてください。
Install Typeはexe(local)にしました。どっちでも大丈夫だと思います。

インストール手順は以下の通りです。下の記事では10.0のを解説しているため、少しバージョンは異なりますが、インストーラーの画面は大体同じなので十分参考になります。

CUDA Toolkit 10.0 インストール手順

Pythonの環境構築

Pythonのバージョンの管理のためにPyenvを、ライブラリの管理のためにPipenvを用いたいので、これらもインストールします。
とはいえ、まずはPythonが必要です。
実は遠い昔にPython3.8をインストールしていたので、Pythonのインストールはやっていないのですが、仮にここでPythonのインストールをするならば以下の手順を踏もうかと思っています。

  1. コマンドプロンプトを開いてPythonを実行してみます。Visual Studioのインストール時にPython開発環境も入っているはずなので、これで大丈夫なのかどうか確認します。Pythonのバージョンも確認して、低すぎなければOKかなと思っています。
  2. 1.でなんかダメそうだなとかもやもやする何かを感じたならば公式サイトからインストールしましょう。

Windows 10 で Python のインストールから Poetry と pyenv の利用

Poetryを使う手もあるみたいです。
ちなみに、普通にインストールしたPythonとPyenv経由でインストールしたPythonが共存しているとき、コマンドプロンプト等でPythonを実行すると、環境変数のリストの上から順にみて、先にヒットしたPythonが呼ばれるようになっています。
あと、Windowsだとpyenv-winが入るようですね。

環境変数まわりのお話は以下が参考になります。

Windows 10 で pyenv + pipenv の環境で Pythonを使いたい

pyenv-winを入れる→pipenvを入れる、までができたら、仮想環境を作ります。
ここまで終わればようやくTensorflowをインストールする作業に入れます。

(Optional)CUDNNのインストール

説明が雑ですが、CUDNNをインストールするとGPUの演算が速くなります。
あとはTensorflowを動かす際にCUDNNがないよって警告が出ます。なくても動くんですが、毎回警告が表示されるのもなんだか癪にさわるので、この際に入れてしまいましょう。

CUDA+cuDNNのインストールまとめ cuDNN Archive

色々バージョンがあってどれにすべきか困ってしまいますが、使いたいライブラリ(Tensorflow, Pytorch)のバージョンとCUDAのバージョンが決まっていればCUDNNのバージョンも決まります。
インストールしたいバージョンとセットでインストール手順を書いている記事を探せば、自ずとインストールすべきCUDNNのバージョンもわかります。
また、CUDNNなしでライブラリを使うと警告文が出るので、その文からどのバージョンのCUDNNが必要なのかという手がかりを得られます。そこから探してみるのもありです。CUDNNのインストール自体は後回しにしても問題ありませんし。

Tensorflowのインストール

pip での TensorFlow のインストール

今回はpipではなく、pipenvで入れます。
わたしは何となく2.3にしました。

pipenv install tensorflow-gpu==2.3.0

特にエラーが出ていなければインストール成功だと思います。
公式サイトにもあるインストールの検証を試してエラーが出ていなければOKです。
CUDNNのインストールをしていないのであれば警告が出ます。わたしは最初、CUDNNをインストールしないで実行していたので、警告文とこんにちはしました。

...毎回警告と遭遇しなきゃいけないなんて、なんだかもやっとしませんか? わたしはしました。(なのでこの後にCUDNNをインストールしました)

にんじんジュース

にんじんジュース、好きなんです。
野菜ジュース系だとにんじん以外の野菜も含まれてるので、にんじん本来の味を感じたく、以下のを購入しました。


りんご成分の入ったにんじんジュースとセットになっている商品です。飲み比べができますね!
これを飲んでいるときだけはにんじんは野菜じゃなくて果物なんじゃないかと錯覚してしまいます。それくらいに甘いです。
かぼちゃも僕の中では果物枠です。あれは野菜じゃない。

トマトジュースとかもフルーツトマトなるものが存在しているのだから、甘くて美味しいジュースがあるのだろうと思ってはいますが...
市販のトマトジュースは飲めず、鶏肉と一緒に煮込むスープとして活用するのがオチになるので、通販で少しお高めのジュースを買ってみるかどうかは未だに検討中のまま。

もくもく会

初めてもくもく会を開催する立場になりました。内容はプログラミング関連です。言語や技術は特に問いませんでした。
人集めはconnpassで行いました。以下のグループで開催してるので興味がある人がいればぜひ参加していただけると嬉しいです。
月一のペースでやりたいと思っています。

tachikawa-otonamuke.connpass.com

とりあえず6月上旬に第2回を開催しようと模索しています。

このような交流会を通じて、私のUnity勉強がもっと捗るといいなあ。
あと、技術仲間が増えるといいなと思っています。

イラストを描く

メディバンペイントで絵を描き始めました。

数年前にiPadを購入し、特に意味もなくApple Pencilも購入したのですが、当時はまったく使わなかったのでペンシルのほうはメルカリで売りました。
それをさらに安値で買い戻し、絵を描き始めた次第です。

私が絵を描き始めた理由はScratchで作りたい作品において、自分のイメージに合う絵を用意したかったからです。
ScratchはGUIのプログラミングツールです。作成したプログラムは他の人にもアクセスしてもらえるよう共有することができるのですが、プログラム内の素材も含めて再配布可能な形式で共有する仕様になっているため、巷にあふれるフリー素材が使えない...なんてことが頻発します。
例えば、いらすとやの素材は使えないんです。

www.irasutoya.com

公式でダメと言われちゃあ、私は手も足も出ませんね。

というわけで、ついに私は再びApple Pencilを握る決意をしたわけです。メルカリで買い戻してね!

Ain't No Magic

自分で色々描いてみて、とりあえず作品として仕上げたのが、このAin't No Magicになります。

f:id:slowsingle:20210511020935p:plain

絵の技術は発展途上です。そこは温かい目で見ていただければと思います。これからも発展し続けるかは私のやる気次第です。
一応、タイトルの「Ain't No Magic(魔法じゃない)」の意味もちゃんと作品に込めていますが、びっくりするほどこの作品に注目が集まらなかったのできっとその意味を理解して何か感じてくれる人が現れることはおそらくないのでしょう。

人を惹きつける何かを作るって難しいですねぇ...

十数年ぶりのしそジュース

私、いま社会人なのですが、小学生だったころはおばあちゃん子だったので、週末はよくおばあちゃんの家に遊びに行っていました。

おばあちゃんがよく作ってくれた飲み物に「しそジュース」がありました。
美味しいんですよ、これが。
いまは地元を離れているのもあってなかなかおばあちゃんの家には行けないというのもあり、久しぶりにしそジュースが飲みたいなと思ってもなかなか叶わないので、ちょっと楽天で買ってみることにしました。


飲んでみると、ちょっと味が違うんですよ。
私の知ってるしそジュースじゃないな、と。
決して味が悪いわけではなく、ちゃんとしその風味も感じられるのですが、思い出とは違うんです。

原因はこのしそジュースが無糖だからなんですね。
私の記憶にあるしそジュースはたしか、砂糖がたくさん入っていて、それですごく甘みを感じられるのですが、無糖の場合は甘みがありません。
野菜本来の甘み、といってもしそなので、無糖だと全然甘くないです。渋みが強いです。

なので、甘いほうが良いという場合はこっちのほうがおすすめですね。


無糖のしそジュースはそのまま飲んだり、水やソーダで割る、というよりかは他の甘い飲み物と割って飲むとより楽しめるんじゃないかと思います。

ということで、色々割って飲んでみました!

コカ・コーラ

配合は、しそジュース:コカ・コーラ=1:3
一番美味しい。しその渋さとコーラの甘さがすごく合いますね。

カルピス

配合は、しそジュース:カルピス=1:3
これも美味しいですね。カルピスの甘みが抑えられることによって、酸味がより引き立つ味わいでした。

ジンジャーエール

配合は、しそジュース:ジンジャーエール=1:3
これはそんなにかな、という感じでした。ジンジャーエール単体のほうが美味しいですね。
甘い飲み物との相性は良いんですが、ジンジャーエールのように甘み以外に、苦みのような味わいがあるとそっちが引き立ってしまうのはあります。

午後の紅茶レモン味

配合は、しそジュース:午後の紅茶=1:3
これもジンジャーエールの場合と同じですね。紅茶の持つ渋みが強調される(甘みが抑えられる?)ので少し飲みにくくなったかも。

オランジー

配合は、しそジュース:オランジーナ=1:3
オレンジは裏切らないですね。

牛乳

配合は、しそジュース:牛乳=1:4
牛乳も合うなんて記事があったから飲んでみたけど、僕はちょっと飲めないですね。。。
健康食品なんだと思えば行けます。リピートはしないけど。

総評?

コカ・コーラとオランジーナは合う。それ以外は気が向いたら。
牛乳はダメ。砂糖とか追加すれば行けるのかもしれませんけどね。
調味料を色々追加して飲むのは手間がかかって面倒なので、たぶん私はやらないですね(笑)