目標:紀錄一下如何將 Python 寫好的東西丟上 Heroku

在先前的 訂便當系列 中已經建立了一個替我們去爬便當網並通知我們的小工具,但還存在一個相當大的問題:要在哪跑?總不能就只放在家裡電腦有開機就跑、沒開機就算了吧?因此我們必須找個主機把它放上去。而在上一篇做 Line Notify 的時候所參考的 如何快速建置一個 LINE Notify 的服務 中提到了將服務放上 Heroku 的部分,因此馬上嘗試看看。

結果過程中碰了不少壁,因此特地紀錄下來。

Heroku 是一個雲端平台,讓使用者可以把服務丟上去跑,同時最讚的部分是,免費用戶就提供了每月 450 小時可以使用(但有每半小時會進入休眠的限制),詳情可以參閱 Heroku 的計費頁面

本系列最後一階段的目標就是要將訂便當爬蟲整套丟上去雲端上運行,達到被動接收通知的效果。但由於訂便當爬蟲還牽涉到用 Selenium 開瀏覽器互動,以及使用 Sqlite 儲存的部分,轉移到 Heroku 的環境上還需要進行一些調整。因此這一階段將會分成兩篇(或以上)文章進行,上篇會先簡單地紀錄如何將服務放上 Heroku,下篇開始則著重於紀錄將訂便當系統放上 Heroku 時遇到的問題和解決過程

本篇主要的參考來源來自於 搭配 Git 在 Heroku 上部署網站的手把手教學發布網站到 Heroku 以及 網站部署(使用 Heroku) 這幾篇,其餘參考將附於文末,感謝各位前人大大留下的優質文。

註冊及安裝

Heroku 的 註冊 相當簡單,這邊就略過不提,需要說明可以參考 這篇

註冊完畢就會回到個人頁面,底部有 Heroku Dev Center,也能選自己慣用的程式語言進去教學說明,有興趣的可以逛個一圈。

這邊我們就先新增一個應用程式,點選畫面中間左側的 Create a new app

接著輸入應用程式名稱,注意只能使用小寫,並且不能重複。如果已經使用後續會提到的 CLI 的朋友,也可以直接使用 heroku create 的指令來建立應用程式。

建立完成之後就會進到專案的頁面:

可以看見 Heroku 提供了幾種方法來將應用程式推送到 Heroku 上,例如連接到 Github。我們這邊用 Heroku CLI 試試,頁面上也已經提供了步驟說明。

Heroku CLI 的安裝說明頁面,在這邊挑選自己的系統下載並安裝。

安裝過程也相當簡易,會有將 Heroku 加到環境變數和路徑等選項,一路下一步即可。

裝完之後,打開命令列輸入 Heroku,如果有跳出指令列表就代表安裝已經成功

連接至 Heroku

備註:由於 Heroku 傳送檔案的方式是使用 Git 進行,因此在後續的操作之前,必須先確保電腦中已經安裝 Git

接著我們就按照上面 Heroku CLI 說明頁面的步驟開始操作。

首先要先登入,輸入 heroku login 之後,便會開啟瀏覽器進行登入驗證,如果成功會看見登入訊息

接著就可以移到專案的資料夾,將專案和 Heroku 做連接

# 先移動到專案的資料夾
$ cd my-project/

# Git 初始化
$ git init

# 和 Heroku 專案連接
$ heroku git:remote -a Heroku的APP名稱

環境設定及測試

這邊由於前面提到訂便當系統有部分要調整的關係,因此只使用 我要訂便當(3) 的 Lint Notify 測試版 的 Line Notify 上去試試看。上一集的簡單 Line Notify 程式碼如下,這邊命名為 myApp.py

import requests

def lineNotifyMessage(token, msg):
    headers = {
        "Authorization": "Bearer " + token,
        "Content-Type": "application/x-www-form-urlencoded"
    }

    payload = {'message': msg}
    r = requests.post(
        "https://notify-api.line.me/api/notify",
        headers=headers,
        params=payload)
    return r.status_code


message = 'Line Notify + Heroku 測試'
token = 'YOUR TOKEN'
result = lineNotifyMessage(token, message)

接著除了主要的 py 檔以外,還需要一些檔案去告訴 Heroku 怎麼處理我們的服務。

事實上我第一次是直接就把 py 傳上去 Heroku 然後建置大失敗,還好 Google 了一陣有前人指點,這邊的設定部份參照自 如何使用 Heroku 部屬一個 Web App 網頁應用程式,特此感謝。

不過 Heroku 還不知道怎麼建我們的服務,因此這邊還需要新增幾個設定的檔案:

Procfile

用來告訴 Heroku 怎麼運行我們的服務

worker: python myApp.py

