Flask 教程 第十八章:Heroku上的部署

本文轉載自:https://www.jianshu.com/p/d13dc21c6e43
這是Flask Mega-Tutorial系列的第十八部分,我將在其中部署Microblog到Heroku雲平臺。

在前面的文章中,我向你展示了託管Python應用程序的“傳統”方式,並且我演示了兩個部署到Linux的服務器的實際示例。 如果你不曾管理過Linux系統,那麼你可能認爲需要投入大量工作到這項任務中,而且肯定會有一個更簡單的方法。

在本章中,我將向你展示一種完全不同的部署方法,該方法依賴第三方託管提供程序來執行大部分管理任務,從而使你能夠騰出更多時間處理應用程序。

許多雲託管提供商提供了一個應用程序可以運行的託管平臺。 你只需提供部署到這些平臺上的實際應用程序,因爲硬件,操作系統,腳本語言解釋器,數據庫等都由該服務管理。 這種服務稱爲平臺即服務(PaaS)。

是不是感到難以置信

我將把Microblog部署到Heroku,這是一種流行的雲託管服務,對Python應用程序也非常友好。 我選擇Heroku不僅僅是因爲它非常受歡迎,還因爲它有一個免費的服務級別,可以讓你跟隨我並在不花錢的情況下完成部署。

本章的GitHub鏈接爲:BrowseZipDiff.

託管於Heroku

Heroku是首批PaaS平臺之一。 它以Ruby的應用程序的託管服務開始,隨後逐漸發展到支持諸多其他語言,如Java,Node.js和Python。

在Heroku中部署Web應用程序主要是通過git版本控制工具完成的,因此你必須將應用程序放在git代碼庫中。 Heroku在應用程序的根目錄中查找名爲Procfile的文件,以獲取有關如何啓動應用程序的描述。 對於Python項目,Heroku還期望requirements.txt文件列出需要安裝的所有模塊依賴項。 在通過git將應用程序上傳到Heroku的服務器之後,你的工作基本就完成了,只需等待幾秒鐘,應用程序就會上線。 整個操作流程就是這麼簡單。

Heroku提供不同的服務級別,允許你自主選擇爲應用程序提供多少計算能力和運行時間,隨着用戶羣的增長,你需要購買更多的“dynos”計算單元。

準備好了嗎?讓我們開始吧!

創建Heroku賬戶

在部署應用到Heroku之前,你需要擁有一個帳戶。 所以請訪問heroku.com並創建一個免費賬戶。 一旦註冊成功並登錄到Heroku,你將可以訪問一個dashboard,其中列出了你的所有應用程序。

安裝Heroku命令行客戶端

Heroku提供了一個名爲Heroku CLI的命令行工具來與服務交互,可安裝於Windows,Mac OS X和Linux。 該文檔包括了支持的所有平臺的安裝說明。 如果你計劃部署應用程序以測試該服務,請將其安裝在你的系統上。

安裝CLI後應該做的第一件事是登錄到你的Heroku帳戶:

$ heroku login

Heroku CLI會要求你輸入電子郵件地址和帳戶密碼。 你的身份驗證狀態將在隨後的命令中被記住。

設置Git

git工具是Heroku應用程序部署的核心,因此如果你還沒有安裝它的話,則必須將它安裝到你的系統上。 如果你沒有可用於你的操作系統的安裝包,可以訪問git site下載安裝程序。

使用git的原因很多並且都理由充分。 如果你打算部署應用到Heroku,那麼這些原因就要又增加一個,因爲要部署應用到Heroku,你的應用程序必須在git代碼庫中。 如果你要爲Microblog執行測試部署,可以從GitHub克隆應用程序:

$ git clone https://github.com/miguelgrinberg/microblog
$ cd microblog
$ git checkout v0.18

git checkout命令將代碼庫切換到指定的歷史提交點,也就是本章所處的位置。

如果更喜歡使用你自己的代碼,你可以通過在頂層目錄中運行git init .來將你自己的項目轉換成git代碼庫(注意init後面的句號,它告訴git你想要在當前目錄中初始化代碼庫)。

