6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Django+MySQL+Dockerの環境をHerokuにデプロイする

Last updated at Posted at 2022-04-22

一年ぶりにHerokuを触ってみたのですが、ほとんど忘れていました。

また、HerokuでDjangoの環境構築を行う上で、リソースが少なかったので同じ境遇の方の助けになれればと思います。

Herokuでは便利なことにDockerのイメージをそのままデプロイ出来るようになったそうです。

これが無料で出来るとはSalceforceさんも太っ腹ですね。

前置きはさておき早速説明を始めますね。

環境

# 実行環境
macOS: Monterey(12.3.1)
shell: zsh 5.8(x86_64-apple-darwin21.0)
Python: 3.9.7
Docker: 20.10.8
docker-compose: 1.29.2

# 主要ライブラリ
django-heroku==0.3.1
django-mysql==4.7.0
django==4.0.5
djangorestframework==3.13.1
guicorn==20.1.0
urllib3==1.26.9
whitenoise==6.2.0

ライブラリのインストール

$ pipenv install django-heroku gunicorn whitenoise

Error: pg_config executable not found.

django-herokuをインストールする際にError: pg_config executable not found.とエラーが出る場合はpostgresqlをインストール。

$ brew install postgresql

settings.pyの変更

settings.pyと同じディレクトリにsettings_local.pyを作成してください。

そして、settings.pysettings_local.pyにコピペし、settings.pyを変更してください。

settings.py
import os
import django_heroku
from urllib.parse import urlparse

from .settings_local import *

DEBUG = False

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# static setting
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'


if not DEBUG:
    # Heroku settings

    # HerokuのConfigを読み込み
    django_heroku.settings(locals())

また、settings_local.pyのミドルウェア(一番上)にwhitenoise.middleware.WhiteNoiseMiddlewareを追加。

settings_local.py
...
MIDDLEWARE = [
    'whitenoise.middleware.WhiteNoiseMiddleware',
    ...
]
...

厳密に言うとdjango.middleware.security.SecurityMiddlewareの下に配置すれば良いのですが、あまり変化はないため一番上に追加します。

プラットフォーム指定(M1・Mac使用者)

M1チップ搭載のMacbookを使用している方は、Dockerfile--platform=linux/amd64を指定してください。

FROM --platform=linux/amd64 python:3.9.7-alpine

このプラットフォームの指定を行わないとError: Exec format errorとHeroku上でエラーが起き、アプリケーションを稼働させることができません。

Dockerfile

Dockerファイルの最後に以下を追加。

...
RUN python3 manage.py collectstatic --noinput
CMD gunicorn --bind 0.0.0.0:$PORT app.wsgi

このCMD~がProcfileの代わりとなります。

念の為私が使っているDockerfileを載せておきます。参考程度に使ってください。

FROM --platform=linux/amd64 python:3.9.7-alpine

ENV PYTHONDONTWRITEBYTECODE=1 \
  PYTHONUNBUFFERED=1 \
  PYTHONUTF8=1 \
  PIP_NO_CACHE_DIR=off \
  PIP_DISABLE_PIP_VERSION_CHECK=on \
  APP_HOME=/usr/src/app

RUN addgroup -S app && adduser -S app -G app

RUN mkdir -p $APP_HOME && \
    mkdir $APP_HOME/staticfiles
    
WORKDIR $APP_HOME

COPY . $APP_HOME

RUN apk update && \
    apk --no-cache add gcc python3-dev mysql-client mysql-dev postgresql-dev musl-dev libffi-dev tzdata && \
    pip install --upgrade pip && \
    pip install pipenv && \
    pipenv install --system --ignore-pipfile --deploy

RUN ln -fs /usr/share/zoneinfo/Etc/UTC /etc/localtime

RUN chown -R app:app $APP_HOME

USER app

RUN python3 manage.py collectstatic --noinput
CMD gunicorn --bind 0.0.0.0:$PORT app.wsgi

heroku.yml

ディレクトリ直下にheroku.ymlを作成し、以下をコピペ。

heroku.yml
build:
  docker:
    web: Dockerfile

Heroku設定

ログイン

$ heroku login && heroku container:login

アプリ作成

$ heroku create [heroku-app-name]

