[toc] ## The Twelve-Factor App - A methodology to build a better SaaS app | | | | -------- | -------- | |  |  | > 2022/10/31 updated 更棒的整理:[[Architecture] The 12 factor App 筆記](https://marcus116.blogspot.com/2020/09/architecture-12-factor-app.html) >  如今,軟體通常會作為一種服務來交付,它們被稱為網路應用程式或軟體即服務(SaaS)應用。12-Factor 為想要實現以下目標的 SaaS 應用提供了方法論: - 使用***聲明式***的自動化配置,從而使新的開發者花費最少的學習成本加入這個項目 - 和作業系統之間盡可能的劃清界限,在各個系統中提供最大的可移植性 - 適合部署在現代的***雲端平台***,從而在伺服器和系統管理方面節省資源 - 將***開發環境***和***產品環境***的差異降至最低,使得持續交付的方法得以實施以最大化敏捷開發 - 可以在工具、架構和開發流程不發生明顯變化的前提下***實踐擴展*** :::info - 原文: https://12factor.net/ - 簡中: https://12factor.net/zh_cn/ ::: 當我們在替 application 維運時,很容易碰到了一些問題。我發現常見的問題與其中 6 個原則很有關係,故摘要它們出來: - I. Codebase - III. Config - IV. Backing services - VI. Processes - VIII. Concurrency - X. Dev/prod parity 這些原則與觀念將有助於我們在設計開發階段想得更清楚,讓你的 app 更適應雲平台的部署與維運方式。 ### [I. Codebase](https://12factor.net/codebase)  - 程式碼應該要在不同的 deploys 之間保持一致 (local development environment 也是一種 deploy) - 故如果程式碼內部出現以下這種邏輯,應就得視你的 app 為不一致的: ``` if env==dev: read ENV_URL_FOR_DEV; else if env==prod: read ENV_URL_FOR_PROD; ... if env==dev: use ENV_URL_FOR_DEV do somwthing else if env==prod: use ENV_URL_FOR_PROD do somwthing ``` - 上述的邏輯將導致每增添一種 deploy,就得顯示地去改動 source code 以滿足特定環境所需 - 應同時考慮 ***III. Config*** 談論的原則,**讓環境 (configurations) 來決定 app 的行為、而不是讓 app 感知環境後做出意料之外的行為** ### [III. Config](https://12factor.net/config) :::success :bulb: 每一種環境的部署,對於周邊環境的需求總是不確定的。你無法保證未來新業務所需的環境能夠套用過去的經驗。 ::: - 應利用「環境變數」儲存 config,因為「環境變數」可以很方便地在不同環境中做出改變、且不用改動任何一行 code。 :::success :bulb: 使用環境變數作為引入配置的手段為第一優先。都使本地開發與各環境部署更加簡潔。 只有極少數的需求會強迫透過載入檔案的方式來取得配置。就算有這種例外,「檔案的路徑」也需要設計成能夠透過環境變數給予。 一樣,你無法掌握部署環境的 file system 的全貌,故將職責交給部署的人去明確指定該檔案的位置即可。 ::: - 你可能會想要**將環境變數做出組別** (`development`, `test`, `production`),但你很快就會發現這方法不 sacle,你會**疲於管理**多種部署環境的排列組合 (i.e. `staging`, `ga`, `joes-staging`)。所以**不要這樣做**。 - 其實**只要環境變數切得夠細、不彼此依賴**,讓負責部署的人根據該環境需求,管理要如何給定參數即可。 :::info :information_source: 那我們目前「部署的人」是如何管理環境變數的差異? :point_right: [sa/manifests](https://gitlab.smart-aging.tech/sa/manifests) ::: ### [IV. Backing services](https://12factor.net/backing-services)  - 所謂的 *backing service* 是指那些需要透過 network 溝通取得資源後,才能讓你的 app 有 normal operation 表現的 services。並將這些 services 視為一種資源 (resources) - 這些 service 理論上都是透過給定 URL 來連接、存取,並使用 ***III. Config*** 提到的方式來儲存 - e.g. 利用 config 來儲存,你可以很輕易地讓 app 連向 local 環境的 resource 或其他第三方的 resource ### [VI. Processes](https://12factor.net/processes) - 在有了 ***IV. Backing services*** 這樣的原則為前提,一個 12-factor app 會進一步實踐 ***stateless*** and ***[share-nothing](https://en.wikipedia.org/wiki/Shared-nothing_architecture)*** 的架構 - 另外,app 可能依賴於 [sticky sessions](https://en.wikipedia.org/wiki/Load_balancing_%28computing%29#Persistence) 的設計,我們要知道它其實是違反 12-factor 精神的 (文中建議是使用 Redis/Memcached 等方式來嘗試解耦) ### [VIII. Concurrency](https://12factor.net/concurrency)  - 若服務吞吐量不足,優先考慮 **Scale out via the process model** :::success - 對我們來說,就是 app 得做好 stateless 的準備,然後使用 K8S 的 [Horizontal Pod Autoscaler](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) 自動做 scale out - 當然,也會迫使我們在設計服務時,就先想清楚對 DB 做出併發請求是否會產生「業務邏輯上的 race conditions」 (e.g. [read phenomena](https://en.wikipedia.org/wiki/Isolation_(database_systems)#Read_phenomena)) ::: ### [X. Dev/prod parity](https://12factor.net/dev-prod-parity) > 開發/產品等價 - 大部分的人,在有越多的開發經驗後皆會感同身受: 1. app 在 development, staging, production **環境之間有差異的時間越久**,在 production 的環境上越容易出問題 2. **開發與維運的人員差異**,容易造成部署後出問題 3. 本地開發環境與線上環境使用的 **tech stacks 不同** (e.g. SQLite vs. MySQL),造成問題 - 而 12-factor 的精神會希望一個 app: 1. 採用 [Continuous Deployment](https://en.wikipedia.org/wiki/Continuous_deployment),儘可能縮小 development 與 production 的差異 2. 盡可能**開發與維運合一** (i.e. **我開發、我維運的主人翁精神**) 3. 盡可能本地開發與線上環境使用**相同的 tech stacks**  :::success :bulb: 實務上,針對這部分,我都使用: 1. [Docker](https://www.docker.com/) 直接運行與線上環境相同的 teck stack 2. 運用 Makefile 模擬 app 運行的環境。事先定義好環境變數讓 app 讀取並運行 (*[Makefile Tutorial By Example](https://makefiletutorial.com/)*) :::
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up