創建Heroku應用

要用Heroku註冊一個新應用,需要在應用程序根目錄下使用apps:create子命令,並將應用程序名稱作爲唯一參數傳遞:

$ heroku apps:create flask-microblog
Creating flask-microblog... done
http://flask-microblog.herokuapp.com/ | https://git.heroku.com/flask-microblog.git

Heroku要求應用程序的名稱具有唯一性。 我上面已使用了flask-microblog這個名稱,所以你需要爲你的部署選擇一個不同的名稱。

該命令的輸出將包含Heroku分配給應用程序的URL以及git代碼庫。 你的本地git代碼庫將配置一個額外的remote,稱爲heroku。 你可以用git remote命令驗證它是否存在:

$ git remote -v
heroku  https://git.heroku.com/flask-microblog.git (fetch)
heroku  https://git.heroku.com/flask-microblog.git (push)

根據你創建git代碼庫的方式,上述命令的輸出還可能包含另一個名爲origin的遠程倉庫地址。

臨時文件系統

Heroku平臺與其他部署平臺不同之處在於它在虛擬化平臺上運行的文件系統是臨時的。 那是什麼意思? 這意味着Heroku可以隨時將運行你的應用的虛擬服務器重置爲乾淨狀態。 你不該天真地認爲你保存到文件系統的任何數據都會被持久存儲,事實上,Heroku經常回收服務器。

在這種條件下工作會爲我的應用程序帶來一些問題,因爲它使用瞭如下的幾個文件:

  • 默認的SQLite數據庫引擎將數據寫入磁盤文件中
  • 應用程序的日誌也寫入磁盤文件中
  • 編譯的語言翻譯存儲庫同樣是本地文件

以下部分將針對這三個方面提出解決方案。

使用Heroku Postgres數據庫

爲了解決第一個問題,我將切換到不同的數據庫引擎。 在第十七章中,你看到我使用MySQL數據庫爲Ubuntu部署添加健壯性。 Heroku基於Postgres數據庫提供了自己的數據庫產品,因此我將轉而使用它來避免使用基於文件的SQLite。

Heroku應用的數據庫使用相同的Heroku CLI進行設置。 在本章中,我將創建一個免費級別的數據庫:

$ heroku addons:add heroku-postgresql:hobby-dev
Creating heroku-postgresql:hobby-dev on flask-microblog... 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-parallel-56076 as DATABASE_URL
Use heroku addons:docs heroku-postgresql to view documentation

新創建的數據庫的URL存儲在DATABASE_URL環境變量中,該變量在應用程序運行時將可用。 這就非常方便了,因爲應用程序已經設定爲在該變量中查找數據庫URL。

輸出日誌到標準輸出

Heroku希望應用程序直接輸出日誌到stdout。 當你使用heroku logs命令時,應用程序打印到標準輸出的任何內容都將被保存並返回。 所以我要添加一個配置變量,指示我是要輸出日誌到stdout,還是像我之前那樣輸出到文件。 這是配置的變化:

config.py:輸出日誌到標準輸出的選項。

class Config(object):
    # ...
    LOG_TO_STDOUT = os.environ.get('LOG_TO_STDOUT')

然後在應用工廠函數中,我會檢查此配置以瞭解應該如何配置應用程序的日誌記錄器:

app/__init__.py:輸出日誌到標準輸出或文件。

def create_app(config_class=Config):
    # ...
    if not app.debug and not app.testing:
        # ...

        if app.config['LOG_TO_STDOUT']:
            stream_handler = logging.StreamHandler()
            stream_handler.setLevel(logging.INFO)
            app.logger.addHandler(stream_handler)
        else:
            if not os.path.exists('logs'):
                os.mkdir('logs')
            file_handler = RotatingFileHandler('logs/microblog.log',
                                               maxBytes=10240, backupCount=10)
            file_handler.setFormatter(logging.Formatter(
                '%(asctime)s %(levelname)s: %(message)s '
                '[in %(pathname)s:%(lineno)d]'))
            file_handler.setLevel(logging.INFO)
            app.logger.addHandler(file_handler)

        app.logger.setLevel(logging.INFO)
        app.logger.info('Microblog startup')

    return app

