バックエンドサーバの準備
クライアント側
本番運用環境用 Django プロジェクト設定ファイル
src/backend/config/settings/production.py
from django.core.exceptions import ImproperlyConfigured
from .base import *
import os
# 本番では DJANGO_SECRET_KEY を必須とする(未設定なら起動時に例外で落とす)。
try:
SECRET_KEY = os.environ['DJANGO_SECRET_KEY']
except KeyError as exc:
raise ImproperlyConfigured(
'DJANGO_SECRET_KEY environment variable must be set in production.'
) from exc
SIMPLE_JWT = {**SIMPLE_JWT, 'SIGNING_KEY': os.environ.get('JWT_SIGNING_KEY', SECRET_KEY)}
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'recsys_full',
'USER': os.environ.get('DB_USER'),
'PASSWORD': os.environ.get('DB_PASSWORD'),
'HOST': '',
'PORT': '',
}
}
DEBUG = False
ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', '').split(',')
CORS_ALLOWED_ORIGINS = os.environ.get("CORS_ALLOWED_ORIGINS", "").split(",")
CORS_ALLOW_CREDENTIALS = True
CSRF_TRUSTED_ORIGINS = os.environ.get("CSRF_TRUSTED_ORIGINS", "").split(",")
BACKEND_BASE_URL = os.environ.get("BASE_URL", "").split(",")
OMDB_API_BASE_URL = os.environ.get('OMDB_API_BASE_URL', 'https://www.omdbapi.com/')
OMDB_API_KEY = os.environ.get('OMDB_API_KEY')
STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'static'
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
# ロガーの設定
'loggers': {
# Djangoが利用するロガー
'django': {
'handlers': ['file'],
'level': 'INFO',
},
# onlineアプリケーションが利用するロガー
'online': {
'handlers': ['file'],
'level': 'INFO',
},
},
# ハンドラの設定
'handlers': {
'file': {
'level': 'INFO',
'class': 'logging.handlers.TimedRotatingFileHandler',
'filename': os.path.join(BASE_DIR, 'logs/django.log'),
'formatter': 'prod',
'when': 'D', # ログローテーション(新しいファイルへの切り替え)間隔の単位(D=日)
'interval': 1, # ログローテーション間隔(1日単位)
'backupCount': 7, # 保存しておくログファイル数
},
},
# フォーマッタの設定
'formatters': {
'prod': {
'format': '\t'.join([
'%(asctime)s',
'[%(levelname)s]',
'%(pathname)s(Line:%(lineno)d)',
'%(message)s',
])
},
},
}
src/backend/config/wsgi.py
...(略)...
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings.production') # <- .productionを追加
application = get_wsgi_application()
src/backend/config/asgi.py
...(略)...
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings.production') # <- .productionを追加
application = get_asgi_application()
インストール済みパッケージ一覧の出力
(recsys_full) $
cd ~/dev/recsys-full/
pip freeze > requirements.txt
(recsys_full) $ vi requirements.txt
requirements.txtの下記の行をコメントアウトする。
...(略)...
# torch==2.13.0
# torchaudio==2.11.0
# torchvision==0.28.0
...(略)...
データの初期化
offline$ cp bkup/data/* data/
リポジトリのプッシュ
$
cd ~/dev/recsys-full/
git add *
git add .*
git commit -m "deploy backend"
git push
git status
バックエンドサーバ側
リポジトリの clone
rsl@*:$ mkdir ~/dev/
rsl@*:$ cd ~/dev/
rsl@*:$ git clone git@github.com:recsyslab/recsys-full.git
rsl@*:$ cd recsys-full/
rsl@*:$ ls
README.md requirements.txt src
パッケージのインストール
rsl@*:$
python3.12 -m venv ~/venv/recsys_full
source ~/venv/recsys_full/bin/activate
(recsys_full) rsl@*:$
pip install --upgrade pip
pip --version
pip 26.2.1 from /home/rsl/venv/recsys_full/lib/python3.12/site-packages/pip (python 3.12)
(recsys_full) rsl@*:$
pip install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu124
pip install -r ~/dev/recsys-full/requirements.txt
pip install gunicorn
(recsys_full) rsl@*:$ pip freeze
...(略)...
gunicorn==26.2.0
...(略)...
torch==2.13.0
torchaudio==2.11.0
torchvision==0.28.0
...(略)...
ログ出力先ディレクトリの作成
rsl@*:backend$
mkdir logs/
mkdir media/
mkdir static/
rsl@*:backend$ ls
api config logs manage.py media static
環境変数の設定
(recsys_full) rsl@*:backend$
python -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"
<DJANGO_SECRET_KEY>
rsl@*:$ sudo vi ~/.profile
~/.profile
- フロントエンドサーバのURLが
https://recsys-full.vercel.appであるとする。
...(略)...
# Django用環境変数
export DB_USER=rsl
export DB_PASSWORD=<DB_PASSWORD>
export DJANGO_SETTINGS_MODULE=config.settings.production
export DJANGO_SECRET_KEY='<DJANGO_SECRET_KEY>'
export ENCRYPTION_KEY=<FERNET_KEY>
export ALLOWED_HOSTS=recsys-full.vercel.app,recsys-full.recsyslab.org,***.***.***.*** # <- ***.***.***.***はバックエンドサーバのIPアドレス
export CORS_ALLOWED_ORIGINS=https://recsys-full.vercel.app,https://recsys-full.recsyslab.org
export CSRF_TRUSTED_ORIGINS=https://recsys-full.vercel.app,https://recsys-full.recsyslab.org
export OMDB_API_KEY=<OMDB_API_KEY>
rsl@*:$
less ~/.profile
diff ~/.profile-org ~/.profile
source ~/.profile
env
データベース環境の構築
postgres=# CREATE ROLE rsl WITH LOGIN PASSWORD 'rsl-pass';
postgres=# CREATE DATABASE recsys_full ENCODING 'UTF8';
postgres=# ALTER DATABASE recsys_full OWNER TO rsl;
postgres=# \l
postgres=# \c recsys_full
recsys_full=# CREATE EXTENSION IF NOT EXISTS pg_trgm;
マイグレーションの実行
(recsys_full) rsl@*:backend$ python manage.py makemigrations accounts
Migrations for 'accounts':
api/accounts/migrations/0001_initial.py
+ Create model CustomUser
(recsys_full) rsl@*:backend$ python manage.py makemigrations online
Migrations for 'online':
api/online/migrations/0001_initial.py
+ Create model Genre
+ Create model User
+ Create model Movie
+ Create model MovieGenre
+ Create model ReclistMovieSimilarity
+ Create model ReclistPopularity
+ Create model ReclistBPR
+ Create model UserMovieRating
(recsys_full) rsl@*:backend$ python manage.py migrate
Operations to perform:
Apply all migrations: accounts, admin, auth, contenttypes, online, sessions, token_blacklist
Running migrations:
Applying online.0001_initial... OK
Applying contenttypes.0001_initial... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0001_initial... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying auth.0012_alter_user_first_name_max_length... OK
Applying accounts.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying sessions.0001_initial... OK
Applying token_blacklist.0001_initial... OK
Applying token_blacklist.0002_outstandingtoken_jti_hex... OK
Applying token_blacklist.0003_auto_20171017_2007... OK
Applying token_blacklist.0004_auto_20171017_2013... OK
Applying token_blacklist.0005_remove_outstandingtoken_jti... OK
Applying token_blacklist.0006_auto_20171017_2113... OK
Applying token_blacklist.0007_auto_20171017_2214... OK
Applying token_blacklist.0008_migrate_to_bigautofield... OK
Applying token_blacklist.0010_fix_migrate_to_bigautofield... OK
Applying token_blacklist.0011_linearizes_history... OK
Applying token_blacklist.0012_alter_outstandingtoken_user... OK
Applying token_blacklist.0013_alter_blacklistedtoken_options_and_more... OK
データの登録
rsl@*:offline$
psql recsys_full -U postgres -c "\copy m_movies (movie_id, title, year, imdb_id, tmdb_id) from 'data/movies.csv' with delimiter E'\t' csv header encoding 'UTF8'"
psql recsys_full -U postgres -c "\copy m_genres (genre_id, genre_name) from 'data/genres.csv' with delimiter E'\t' csv header encoding 'UTF8'"
psql recsys_full -U postgres -c "\copy m_movies_genres (id, movie_id, genre_id) from 'data/movies_genres.csv' with delimiter E'\t' csv header encoding 'UTF8'"
psql recsys_full -U postgres -c "\copy t_users (user_id, email_encrypted, email_hash) from 'data/users.csv' with delimiter E'\t' csv header encoding 'UTF8'"
psql recsys_full -U postgres -c "\copy t_users_movies_rating (id, user_id, movie_id, rating, rated_at) from 'data/ratings.csv' with delimiter E'\t' csv header encoding 'UTF8'"
psql recsys_full -U postgres -c "\copy r_reclist_popularity (id, target_genre_id, rank, movie_id, score) from 'data/reclist_popularity.csv' with delimiter E'\t' csv header encoding 'UTF8'"
psql recsys_full -U postgres -c "\copy r_reclist_movie_similarity (id, base_movie_id, rank, movie_id, score) from 'data/reclist_movie_similarity.csv' with delimiter E'\t' csv header encoding 'UTF8'"
psql recsys_full -U postgres -c "\copy r_reclist_bpr (id, user_id, movie_id, score, rank) from 'data/reclist_bpr.csv' with delimiter E'\t' csv header encoding 'UTF8'"