Login  |  繁體中文
感謝您對「自由軟體鑄造場」的支持與愛護,十多年來「自由軟體鑄造場」受中央研究院支持,並在資訊科學研究所以及資訊科技創新研究中心執行,現已完成階段性的任務。 原網站預計持續維運至 2021年底,網站內容基本上不會再更動。本網站由 Denny Huang 備份封存。
也紀念我們永遠的朋友 李士傑先生(Shih-Chieh Ilya Li)。
Tech Column Python/Django on Heroku

Python/Django on Heroku

簡介

自從 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

如果本地端的程式可以正常執行,就可以準備把程式部署到 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 更快。




OSSF Newsletter : 第 188 期 PaaS:程式語言開發在雲端「Programming in Paas」(下)
Tags: PaaS,   platform as a service,   小海,   Python,   Heroku,   Programming on PaaS,   767,  
Category: Tech Column



Comments 

 
0 #1 yeh_ray 2012-01-06 00:22
$ gt add .
$ git commit -am 'initial commit'
-->
git add .
git commit -m 'initial commit'
 
 
0 #2 maggie 2015-07-05 23:49
When I run this comment, there is error back to me and I also try connection the site "django.core.management " that seems not existed any more. Would you please help about it? Thanks!
*************** *****
$ 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