所以現在我需要在Heroku中運行應用程序時設置LOG_TO_STDOUT環境變量,但在其他配置中則不需要。 Heroku CLI使得做到這一點變得簡單,因爲它提供了一個選項來設置運行時使用的環境變量:

$ heroku config:set LOG_TO_STDOUT=1
Setting LOG_TO_STDOUT and restarting flask-microblog... done, v4
LOG_TO_STDOUT: 1

編譯翻譯

Microblog依賴本地文件的第三個方面是編譯後的語言翻譯文件。 確保這些文件永遠不會從臨時文件系統中消失的粗暴做法是將編譯後的語言文件添加到git代碼庫,以便在部署到Heroku後它們成爲應用程序初始狀態的一部分。

在我看來,更優雅的選擇是在Heroku的啓動命令中包含flask translate compile命令,以便在服務器重新啓動時再次編譯這些文件。 我打算選擇這個方案,因爲我知道啓動過程需要多個命令,至少我還需要運行數據庫遷移。 所以現在,我將把這個問題放在一邊,稍後當我寫Procfile的時候會重新討論它。

託管Elasticsearch

Elasticsearch是可以添加到Heroku項目中的衆多服務之一,但與Postgres不同的是,這不是由Heroku提供的服務,而是由與Heroku合作提供附加組件的第三方提供的。 在我寫這篇文章的時候,有三個不同的集成Elasticsearch服務提供商。

在配置Elasticsearch之前,請注意,Heroku要求你的帳戶在安裝任何第三方附加組件之前添加信用卡信息,即使你仍處於在免費級別中。 如果你不想將信用卡信息提供給Heroku,請跳過此部分。 你仍然可以部署應用程序,但搜索功能不起作用。

在可作爲附加組件提供的Elasticsearch選項中,我決定嘗試SearchBox,它附帶一個免費的初試計劃。 要將SearchBox添加到你的帳戶,你必須在登錄到Heroku後運行以下命令:

$ heroku addons:create searchbox:starter

該命令將部署一個Elasticsearch服務,並將該服務的連接URL保存在與你的應用程序關聯的SEARCHBOX_URL環境變量中。 請記住,除非將你的信用卡信息添加到你的Heroku帳戶中,否則此命令將失敗。

回憶一下第十六章,我的應用程序在Elasticsearch連接URL中查找的是ELASTICSEARCH_URL變量,所以我需要添加這個變量並將其設置爲由SearchBox分配的連接URL:

$ heroku config:get SEARCHBOX_URL
<your-elasticsearch-url>
$ heroku config:set ELASTICSEARCH_URL=<your-elasticsearch-url>

在這裏,我首先要求Heroku打印SEARCHBOX_URL的值,然後將其添加到一個名爲ELASTICSEARCH_URL的新環境變量中。

更新依賴

Heroku期望依賴關係在requirements.txt文件中,就像我在第十五章中定義的那樣。 但是爲了在Heroku上運行應用程序,我需要爲這個文件添加兩個新的依賴關係。

Heroku不提供自己的Web服務器。 相反,它希望應用程序根據環境變量$PORT中給出的端口號啓動自己的Web服務器。 由於Flask開發Web服務器不足以用於生產,因此我將再次使用gunicorn,這是Heroku爲Python應用程序推薦的服務器。

該應用程序還將連接到Postgres數據庫,爲此SQLAlchemy依賴psycopg2軟件包的安裝。

gunicorn 和psycopg2 都需要添加到requirements.txt文件中。

Procfile

Heroku需要知道如何執行應用程序,並且它會在應用程序的根目錄中使用名爲Procfile的文件。 這個文件的格式很簡單,每行包含一個進程名稱,一個冒號,然後是啓動進程的命令。 在Heroku上運行的最常見的應用程序類型是一個Web應用程序,對於這種類型的應用程序,進程名稱應該是web。 下面你可以看到Microblog的Procfile

