【Django】Heroku無料枠がなくなるのでRenderを使ってみた。

※ 当サイトではアフィリエイト広告を利用しています。リンクは広告リンクも含みます。

この記事は約20分で読めます。
広告

Herokuが2022/11/末から有料になるため代わりになるRenderを使ってみました。どうにかデプロイできたので、その様子をご紹介します。Herokuで動いていたものを動かすことができました。HerokuやRailwayとは違ってアプリによってはアプリ自体の修正が必要になりました。まずはAnacondaで作ったDjangoアプリをRenderにデプロイしたときにハマったことと解決策のご紹介。それとHerokuで動いていたものをRenderにデプロイしたときにハマった内容のご紹介です。
Renderの登録方法などは省略しています。
半年程度使った2023/4/23の状況は、無料では立ち上がりがすごく遅い。データ保存ができない(最初の90日は保存できた)という運用しています。有料にしないと、この辺は改善できないと思います。

使用した環境Windows11、Anaconda、Git、VSCode

2023/02/17以下のメールが来ました。90日たったのでデータベースにアクセスできなくなりました。
Your free Render PostgreSQL database, django_render_db, will be suspended on 2023-02-17. The database will become inaccessible unless you upgrade to a paid plan.
PostgreSQLではなくsqlite3使っているから大丈夫だと思っていたのですが、データが保存されなくなっていたりエラーが出たりしています。1番下にPostgress→SQLite3の記事追記しました。

Renderにデプロイしたアプリ
Django+Vuetify掲示板 (表示するまで数分かかることがあります)
データ入力グラフ描画(表示するまで数分かかることがあります)

Render無料が遅い理由は、こちら↓↓

おすすめ!
Renderで1番簡単なアプリをデプロイする手順です。Render公式をベースにやっていきます。

私の他のDjangoの記事でも成果物はRailwayとRenderにそれぞれデプロイしています。
同じくHerokuの代替Railwayについてはこちらの記事。

AnacondaでDjangoアプリを作る場合、エディタはVSCodeを使ったほうがいいです。というのはRender.comを使うときに作るbuild.shファイルの改行コードがLFでなければエラーになりVSCodeだとこの変換が簡単にできます。(Spyderを使ってもできると思いますが、やり方は調べてません。)

イチゲブログ掲示板(csvをシン・クラウド for Free保存)(表示するまで数分かかることがあります)

広告

Renderにデプロイ

Renderにデプロイする方法はこちらを参考にしました。
参考サイトDjangoをRenderにデプロイする方法
Anacondaをインストールしていない環境では、この通りいけると思います。
私はデプロイの前の仮想環境でつまづきました。というのもAnacondaをインストールしているとうまくいきません。
Anacondaをアンインストールしたくなかったので上述のAnaconda仮想環境で、参考サイトのアプリを作りデプロイしました。参考サイトと違う部分を記述します。

Anacondaの場合、上の「Environments」→「該当の仮想環境」→「Open Terminal」でこのターミナルを使っていきます。
この状態で参考サイトの「仮想環境の作成」と「仮想環境の実行」は不要になります。

python3 manage~ではエラーになるのでpython manageでやりました。
例えばpython manage.py startapp app

RenderのNew Blueprint Instance ボタンをクリックしたときレポジトリがないときはConfigure accountをクリックRepository accessがOnly select repositoriesになっているためこうなります。select  repositoriesでレポジトリが選べるようになります。

