iT邦幫忙

2024 iThome 鐵人賽

DAY 25
0
Software Development

做一支專屬自己學校的課程評價 LINE Bot 吧!系列 第 25

[Day 25] Django 部屬至 Heroku 的前置準備

  • 分享至 

  • xImage
  •  

部屬需要處理的事兒

當開發環境 (本機端) 要放上雲端成為正式環境時,會需要處理資料庫以及網頁伺服器 (Web Server) 兩大問題: 資料庫因為使用者不會再透過自己電腦取資料,需要於雲上建立一個新的雲端資料庫。網頁伺服器則是扮演幫助 Python 與接收前端伺服器 (能簡單理解為使用者),所轉發的動態請求的中間溝通角色:

最左邊 Client 指的是使用者瀏覽/使用機器人,最右邊 Django 則是我們所編寫的程式,可以發現中間還會經過兩道 Web Server,而我們需要處理位於 Django 與 Nginx 之間的 Web Server,圖示中 Nginx 的 Web Server 則會由 Heroku 協助代勞 (實務上 Heroku 並非使用 Nginx,但邏輯類似)。如果你對 WSGI 有興趣可以到 這裡,圖片來源也是來自此

在繼續之前,需要先完成以下步驟與具備下列知識

  • 已將專案推送至 GitHub Repo
  • 已經註冊好 Heroku 並安裝完 Keroku CLI

定義需求

  • 準備要將專案放到正式環境的文件

編寫邏輯

1. 安裝套件與輸出 requirements.txt

以下步驟執行前記得啟動虛擬環境:

  • 安裝雲資料庫與網頁伺服器套件
    有別於本地端所使用的資料庫為 SQLite,Heroku 所使用的資料庫為 PostgreSQL,我們需要在requirements.txt 加上 psycopg2 ,其能協助 Python 操作連結 PostgreSQL;以及加上 gunicorn 網頁伺服器套件,Heroku 主要依靠它建置網站:
    在虛擬環境中輸入:

    $ pip install psycopg2
    
    $ pip install gunicorn
    
  • 安裝靜態檔案處理套件
    比起動態的 Python 渲染網頁,靜態檔案 (HTML、CSS、JS) 存取頻率高,容易造成網頁伺服器負擔,所以會將其分開放置、壓縮與運行,在這裡可以安裝 WhiteNoise,協助我們處理靜態文件:

    $ pip install whitenoise 
    
  • 安裝資料庫環境變數處理套件
    在處理環境變數的資料庫配置時,可以透過 dj_database_url 工具將資料庫的 URL 字串(如 DATABASE_URL)轉換為 Django DATABASES 設置中需要的 Python 字典格式,讓 Django 可以使用,簡單來說是一個可以幫助我們處理資料庫環境變數的套件。

    $ pip install dj_database_url
    
  • 最後輸出 requirements.txt
    在虛擬環境中與 hulolo 同層資料夾的指令輸入:

    $ pip freeze > requirements.txt
    

    這個動作可以將所有虛擬環境中的套件名稱與版本輸出,並且存成一在名為 requirements.txt 檔案中,Heroku 會識別此檔案進行套件安裝,建置環境在雲上。

2. 新增 Procfile 檔案告訴 Heroku 如何運行網頁伺服器

需要編寫一個新檔案告訴 Heroku 應該如何執行網頁伺服器,我們在與 hulolo 同層資料夾的地方新建一個檔案名為Procfile,內容輸入:

# hulolo > Procfile

web: gunicorn --pythonpath hulolo hulolo.wsgi --log-file -

如果專案名稱與教學文不同記得要更改哦。