DB設定

ClearDBをアプリに追加。

$ heroku addons:add cleardb:ignite

JawsDBのすゝめ(2022年6月1日追記)

Heroku上でMySQLのバージョンが5.7以上を使用する場合はJawsDBが推奨されているそうなので、特に理由はない限りJawsDBを使用しましょう。

念の為、ClearDB・JawsDB両方の設定方法を記述します。

JawsDBの追加方法

$ heroku addons:create jawsdb:kitefin --version=8.0 // 任意のバージョンを指定

次に、ClearDBのデータベースURLを確認しコピーします。

$ heroku config
CLEARDB_DATABASE_URL: mysql://***:***@***/***?reconnect=true // ClearDB
JAWSDB_URL: mysql://***:***@***/*** // JawsDB

環境変数

環境変数にDATABSE_URLを追加。

.env
DATABASE_URL = mysql://***:***@***/***

ClearDBを使用した場合?reconnect=trueは取り除いちゃってください。

settings.py

冒頭に修正したsettings.pyにClearDBの設定を追加。

settings.py
import os
import django_heroku
from urllib.parse import urlparse

from .settings_local import *

DEBUG = False

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# static setting
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'


if not DEBUG:
    # Heroku settings

    # ClearDB setting
    if 'DATABASES' not in locals():
        DATABASES = {}

    if 'DATABASE_URL' in os.environ:
        url = urlparse(os.environ['DATABASE_URL'])

        # Ensure default database exists.
        DATABASES['default'] = DATABASES.get('default', {})

        # Update with environment configuration.
        DATABASES['default'].update({
            'ENGINE': 'django.db.backends.mysql',
            'NAME': url.path[1:],
            'USER': url.username,
            'PASSWORD': url.password,
            'HOST': url.hostname,
            'PORT': url.port,
        })

    django_heroku.settings(locals())

スタック設定

$ heroku stack:set container

Dockerイメージをデプロイ

$ heroku container:push web && heroku container:release web

スケール設定

$ heroku ps:scale web=1

マイグレーション

$ heroku run python3 manage.py migrate

管理者ユーザー作成

$ heroku run python3 manage.py createsuperuser

アプリ状態確認

$ heroku open

いつもどおりの画面が開けばOK

image.png

補足

Procfileは不要

途中にも書いたのですが、DockerfileCMDがProcfileの代わりとなっています。

STATICFILES_DIRSは不要

Heroku上での環境構築を行うにあたって、静的ファイルを読み込めないエラーに苦戦しました。

結果、settings.pyに以下の2文を付け加えるだけ。

settings.py
...
    STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
    STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
...

色々情報は出回ってますが、これが現時点での最適解かと思われます。

また、whitenoiseに関連するミドルウェアの追加も忘れずに。

ALLOWED_HOSTS

Heroku上で作業を行う上で、settings_local.pyにあるALLOWDED_HOSTSにHerokuのホストを指定してください。

settings.py
...
ALLOWED_HOSTS = ['[アプリ名].herokuapp.com']
...

追記:スリープ

Herokuの無料枠では30分アクセスがないとサーバーがスリープ状態に入ります。

それを防ぐためには様々な方法があります。

こちらの記事を見ていただければ大概のことは解決できます。

ただし、少し調べてみると、メジャーなやり方でもあるSchedulerだと時々実行されない、意図せぬ課金が発生などの問題もあるそうです。

なので、私はdjango-crontabを使って25分毎にHerokuにアクセスするように設定しました。

最後に

Djangoのリソースが出回っておらず、かなり苦戦しましたが動いてくれてよかったです。

何か不明な点や上手く動作しないということがあれば気軽にコメントにて質問してください。

以上、「Django+MySQL+Dockerの環境をHerokuにデプロイする」でした!

Thank you for reading

参考記事

以下、この記事を書くにあたって参考にさせていただいた記事となります。

https://qiita.com/rebi/items/efd1c36f0a9e46222d80
https://zenn.dev/daku10/articles/m1-heroku-container-trouble-exec-format-error
https://qiita.com/akirakudo/items/16a01271b0a39316e439
https://devcenter.heroku.com/articles/cleardb#using-cleardb-with-python-django

6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?