Procfile:Heroku Procfile。

web: flask db upgrade; flask translate compile; gunicorn microblog:app

在這裏,我定義的啓動命令中將按順序執行三個命令作以啓動Web應用程序。 首先,我運行數據庫遷移升級,然後編譯語言翻譯,最後啓動服務器。

因爲前兩個子命令是基於flask命令的,所以我需要添加FLASK_APP環境變量:

$ heroku config:set FLASK_APP=microblog.py
Setting FLASK_APP and restarting flask-microblog... done, v4
FLASK_APP: microblog.py

gunicorn命令比我用於Ubuntu部署的還要簡單,因爲這個服務與Heroku環境有很好的集成。 例如,$PORT環境變量默認會被設置,取代使用-w選項來設置worker的數量,heroku推薦添加一個名爲WEB_CONCURRENCY的環境變量,在-w參數沒有提供的時候,就會使用這個環境變量,因此你可以靈活地控制worker的數量而無需修改Procfile。

部署應用

所有準備步驟都已完成,所以現在是時候執行部署了。 要將應用程序上傳到Heroku的服務器進行部署,需要使用git push命令。 這與你將本地git代碼庫中的更改推送到GitHub或其他遠程git服務器的方式類似。

現在我已經達到了最有趣的部分,就是將應用程序推送到我們的Heroku託管帳戶。 這其實很簡單,我只需要使用git將應用程序推送到Heroku git代碼庫的主分支就行了。 關於如何做到這一點有幾種方法,取決於你是如何創建你的git代碼庫的。 如果你使用我的v0.18代碼,那麼你需要基於此標記創建一個分支,並將其作爲遠程主分支推送,如下所示:

$ git checkout -b deploy
$ git push heroku deploy:master

相反,如果你正在使用自己的代碼庫,那麼你的代碼已經在master分支中,所以你首先需要確保你的更改已經提交:

$ git commit -a -m "heroku deployment changes"

然後運行如下命令啓動部署:

$ git push heroku master

無論你如何推送分支,都應該看到Heroku的以下輸出:

$ git push heroku deploy:master
Counting objects: 247, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (238/238), done.
Writing objects: 100% (247/247), 53.26 KiB | 3.80 MiB/s, done.
Total 247 (delta 136), reused 3 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Python app detected
remote: -----> Installing python-3.6.2
remote: -----> Installing pip
remote: -----> Installing requirements with pip
...
remote:
remote: -----> Discovering process types
remote:        Procfile declares types -> web
remote:
remote: -----> Compressing...
remote:        Done: 57M
remote: -----> Launching...
remote:        Released v5
remote:        https://flask-microblog.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/flask-microblog.git
 * [new branch]      deploy -> master

我們在git push命令中使用的標籤heroku是在創建應用程序時由Heroku CLI自動添加的遠程代碼庫。 deploy:master參數意味着我將代碼從本地代碼庫的deploy分支推送到Heroku代碼庫上的master分支。 當你使用自己的項目時,你可能會用git push heroku master命令推動你的本地master分支。 由於這個項目的代碼庫分支結構,我推送了一個非master的分支,但Heroku側要求的目標分支是’master’,因爲這是Heroku唯一接受部署的分支。

就這樣,應用程序現在應該已經部署在創建應用程序的命令的輸出中給出的URL上了。 在我的案例中,URL是https://flask-microblog.herokuapp.com,所以這就是我需要鍵入和訪問該應用程序的URL。

如果你想查看正在運行的應用程序的日誌,請使用heroku logs命令。 如果由於任何原因導致應用程序無法啓動,該命令可能很有用。 如果有任何錯誤,將在日誌中顯示。

部署應用更新

要部署新版本的應用程序,只需要使用git push命令將新的代碼庫推送到Heroku即可。 這將重複部署過程,關停舊部署,然後用新代碼替換它。 Procfile中的命令將作爲新部署的一部分再次運行,因此在此過程中將更新任何新的數據庫遷移或翻譯內容。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章