デプロイでCreate web service django_render
(git branch not found: "main" in https://api.github.com/repos/miyamiko/mysite/commits/main)とエラーが出たので
render.yamlのservices:の branch: main →master変更でOKでした。(masterだったのは私がGitHubにプッシュするときgit push origin masterでプッシュしたからです。)
目次へ

Heroku、Railwayでうまくいっていたのにエラーが出たこと

Heroku、Railwayで動いていたアプリをRenderにデプロイするときにはまったことです。

/usr/bin/env: ‘bash\r’: No such file or directoryが出る

/usr/bin/env: ‘bash\r’: No such file or directoryが出たときの対処法を参考に
VSCodeでbuild.shを開いて改行をlfに変えてok
VSCodeで*.shでファイルを新規作成したときは自動的に改行コードがLFになっているので何もする必要はありません。

Not Found: /

ルートに何かを表示する処理がないとデプロイ失敗になります。
なので処理を追加、具体的にはプロジェクトのほうのurls.pyにルートの表示処理を追加する。

urlpatterns = [
    path('',~)←これがないとデプロイ失敗になる。

これはsettingsのHealth Check Pathに/が設定されている。その説明をみるとRenderのHealth Checkが/にリクエストしたとき200 OKのレスポンスが返ってこないとエラーになるみたい。

app.models.モデル名.DoesNotExist: モデル名matching query does not exist.

デプロイ完了後いきなりアプリが立ち上がりデータオブジェクトがない処理だとデプロイ失敗になってしまう。Herokuでは起動する前にPythonシェル起動やadminを起動してデータオブジェクトを作成できたので、デプロイ失敗にはならなかった。
get_or_create()を使うと最初の1回だけオブジェクトを作成する処理を作れる。
参考【django】モデルの get_or_create()の使い方

sqlite3を使う場合だったらローカルでデータ入力しておけばデプロイしても、そのまま使える。ただデータベースのデータはdb.sqlite3にはいっている。なので.gitignoreでdb.sqlite3を書いてるとGitHubにdb.sqlite3がプッシュされないので消しましょう。

relation “モデル名” does not exist

adminでモデルをクリックしたときやapiでモデルにアクセスしようとすると出る。migrateがうまくいってないようです。
具体例
relation “article_vtfyarticle” does not exist(articleはアプリ名_vtfyarticleはモデル名)

解決策

build.shの
python manage.py migrate
→
python manage.py migrate --fake article zero
python manage.py migrate article
articleはアプリ名
デプロイ時のログでarticle.0001_initialが適用されているのが確認できました。
Jan 5 07:16:26 AM    Apply all migrations: article
Jan 5 07:16:26 AM  Running migrations:
Jan 5 07:16:26 AM    Applying article.0001_initial... OK

参考
postgresql – django.db.utils.ProgrammingError: relation “bot_trade” does not exist – Stack Overflow

djangorestframework==3.10.0だとエラー

何かimportできないエラーが出た。(具体的には忘れました)
Djangoのバージョンとの関係だと思いますがrequirements.txtでバージョン指定しないでdjangorestframeworkとすればデプロイは通る。
また参考サイトではrequirements.txtでdjango==4.1.2にしてRenderのEnviroment環境変数設定でPYTHON_VERSION 3.8.10に変更しています。最初からrequirements.txtで3.8.10にしてみましたが、これではヴァージョンがないというエラーになりました。なので参考サイトの手順でやらないとダメでした。

細かいところまでチェックされダメだとデプロイ失敗になる。

HerokuやRailwayではチェックされないところまでチェックされます。やっかいなのはデプロイ失敗として扱われて先に進めないところです。

具体的に出たエラーは
The JS file 'app_cal/js/chunk-vendors.17cbe1d3.js' references a file which could not be found:
Nov 23 05:51:19 PM    app_cal/js/chunk-vendors.17cbe1d3.js.map
mapファイル(デバックで使う)がないというエラー

jsファイルの以下の該当部分を削除したらOKでした。
//# sourceMappingURL=app.e34c0f45.js.map

プロジェクトが違っても同じモデル名やアプリ名だと動作がおかしい

HerokuやRailwayでは問題なかったのに別プロジェクトの同じモデル名やアプリ名だと干渉してしまう。アプリを作り直した。

5秒ごとに”GET / HTTP/1.1″ 200 10831 “-” “kube-probe//”が発生する

プログラムによっては問題になるので注意です。Renderが5秒おきにアクセスしてヘルスチェック(ちゃんと動いてるか)してるようです。私はアクセスカウンターのアプリで、これによりうまくカウントできなくなりました。

追記:上に記述してある「Not Found: /」が原因。以下、最初に書いた文章を残しておきます。
ヘルスチェックはdashboardのsettingsでHealth Check Pathに/が入っていたので、
空欄にしたらヘルスチェックしなくなりました。

views.pyにprint(request.headers)をおいて、どんなrequestが来てるか見ようとしましたが何も入ってません。またチェックしてるのはルートのアプリだけのようで他のところのアプリのアクセスカウンタでは不具合はおきません。なのでurls.pyでルートから変えてみたけどダメでした。最初にルートのアプリに設定したらそれについてくるのか?個人的対策として、ヘルスチェックを受けたくないアプリは最初のデプロイでルートにおかないようにしようと思います。
HerokuやRailwayでは起きていなかったのに。うまくいかなくなったアプリの記事

502 Bad Gateway

logでは最初デプロイ成功になっているがGET / HTTP/1.1″ 400が連発して最終的にはdeploy failedになる。
settings.py
私の最初の設定ALLOWED_HOSTS = [‘.onrender.com’,’localhost-abc-1.paiza-user-free.cloud’, ‘.herokuapp.com’]をALLOWED_HOSTS = [‘*’]にしたらとりあえずデプロイは成功してアプリも表示する。すべてを表す*ではちょっと心配なので[‘.onrender.com’]を試したけどダメ。サブドメインつきの[‘vtfy2article.onrender.com’]でもダメでした。他のアプリは問題なかったのになぜ?
Delete Web Serviceしてやり直したり、デプロイするときハイライトされてないほうのボタンでやったり、
いろいろやっているうちにログに以下が出てきたので ‘127.0.0.1’ をALLOWED_HOSTS に追加しました。
Invalid HTTP_HOST header: ‘127.0.0.1:10000’. You may need to add ‘127.0.0.1’ to ALLOWED_HOSTS.
最終的にはこれでOKになりました。
ALLOWED_HOSTS = [‘vtfy2article2.onrender.com’,’127.0.0.1′]
‘127.0.0.1’はlocalhostと同じ。ループバックアドレスといって自分自身をさすIPみたいです。そういえばローカルでやるときは、ここにアクセスしますね。

Worker (pid:561) was sent SIGKILL! Perhaps out of memory?

たまにServer unhealthyになっていてlogを見ると上のエラーが出て動かないときがあった。
直前にMatplotlib is building the font cache; this may take a moment.があるので
matplotlibがメモリを使いすぎていたみたいでエラーになる。
下の2行を意味も分からず入れていたがなくても動いたので、削除して様子を見ます。

# import matplotlib←コメントアウトした
#バックエンドを指定
# matplotlib.use('Agg')←コメントアウトした
import matplotlib.pyplot as plt

Postgressに変更する方法

SQLiteからPostgressへ変更する方法。簡単にできるので本当にPostgressで動いているのか確認の仕方がわかりませんがエラーにはなりませんでした。

settings.pyで以下のように変更する
import dj_database_url
# DATABASES = {
    # "default": config("DATABASE_URL", default=default_dburl, cast=dburl),
# }
DATABASES = {"default": dj_database_url.config()}
必要に応じて(私はよくわかっていません。書かなくても動きました。)config()の中にconn_max_ageを書くみたいです。
例conn_max_age=600

参考
https://render.com/docs/deploy-django
https://django.baby/deploy-django-to-render-com/
https://github.com/yeconnect/deploy_django_on_render/blob/main/config/settings.py

目次へ

Postgress→SQLite3

SQLite3で動いているとばかり思っていたらPostgressで動いていたようです。3カ月でPostgressの期限切れでアプリが動かなくなりました。
原因は後述。PostgressからSQLite3に変更してデプロイだけは成功したので紹介します。ただし、データの読み書きはできますが再度立ち上げた時データが保存されていない。
私の作ったDjango+Vuetify掲示板 (表示するまで数分かかることがあります)で確認したところ約15分後に再アクセスすると初期状態に戻りました。
db.sqlite3が更新保存されていないようです。(原因は後述)

git clone https://github.com/****/****.git
cd ****
code .
render.yamlの以下削除
databases:
  - name: django_render_db
    region: singapore
    plan: free
    databaseName: django_render_db
    user: django_user

以下は恐らくPostgressの設定がされていればPostgressを使って、されていないときは、SQLite3を使うというコードだったと思われます。これをSQLite3を使うと明示しました。(Djangoに最初から入っているコードに戻した。)

settings.pyでDATABASE変更
# DATABASES = {
#     "default": config("DATABASE_URL", default=default_dburl, cast=dburl),
# }
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}
git status
git add .
git commit -m "sqlite3に変更"
git push origin master

RenderのDashboadで該当するアプリを選択Manual Deploy→Deploy latest commit

SQlite3で最初から動かす場合

今、私が運用しているこの方法だとローカルで作ったdb.sqlite3のまま更新保存されません。(原因は後述)ただシンプルに運用できるので紹介しておきます。

ローカルで以下をやっておきます。
python manage.py makemigrations (migrationフォルダができないときは最後にアプリ名入れるとmigrationフォルダできる)
python manage.py migrate
migrateやpython manage.py createsuperuser
アプリを動かしてデータベース(db.sqlite3)にデータを入れておく。

build.sh
set -o errexit

pip install -r requirements.txt

python manage.py collectstatic --no-input

render.yamlのstartCommand:はgunicorn (wsgi.pyのあるディレクトリ).wsgi:applicationの形です。またRenderの各アプリのsettingsのStart Commandにも同じものを入力します。
Start Commandについてはこちら↓も参考にしてください。

render.yaml
services:
  - type: web
    name: アプリ名 例vchartren2
    env: python
    region: singapore
    buildCommand: './build.sh'
    startCommand: 'gunicorn project_vchart2.wsgi:application'
    plan: free
    branch: main
    healthCheckPath: /
    envVars:
      - key: DATABASE_URL
        fromDatabase:
          name: django_render_db
          property: connectionString
      - key: SECRET_KEY
        generateValue: true
      - key: WEB_CONCURRENCY
        value: 4
    autoDeploy: true

Superuserコマンドは使用せず、ローカルで作っておきます。なのでsettings.pyもSuperuser関連やデータベースのPosgress関連の処理はなくしました。

settings.py
from pathlib import Path
import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
# BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
BASE_DIR = Path(__file__).resolve().parent.parent
略
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}
略
# STATIC_URL = '/static/'
STATIC_URL = "static/"
STATIC_ROOT = str(BASE_DIR / "staticfiles")
STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"

DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"

GitHubにデプロイしたらブループリントではなくDashboadからNew→WebService→WebConfigure accountをクリック(Repository accessがOnly select repositoriesになっているためこの作業が必要になる。)select  repositoriesでレポジトリが選べるようになります。選んでConect。環境変数設定はPYTHON_VERSION 3.8.10のみでSuperuserはやらない。

SQlite3の件でデータベースがなんだかわかった

SQlite3はdb.sqlite3ファイルにデータを保存している。今回の原因は、データを更新したdb.sqlite3ファイルが保存されないことが原因でした。
基本的にRailwayやRenderでは変更したファイルは保存できない。
なぜRailwayとRenderで動きが違うかと言うと、アクセスしたときの立ち上がり時間からもわかる。Railwayはデプロイしたあとは、ずっとdb.sqlite3ファイルが使われていてスリープしない状態(20日間)なのでデータ変更ができる。ローカル環境と同じ状況。なのでアクセスしたときの反応は速いしデータベースSQlite3のデータも残っている。
Renderはデプロイ後、スリープ状態になって立ち上がるたびにデプロイ時と同じ動作をしてdb.sqlite3ファイルがデフォルトに戻ってしまう。なので立ち上がりに30秒以上かかったり、データが初期値に戻る現象が起きる。
処理を作り直してcsvファイルでデータを保存できそうだが多分できない。こちらはStreamlit Cloudで使ったpandasとcsvを利用した掲示板です。詳細は以下記事

