# 佈署 Django 2 App 上 Heroku

專案:

  • 專案根資料夾: /home/juzhengzhong/workspace/django2_helloworld/
  • Django Project 資料夾:/web_site
  • Django 設定檔: /web_site/settings/
    • init.py
    • base.py
    • dev.py
    • qa.py
    • staging.py
    • prod.py

專案資料夾架構

.
|-- Create_Project_Template.md
|-- Dockerfile
|-- Dockerfile_web
|-- Pipfile
|-- Pipfile.lock
|-- Procfile
|-- Procfile.local
|-- README.md
|-- README_Deploy.md
|-- README_SIT.md
|-- _tools
|-- accounts
|-- author_headshots
|-- books
|-- build_app.sh
|-- build_web.sh
|-- db.sqlite3
|-- deploy_app.sh
|-- django2_helloworld_uwsgi.ini
|-- docker-compose-dev.yml
|-- docker-compose-prod.yml
|-- docker-compose.yml
|-- docker-stack.yml
|-- manage.py
|-- nginx
|-- pages
|-- posts
|-- requirements.txt
|-- run_app.sh
|-- run_docker_compose.sh
|-- run_docker_swarm.sh
|-- runtime.txt
|-- templates
`-- web_site

# 建置專案用 Python 虛擬環境

使用者:juzhengzhong ,在路徑: ~/workspace/django/django2_helloworld/

$ $ cd ~/workspace/django
$ git clone git@bitbucket.org:AlanJui/django2_helloworld.git
$ cd django2_helloworld/ 

建立虛擬目錄 .venv

$ export PIPENV_VENV_IN_PROJECT="enabled"
$ pipenv install -r requirements.txt

啟用 Python 虛擬環境

$ pipenv shell
$ pipenv install django gunicorn whitenoise dj-database-url psycopg2

產生 Python 套件安裝清單檔

$ pipenv lock --requirements > requirements.txt 

建立 Heroku App 設定檔:Procfile

web: gunicorn web_site.wsgi --log-file -

.gitignore

.idea/
*.log
*.pot
*.pyc
**/__pycache__/
_tools/log/
/django2_helloworld_nginx.conf
/django2_helloworld_uwsgi.ini
/app.sock
/ENV/
/VENV/
/.venv/
db.sqlite3

login heroku

$ heroku login

create heroku app

$ heroku create


$ heroku create
Creating app... done, ⬢ serene-crag-30137
https://serene-crag-30137.herokuapp.com/ | https://git.heroku.com/serene-crag-30137.git

在 Django 的 settings.py 加入如下各種設定

需自環境變數讀入值:

EMAIL_HOST_USER = os.environ.get('EMAIL_HOST_USER')
EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD')

設定 INSTALLED_APPS:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'whitenoise.runserver_nostatic',
    'django.contrib.staticfiles',

    # Libs
    'crispy_forms',

    # My Apps
    'pages.apps.PagesConfig',
    'posts.apps.PostsConfig',
    'books.apps.BooksConfig',
    'accounts.apps.AccountsConfig',
]

設定 MIDDLEWARE:

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',

    # My MiddleWare
]

設定 ALLOWED_HOSTS:

ALLOWED_HOSTS = [
    '127.0.0.1',
    '0.0.0.0',
    'localhost',
    '.herokuapp.com',
]

設定 STATIC 相關值:

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.0/howto/static-files/

STATIC_URL = '/static/'

# location where you will store your static files
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "../static"),
]

# The absolute path to the directory where collectstatic will collect static files for deployment.
STATIC_ROOT = os.path.join(BASE_DIR, '../staticfiles')

# Simplified static file serving.
# https://warehouse.python.org/project/whitenoise/
# Document Ref: http://whitenoise.evans.io/en/stable/django.html
STATICFILES_STORAGEGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'

參考: http://whitenoise.evans.io/en/stable/django.html

設定 MEDIA 相關值:

MEDIA_ROOT = os.path.join(BASE_DIR, '../media')
MEDIA_URL = '/media/'

manage.py:

if __name__ == "__main__":
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'web_site.settings.prod')
    ......

wsgi.py:

import os
from django.core.wsgi import get_wsgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'web_site.settings.prod')

application = get_wsgi_application()

Heroku Environment Variable:

DJANGO_SETTINGS_MODULE = "web_site.settings.heroku"

# Postgres Database

要求 Heroku 加入 Postgres 的 Add-Ons

$ heroku addons:create heroku-postgresql:hobby-dev
Creating heroku-postgresql:hobby-dev on ⬢ serene-crag-30137... free
Database has been created and is available
 ! This database is empty. If upgrading, you can transfer
 ! data from another database with pg:copy
Created postgresql-defined-16536 as DATABASE_URL
Use heroku addons:docs heroku-postgresql to view documentation

$ heroku pg:info
=== DATABASE_URL
Plan:                  Hobby-dev
Status:                Available
Connections:           0/20
PG Version:            11.2
Created:               2019-04-02 13:27 UTC
Data Size:             7.7 MB
Tables:                0
Rows:                  0/10000 (In compliance)
Fork/Follow:           Unsupported
Rollback:              Unsupported
Continuous Protection: Off
Add-on:                postgresql-defined-16536

設定 Heroku 平台 DB URL

$ heroku config -s | grep DATABASE_URL


$ heroku config -s | grep DATABASE_URL

DATABASE_URL='postgres://bfmsqsgqqhibrl:b0e69f257d7dc611c29f2d437368874c11065a80aa31880f67e987210f5c2e25@ec2-54-225-242-183.compute-1.amazonaws.com:5432/d9mn8r7u66f8h1'

將 local 端的 Postgres 資料庫匯入 Heroku 平台

$ heroku pg:push 《SOURCE》 《TAGRET》


$ heroku pg:push postgres://django2_helloworld:Passw0rd@localhost/django2_helloworld_db postgresql-defined-16536

# Heroku 環境變數設定

設定 DATABASE_URL:

$ heroku config:set DATABASE_URL='postgres://bfmsqsgqqhibrl:b0e69f257d7dc611c29f2d437368874c11065a80aa31880f67e987210f5c2e25@ec2-54-225-242-183.compute-1.amazonaws.com:5432/d9mn8r7u66f8h1'

設定停用 Collectstatic

$ heroku config:set DISABLE_COLLECTSTATIC=1

設定 DJANGO_ALLOWED_HOSTS

$ heroku config:set DJANGO_ALLOWED_HOSTS='serene-crag-30137.herokuapp.com'

設定 DJANGO_STATIC_HOST

$ heroku config:set DJANGO_STATIC_HOST='https://serene-crag-30137.herokuapp.com'

設定 DJANGO_SETTINGS_MODULE:

$ heroku config:set DJANGO_SETTINGS_MODULE='web_site.settings.heroku'

佈署

$ ./manage.py collectstatic
$ git add . && git commit -m "Deploy to Heroku Platform"
$ git push heroku master


$ git push heroku master
Counting objects: 10354, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (6512/6512), done.
Writing objects: 100% (10354/10354), 23.43 MiB | 3.03 MiB/s, done.
Total 10354 (delta 4062), reused 7172 (delta 2355)
remote: Compressing source files... done.
remote: Building source:
remote: 
remote: -----> Python app detected
remote:  !     Python has released a security update! Please consider upgrading to python-3.6.8
remote:        Learn More: https://devcenter.heroku.com/articles/python-runtimes
remote: -----> Installing python-3.6.4
remote: -----> Installing pip
remote: -----> Installing dependencies with Pipenv 2018.5.18…
remote:        Installing dependencies from Pipfile.lock (dd71a2)…
remote: -----> Installing SQLite3
remote: -----> Discovering process types
remote:        Procfile declares types -> web
remote: 
remote: -----> Compressing...
remote:        Done: 87.1M
remote: -----> Launching...
remote:        Released v7
remote:        https://serene-crag-30137.herokuapp.com/ deployed to Heroku
remote: 
remote: Verifying deploy... done.
To https://git.heroku.com/serene-crag-30137.git
 * [new branch]      master -> master

啟動 Heroku App

$ heroku open

重新啟動 Heroku App

$ heroku restart -a serene-crag-30137

查 Log 紀錄

$ heroku logs -n 200


$ heroku logs --tail

# 在 Local 端試行

備妥下列三個檔案:

  • runtime.txt
  • .env
  • Procfile.local

runtime.txt

python-3.6.8

.env

DATABASE_URL=postgres://bfmsqsgqqhibrl:b0e69f257d7dc611c29f2d437368874c11065a80aa31880f67e987210f5c2e25@ec2-54-225-242-183.compute-1.amazonaws.com:5432/d9mn8r7u66f8h1
DISABLE_COLLECTSTATIC=1
DJANGO_ALLOWED_HOSTS=serene-crag-30137.herokuapp.com
DJANGO_SETTINGS_MODULE=web_site.settings.heroku

【註】: 自 Heroku 平台抄錄環境變數到 .env 檔案

$ heroku config:get 《變數名稱》 -s >> 《檔案名稱》  
$ heroku config:get DJANGO_SETTINGS_MODULE -s >> .env  

Procfile.local

web: gunicorn --env DJANGO_SETTINGS_MODULE="web_site.settings.heroku"  web_site.wsgi  --log-file 

# 參考文章

https://medium.com/@hdsingh13/deploying-django-app-on-heroku-with-postgres-as-backend-b2f3194e8a43

https://devcenter.heroku.com/articles/heroku-local