這行的意思是:worker 的運行方式是 python myApp.py 這行命令,Heroku 會根據這個文件的內容去建 dynos 容器來運行我們的應用服務

像上面的參考文章在建置 Flask 時,就將運行 web 的命令設定為 gunicorn flask_app:appGunicorn 去起網站來跑。

由於這次的示範組只是個小腳本,因此我們宣告個 worker 而不是網站方便之後處理。當宣告的運行是 web 時,Heroku 還會幫忙接 HTTP 的內容,當然想包裝成 Web APP 的朋友,也可以參考上面的文章將腳本包裝成簡單的 Flask。

關於 Procfile 和 dynos,可以參見 Heroku 運行類別、 Procfile、常用指令筆記 以及 Heroku 官方的 Dynos (app containers)

這邊另外要注意的地方有兩個:這個檔案是不需要副檔名的,而且大小寫請正確。我在碰壁的過程中有遇到本機測試可以但推送上去就不行的情況,後來發現是打成全小寫了,改成字首大寫就正常,因此這邊提醒一下大家。

requirements.txt

用來標示需要安裝的套件,逐行列出套件即可,也可以用 套件名稱==版本號 的方式指定套件版本。由於測試的程式碼只用到 requests,因此這邊列上 requests 就可以了。

requests

runtime.txt

用來標示 Python 的版本,這篇文當下的版本為

python-3.7.6

本機測試

到目前為止沒意外的話應該會包含這些東西

這邊可以嘗試在本機測試看看,打開命令列輸入 heroku local worker 就可以在 localhost Run 起來看看囉。注意這是在本機啟動 worker 這個 dynos 的意思,所以如果前面的 Procfile 是使用 web 的朋友,這邊就要輸入 heroku local web 囉。

想要全面啟動,可以直接輸入 heroku local;想要指定 Port 的也可使用 heroku local -p 7000 等等,可以參見 Heroku 運行類別、 Procfile、常用指令筆記 的啟動段落有比較常用的用法。

如果一切安好,就可以開始嘗試部署囉

部署至 Heroku

Heroku 的部署只需要用 Git 推送上去就可以了,也就是只需要

# 把所有檔案都加到這次變更
$ git add .

# Commit 所有變動(記得標註解,養成好習慣)
$ git commit -am "這是Commit註解"

# 推送
$ git push heroku master

就可以發到 Heroku 進行部署了,推送時也能看見建置的過程,如安裝的包和建置是否成功等資訊都會顯示

如果前面架上去的是網站,也就是 Procfile 使用 Web 的朋友,Heroku 應該會幫忙把服務建起來。而像我是另外定義 worker 的朋友,這邊還需要多一個把 dynos 建起來的動作

命令列中輸入 heroku ps 就可以看到現在正在運行的服務,如果沒有任何服務運行,或是想擴展服務,可以使用 heroku ps:scale Procfile裡定義的服務=服務數 來操作。

例如我是使用 worker,這邊就輸入 heroku ps:scale worker=1 就會開啟一個 worker 來運行;反過來說,輸入 heroku ps:scale worker=0 就可以停止 worker 的服務囉。

如果這邊部屬和運行有問題的朋友,可以查看 Heroku 的 Log:在命令列輸入 Heroku log 就會顯示了(建議搭配 --tail 等方法使用,詳請可見 官方文檔

此外,若是跟我初嘗試一樣跑出 Couldn't find that process type 請參照 這篇,我個人是修改 Procfile 檔名的大小寫就解決了

若是建置時無法成功的朋友,可能是沒抓到你的服務的語言(例如 Python),需要自己去拉一下 buildpacks,例如 Python 的建置包就是 heroku-buildpack-python

最後我們回來看一下 Heroku 的 APP 頁面

Activity 可以看見最近的活動,例如部署失敗也會顯示在這;而 Settings 則是一些專案設定,例如名稱和建置包都要到這裡調整

其中可以從 Domains 這裡連到你的服務,如果你放的是網頁或 API 的話就可以從這裡進入。不過更快進入自己服務的方法,是在命令列中直接下 Heroku open 就行啦。

後記

其實原本打算部署的部分一篇解決的,沒想到牆就這樣撞了上來,將便當放到 Heroku 上時實在遇到挺多問題,例如第一次使用時直接把整坨檔案直接推上去也沒設定結果建置失敗,或是發現 Heroku 不給用 Sqlite,或是 Selenium 要另外找建置包等等,因此最後決定切成兩篇,一篇好好記 Heroku 的流程,剩下的部份再按照問題做紀錄。

同時因為原本的訂便當已經在家裡電腦跑著了,部屬上雲似乎是額外再戰的部份。待到剩下問題解決了,抓緊下班時間再寫上來記著,希望以後能派上用場吧。

我要訂便當系列

參考資料