この掲示板に投稿したデータはスリープ状態からの復帰で初期値に戻る。なのでRenderで同じようにcsvでデータ保存する処理に変更しても結局sqlite3使っているときと同じ状況で使えないと思う。
こちらのPHP・MySQLで作ってXfreeにおいた掲示板は2021年のデータがずっと残っている。PHPを勉強するとDjangoのsettings.pyとかでやってるデータベースの謎処理の理解につながる感じがします。
詳細は以下

ということでRailwayやRenderでは有料のPostgreSQLなどを使わないと、ちゃんとしたデータ保存する運用はできないっぽい。

この記事を書いたイチゲを応援する
Vプリカでのお支払いがおすすめです。

まとめ

気づいたことがあったら随時更新します。

  • HerokuやRailwayではハマらなかった内容でハマった。
  • アプリが異なっていても同じデータベースのモデル名を使っていると干渉してしまいアプリを作り直した。
  • 5秒おきに実行されるへルスチェック(ちゃんと動いてるか)も動作に影響がある。
  • スリープ状態から立ち上がるまで数分かかるときがある
  • BlueprintsのstatusがSync failed(原因未調査)でもとりあえず動く。今はBlueprintsを削除して使っている。
  • ローカルでうまくいっていたページネーションがうまくいかない。(原因未調査)
  • 3か月後Postgressが使えなくなる。SQLite3に変えるがデータが残ってない。
    スリープするとSQLite3のデータはGitHubにpushしたときの状態に戻る。

この記事を書いたイチゲを応援する
Vプリカでのお支払いがおすすめです。
MENTAやってます(ichige)
目次へ

コメント