Heroku 大逃殺之 Fly.io
![](https://assets.matters.news/embed/350da51e-6bf8-4dcf-95dc-f7a216546885.png)
Heroku 打算在 2022 年 11 月 28 終止所有免費服務,我輩免費仔只能付費升級,或是搬家,既然是免費仔,付費升級就不是個選項,要搬家的話,新家的選擇大概有這些:
- Render
- Fly.io
- Northflank
- Koyeb
- Deta
- Qoddi
- Cyclic.sh
- Railway
這篇記錄了搬家到 Fly.io 的過程。
Fly.io
Heroku、Fly.io 以及前面列的一大堆服務,都可以概括為 serverless 服務,更精確的分類是 PaaS,其中的 P 為 platform,所謂 platform 表示語言/框架的複合意義,PaaS 的優勢在於我們不用去管理更底層的 infrustructure,也就是硬體層、OS 層、web server 層都無須操心,由 PaaS 業者自理。
Fly.io 的特色個人認為有二:
- 有東京節點,離台灣較近,速度當然也比較快囉!
- 初階費率低廉,雖然本人是免費仔,還是要考慮付費時的費率方案,以 Fly.io 單一共享 CPU 的費率來看,還是頗便宜的。
![](https://assets.matters.news/embed/8880b542-9f7a-4057-b078-ba2cf5bb1bed.png)
前置作業
第一步當然是開帳號,眼睛閉閉帳號開一開之後,與 Heroku 類似,要裝 Fly.io 的 CLI 工具。
如果是 Windows,不需要 Administrator 權限,開 PowerShell 執行此命令:
$ iwr https://fly.io/install.ps1 -useb | iex
裝好就登入吧:
$ flyctl auth login
至此前置作業告一段落,後面我們進入專案目錄配置 Fly.io 設定。
建立 Fly.io App
我們這整個專案對 Fly.io 來說就是一套 app,最基本的 app 裡面大概會跑一個 web 服務,稍微複雜一點的大概會多跑一個 database 服務,在本文的範例中,我們只有一個 web 服務。
先初始化一個 Fly.io app:
$ flyctl launch
上面的子命令為 launch
,但它其實只是產生配置檔而已,並沒有真的 launch 什麼。
跑起來會跳出一些資訊還有問題:
Detected a Python app Using the following build configuration: Builder: paketobuildpacks/builder:base ? Overwrite "C:\Users\leonh\Projects\katsuyo-backend\Procfile"? Yes ? App Name (leave blank to use an auto-generated name): katsuyo ? App Name (leave blank to use an auto-generated name): katsuyo ? Select organization: Katsuyo (katsuyo) ? Select region: nrt (Tokyo, Japan) Created app katsuyo in organization katsuyo Wrote config file fly.toml ? Would you like to set up a Postgresql database now? No We have generated a simple Procfile for you. Modify it to fit your needs and run "fly deploy" to deploy your application.
整理如下:
- 自動偵測到這是個 Python 專案。
- 要改寫 Procfile 嗎?Yes(反正有版控不怕不怕)。
- 幫這個 Fly.io app 取名字。
- 選定要放在 Fly.io 的哪個組織下,每個 Fly.io 帳號都有一個自己的「Personal」組織,當然也可以另外創建更多組織,本例的組織就是另外創的 Katsuyo,這樣感覺事業做比較大,比較唬人。
- 要放在哪個機房,東京應該是首選。
- 以上設定都寫入 fly.toml 和 Procfile,還沒真正部署,可以再改。
- 最後一題,要設定 PostgreSQL 嗎?不用。
- 最後提示我們用
fly deploy
部署,不過最好先檢查一下配置再說。
先看 Procfile:
# Modify this Procfile to fit your needs web: gunicorn server:app
格式和 Heroku 相同,印象中這是來自某個開源專案的通用格式,但是是哪個忘記了。
它幫我們配置了用 Gunicorn 來跑專案,但在這裡的範例專案中用的是 Uvicorn,所以改一下:
# Modify this Procfile to fit your needs web: uvicorn app.main:app --host 0.0.0.0 --port 8080
此處設定 Uvicorn 與參數:
- 指定了 Python ASGI 程式進入點,這部分請根據自身專案而改。
- 不綁定任何 IP,因為我們不知道,也不需要知道 Fly.io 給的 IP 是什麼。
- 監聽 8080 埠,因為在 fly.toml 中,預設配置就是把 HTTP、HTTPS 請求送到機台內的 8080 埠。
Procfile 的部分告一段落,來看看 fly.toml 吧:
# fly.toml file generated for katsuyo on 2022-08-27T11:38:16+08:00 app = "katsuyo" kill_signal = "SIGINT" kill_timeout = 5 processes = [] [build] builder = "paketobuildpacks/builder:full" [env] PORT = "8080" [experimental] allowed_public_ports = [] auto_rollback = true [[services]] http_checks = [] internal_port = 8080 processes = ["app"] protocol = "tcp" script_checks = [] [services.concurrency] hard_limit = 25 soft_limit = 20 type = "connections" [[services.ports]] force_https = true handlers = ["http"] port = 80 [[services.ports]] handlers = ["tls", "http"] port = 443 [[services.tcp_checks]] grace_period = "1s" interval = "15s" restart_limit = 0 timeout = "2s"
此處多數的配置可以望文生義,其中幾行要關注一下:
- 前面提過的
internal_port = 8080
指定了 Python app 應該監聽 8080 埠。 - 那
[env]
區塊內的設定,是讓 app 可以讀取到系統內的環境變數,可隨喜配置。 builder = "paketobuildpacks/builder:base"
指定了運作時的容器映像,預設的base
沒有 C 函式庫,本範例中的 Python 剛好有需要 SQLite,libsqlite3.so.0 是一定要的,所以得改為paketobuildpacks/builder:full
。這部分詳細說明參閱 Paketo Buildpack 文件。
fly.toml 的其他部分先擱著,以現有的設定部署看看:
$ flyctl deploy
可以看到一堆嘰哩呱啦訊息,大部分是層層容器映像下載和部署的訊息。
如果一切沒問題,應該跑完就上線了,恭喜,灑花,轉圈圈!
但實際上不會這麼順利,否則我早就財富自由了。通常初次部署都會遇到各種疑難雜症,只能根據部署丟出的錯誤訊息來一一排除囉!
以我手上的範例專案來說,它就需要安裝字體,無奈 Fly.io 用的 builder / buildpack 架構下似乎沒有夠簡單的方法能讓我跑 apt install fonts-noto-cjk
,所以雖然部署成功,但其中字體的顯示卻是異常的,殘念。
CLI 常用命令
看當前專案 app 資訊
$ flyctl info
可以看到當前專案 app 的諸元:
App Name = katsuyo Owner = katsuyo Version = 3 Status = running Hostname = katsuyo.fly.dev Services PROTOCOL PORTS TCP 80 => 8080 [HTTP] 443 => 8080 [TLS, HTTP] IP Adresses TYPE ADDRESS REGION CREATED AT v4 168.220.91.169 11h34m ago v6 2a09:8280:1::1:657d 11h34m ago
另一個類似的命令:
$ flyctl status App Name = katsuyo Owner = katsuyo Version = 3 Status = running Hostname = katsuyo.fly.dev Platform = nomad Instances ID PROCESS VERSION REGION DESIRED STATUS HEALTH CHECKS RESTARTS CREATED 6bcb55a9 app 3 nrt run running 1 total, 1 passing 0 6h7m ago
個人認為這兩個命令大可合併,或作為彼此的替身。
看 log
$ flyctl logs
當然就是看專案即時 log 啦!
結語
簡單的試用一下 Fly.io,初步的感受是配置有點繁雜,那 fly.toml 看起來好像很厲害,但本人更愛好像 Netlify / Vercel 那樣的傻瓜配置,如果 PaaS 還要搞那麼多配置那不如回到 IaaS 自己搭架構就好,想單體就單體,想微服務就微服務,爽快。