3. 調整 settings.py 參數

  • 調整部屬網域 ALLOWED_HOSTS
    將其調整為自環境變數取值,ALLOWED_HOSTS 是一個安全參數,標示哪些網域名稱可以訪問 Django 應用程式。它的主要作用是防止 HTTP Host 標頭攻擊(Host Header Attack)。

    # hulolo > hulolo > settings.py
    ALLOWED_HOSTS = os.getenv("ALLOWED_HOSTS", "").split(",")
    

    因正式與開發環境的網址名稱不同,原先的 ALLOWED_HOSTS 可以將其註解或移除,改由環境變數取值,而環境變數套件dotenv因無法讀取陣列 (array),這邊以 split()轉換為列表,相對的,在 env 檔案中請添加 ALLOWED_HOSTS = 127.0.0.1,a1fa-119-14-201-163.ngrok-free.app

  • 調整資料夾路徑 DATABASE_URL
    要讓程式可以辨識現在是本地端的資料庫還是雲端,可以加上判斷式進行處理,如果環境變數中有 DATABASE_URL 則認為在 Heroku 正式環境上。

    # hulolo > hulolo > settings.py
    
    import dj_database_url
    
    DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
    }
    # 如果有 DATABASE_URL 這個環境變數,則使用它覆蓋預設的資料庫類型
    DATABASE_URL = os.environ.get("DATABASE_URL")
    if DATABASE_URL:
        DATABASES["default"] = dj_database_url.config(default=DATABASE_URL, conn_max_age=600)
    
  • 調整態檔案 MIDDLEWARE、STATIC_ROOT
    在這邊我們要將 WhiteNoise 套件引入並放到中間層協助處理靜態檔案,並且建立一個存放這些檔案的資料夾 static,加上 STATICFILES_STORAGE 後讓 WhiteNoise 將壓縮後的靜態檔案進行處理。

    # hulolo > hulolo > settings.py
    MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware',  
    # 加上 WhiteNoise Middleware
    # 其他的 middleware...略
    ]
    # 設定 static 靜態檔案的根目錄
    STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')  
    # 啟用壓縮與緩衝存取的控制
    STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'  
    
  • HTTPS 處理
    現今主流網站必須使用 HTTPS 通訊協定,在這邊我們也需要對正式環境做處理:

    # hulolo > hulolo > settings.py
    _secure_proxy_ssl_header = os.getenv("SECURE_PROXY_SSL_HEADER")
    if _secure_proxy_ssl_header:
        SECURE_PROXY_SSL_HEADER = tuple(_secure_proxy_ssl_header.split(","))
        SESSION_COOKIE_SECURE = os.getenv("SESSION_COOKIE_SECURE")
        CSRF_COOKIE_SECURE = os.getenv("CSRF_COOKIE_SECURE")
        SECURE_SSL_REDIRECT = os.getenv("SECURE_SSL_REDIRECT")
    

4. 調整 manage.py

由於 Heroku 雲端並不需要 .env 文件,透過後台直接設定環境參數,這裡我們要將 manage.py 調整為當偵測到環境變數 DJANGO_ENV 不是 production (即正式環境時),才去執行 otenv.read_dotenv()

# hulolo > manage.py

if __name__ == '__main__':
    # 檢查環境變數來區分開發和生產環境
    if os.getenv('DJANGO_ENV') == 'production':
        print("PRODUCTION")
    else:
        # 如果不是生產環境,讀取 .env 文件
        dotenv.read_dotenv()
        print("DEV")

    main()

關於 Heroku 的環境變數 DJANGO_ENV 如何設定會在下一篇說明。

再往前一點點

  • 因為有判斷式的關係,不需要在本地端的 .env 加上 DATABASE_URLSECURE_PROXY_SSL_HEADER,甚至是SESSION_COOKIE_SECURECSRF_COOKIE_SECURESECURE_SSL_REDIRECT 也不需要設置,因為預設即為 False,而我們在本地所使用的網址為 HTTP 非 HTTPS。

覆盤

在這篇文章中,我們學會了:

  • 部屬的意義與架構
  • 部屬所需的套件 (資料庫、網頁伺服器、資料庫環境變數、靜態檔案處理)
  • 調整 settings.py 參數與環境變數
  • Day 25 原始碼

上一篇
[Day 24] 透過學生專案部屬 GitHub 與 Heroku SaaS 平台
下一篇
[Day 26] Heroku 創立專案、環境變數設定與正式部屬
系列文
做一支專屬自己學校的課程評價 LINE Bot 吧!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言