Python/Django on Heroku

因為先前 Open Foundry 電子報, 關於 Heroku 部屬的相關文章獨缺 Python,所以便找了我寫這部份, 想說順便借這次機會催促自己玩一下 Heroku,所以就生出了這篇 Python/Django on Heroku

不過前一陣子又玩了很多 Heroku 上的東西,之後再寫篇文章來補充一下好了,下面就直接把文章直接放上來,存個備份,話說當然有修 typo :p

簡介

自從 Heroku 出現之後,挺羨慕 Rails 的開發者有這麼酷的服務可以使用。不過就在不久前 Heroku 也開始支援 Python 了,所以便趁著空閒玩了一下。基本上只要熟悉平常使用的 Python 相關工具,像是 virtualenv、pip 以及 git 的話,整個部屬流程可以說是非常簡單。

接下來,我會說明如何透過簡單的幾個步驟,把 Django 部屬到 Heroku,手腳快的話在十分鐘之內便可以看到網站在 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

最後透過瀏覽器連線到 http://localhost:5000/ 就可以看到執行畫面了。

將程式部屬到 heroku

本地端的程式可以正常執行的話,就可以準備把程式部屬到 Heroku 上了。不過這邊得另外說明一下,由於我提供的 Django 設定是使用 SQLite3 當做開發用的資料庫,方便本地端開發,不過在 Heroku 上得使用 PostgreSQL ,所以在部屬之前得先修改 requirements.txt,把最後一行的 psycopg2 的註解拿掉,這樣在部屬上 Heroku 時,Heroku 才會幫我們裝上 PostgreSQL 的 driver。

# testenv/requirements.txt
django  
gunicorn  
psycopg2  

取消註解掉 psycopg2 之後,就可以開始進行第一次 git commit,準備把程式部屬到 Heroku。

$ git init
$ gt 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  
http://electric-light-4662.herokuapp.com/ | [email protected]: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 所提示的資料即可完成資料庫的初始化,最後就可以連上 http://<your-app-name>.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 來的好。有空再來寫個玩具丟上 Heroku 玩好了!

tzangms

Read more posts by this author.

Subscribe to Oceanic / 海海人生

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!