自從 Heroku 出現之後,筆者挺羨慕 Rails 的開發者有這麼酷的服務可以使用。不過就在不久前 Heroku 也開始支援 Python 了,便趁著空閒玩了一下。大體而言只要熟悉平常使用的 Python 相關工具,像是 virtualenv、pip 以及 git,整個部署流程就很簡單。
本文將說明如何透過幾個簡單的步驟,把 Django 部署到 Heroku,手腳快的話十分鐘之內便可以看到網站在 Heroku 上運作了。
首先到 Heroku 官方網站註冊並啟用帳號,接下來就可以在本地端操作,而不需至官方網站設定了。因為只要安裝完 Heroku 的 CLI,之後使用 heroku
這個指令即可完成所有的部署流程。
Heroku 的 CLI 有不同平台的 package 供下載安裝,直接到 Heroku Toolbet 即可下載。或者可以直接透過 rubygems 安裝,指令如下:
$ sudo gem install heroku
首先要建立並啟用 virtualenv。
$ virtualenv testenv --no-site-packages
$ cd testenv
$ source bin/activate
接下來為了不在 Django 上著墨太多,筆者準備了一份專為部署 Heroku 的 Django 專案,包含了基本的 Django 設定跟部署到 Heroku 的設定檔。筆者把檔案放在 github,可以直接透過此網址下載壓縮檔,解開後把檔案放進剛建立好的 virtualenv,檔案結構如下即可。
注意,別漏了 .gitignore 這個隱藏檔。
Procfile
bin/
herokutest/
include/
lib/
.gitignore
requirements.txt
如果您熟悉 pip 和 virtualenv,就知道接下來必須透過 pip 讀取 requirements.txt 以自動安裝專案所需要的 python packages。
$ pip install -r requirements.txt
接著執行以下指令初始資料庫,然後輸入 Django 所提示的資料即可完成本地資料庫的初始化。
$ python herokutest/manage.py syncdb
然後安裝 foreman,接著用 foreman 運作專案,看看我們的專案是否能夠正常執行。
$ sudo gem install foreman
$ foreman start
最後透過瀏覽器連線到 https://localhost:5000/ 就可以看到執行畫面了。
如果本地端的程式可以正常執行,就可以準備把程式部署到 Heroku 上了。不過這邊得另外說明,由於筆者提供的 Django 設定使用 SQLite3 當作開發用的資料庫,方便本地端開發,但在 Heroku 上必須使用 PostgreSQL,所以部署之前需要先修改 requirements.txt,這樣在部署上 Heroku 時,Heroku 才會幫我們裝上 PostgreSQL 的 driver。
修改方式是於 requirements.txt 檔案上,將最後一行的 psycopg2 的註解拿掉。修改完成如下:
# testenv/requirements.txt
django
gunicorn
psycopg2
取消註解 psycopg2 之後,就可以開始進行第一次 git commit,準備把程式部署到 Heroku。
$ git init
$ git add .
$ git commit -m 'initial commit'
部署前,我們得先使用以下指令登入 Heroku、上傳 ssh 的 public key,並且建立新的 Heroku app。
$ heroku login
$ heroku keys:add
$ heroku create --stack cedar
接下來就可以看到以下訊息,Heroku 已經幫我們建好了 App,並提供 App 的網址,然後 Heroku 會自動把 git remote 加上 Heroku 的位置。
Creating electric-light-4662... done, stack is cedar
https://electric-light-4662.herokuapp.com/ |
This e-mail address is being protected from spambots. You need JavaScript enabled to view it
:electric-light-4662.git
如此就能直接透過 git 把專案送上 Heroku。
$ git push heroku master
在部署的過程中,Heroku 會新增新的資料庫設定到 settings.py 覆蓋原本的設定,以便連到 Heroku 的指定 PostgreSQL。然後會讀取 requirements.txt 安裝所需的 python packages,最後透過 Procfile 執行 web 程式。
最後我們需要初始化 Heroku 上的資料庫,直接透過 heroku run
指令來做遠端執行。
$ heroku run python herokutest/manage.py syncdb
接著輸入 Django 所提示的資料即可完成資料庫的初始化,最後就可以連上 https://.herokuapp.com/admin/app/post/add/
來登入 Django 的後台新增文章。新增完畢後,回到首頁就看到剛才的資料出現在首頁啦!
自 Django 1.3 開始,靜態檔是透過 collectstatic 指令收集到同一個目錄,方便透過網頁伺服器處理。所以我們在部署完後,通常會執行以下指令收集靜態檔:
$ heroku run python herokutest/manage.py collectstatic --noinput
然而在透過 heroku run
指令執行 collectstatic 時,Heroku 會開啟另一個 dyno 來執行,所以此時會進入另一個 App 環境,跟我們原先部署的程式空間是分開的,導致無法正確處理靜態檔。
所以筆者用了另一個解法,就是安裝 django-storages 並且將 STATICFILES_STORAGE 設定為 S3Storage,之後執行 collectstatic 指令時,靜態檔就會自動被放上 S3,這麼一來就解決無法把靜態檔放上 Heroku 的問題了。
Heroku 的確大大減輕了部署的很多麻煩,不用自己裝任何伺服器也不需管理,處理 scale 更是輕鬆,只需輸入指令就可以多開一個 dyno 支撐更多流量,讓開發者更能專心在程式開發,不必花時間部署自己的伺服器和後續維護。
在用過好幾家 PaaS 之後,因為各家部署的方式不同,有時會有一些小問題得另外處理,不過單就這次把 twitthat 搬到 Heroku 運作的經驗,除了 staticfiles 的問題之外,Heroku 的部署方式算是設計得挺不錯,而且反應速度也比先前用過的幾個 Python 專屬 PaaS 更快。
Comments
$ git commit -am 'initial commit'
-->
git add .
git commit -m 'initial commit'
*************** *****
$ python herokutest/manage.py syncdb
Traceback (most recent call last):
File "herokutest/manage.py", line 2, in
from django.core.management import execute_manager
ImportError: cannot import name execute_manager