一種部署 Python 程式碼的新方法
在Nylas,我們喜歡使用Python進行開發。它的語法簡單並富有表現力,擁有大量可用的開源模組和框架,而且這個社群既受歡迎又有多樣性。我們的後臺是純用 Python 寫的,團隊也經常在 PyCon 和 meetups 上演講。你可以認為我們是 Python 的超級粉。
然而,Python 的一個大缺陷是沒有一個明確的工具來部署 Python 服務端應用。工作的情況就像是“執行 git 的 pull 命令後剩下的就只有祈禱了”,但這並不是一個好的方式,尤其當用戶依賴於我們的應用。當你的應用引用了很多仍在變化的依賴時,這會讓 Python 的部署工作變得更加複雜。下面 HN 上的評論概括了 Python 部署的糟糕情況。
為什麼這麼多年了,仍沒有一個有效的辦法幫我將 Python 編寫的軟體轉換成 deb 格式?
—— 來自一個受挫的 HN 使用者
在 Nylas,我們開發了一種更好的方法可以將 Python 程式碼連同其依賴一起部署,使得我們能夠輕鬆地對輕量級包進行安裝、升級或者刪除。該方式的實現並不需要將我們的整個棧遷移到像 Docker、 CoreOS 或者AMIs 這樣的系統上。
新手才用 GIT 和 PIP 進行 Python 部署
Python 提供了豐富的模組。不管你搭建的是一個web 伺服器還是機器學習分類器,總會有一個合適的模組幫你啟動專案。現在獲取這些模組的標準方法是通過 pip 從 Python 包索引 (亦稱 PyPI)中下載和安裝。這就跟 apt,yum,rubgem 等命令操作是一樣。
大多數人搭建開發環境的第一步就是用 git 克隆份程式碼,然後通過 pip 安裝其依賴。這也是大多數人第一次嘗試部署程式碼的做法。部署指令碼大致如下:
Shell1234 | git clonehttps://github |
但是當部署大量生產服務時,這種策略有下面幾個原因可能導致失敗:
PIP 並沒有提供“部署回滾”策略
pip unistall
並不是每次都能正常工作,也沒有辦法“回滾”到上一個狀態。雖然可以用Virtualenv 實現,但它並不是用來管理歷史環境的。
用 pip 安裝依賴會讓部署變得極其慢
使用pip install 來安裝一個由C語言編寫的模組經常需要從原始碼進行編譯,對於一個新建立的virtualenv環境,這將花費幾分鐘的時間。但部署應用應該是一個以秒計算的快速而輕量的過程。
在每臺主機上分別構建程式碼會有一致性問題
當你使用 pip 部署時,無法保證不同伺服器上執行的應用版本是一致的。構建過程或現有依賴中的錯誤導致的不一致,這是很難去除錯的。
如果 PyPI 或者你的 git 伺服器掛掉會導致部署失敗
pip install
和 git pull
通常依賴於外部伺服器。你可以選擇使用第三方平臺 (如 Github,PyPI)或者自己搭建伺服器,重要的是確保部署過程滿足正常執行時間和規模的預期。當擴充套件自己的基礎設施,尤其是在大型部署時,外部服務往往是第一個掛掉的。
如果你在運營一個人們依賴的應用系統,而且它又是部署在多個伺服器上,那麼採用 git + pip 部署策略只會讓你更加頭痛。我們需要的部署策略應該是快速的、一致而且可靠的。更具體地說:
- 能夠構建程式碼成單一、有版本控制的工件
- 受版本控制的工件可以進行單元測試和系統測試
- 一種簡單的機制可以從遠端主機完全的安裝或解除安裝工件
有了這三樣東西可以讓我們將更多的時間花在功能的構建上,以更少的時間進行程式碼一致性遷移。
“乾脆用DOCKER吧”
初看下,這似乎最適合用 Docker 了,Docker 是當前盛行的容器管理工具。在一個 Dockerfile裡,只要簡單地新增程式碼倉庫的引用,安裝必要的庫和依賴。那麼我們就建好 Docker 映象,將它作為受版本控制的工件發往到遠端主機。
然而,當我們嘗試這樣操作時遇到了幾個問題:
- 我們的核心版本 (3.2)並不完美支援 Docker,如果為了更快的遷移程式碼而升級核心,我們覺得這有點像在用牛刀殺雞。
- 在專用網路裡分發 Docker 映象要有一個獨立服務,這樣我們又需要對服務進行配置,測試和維護。
- 將 ansible 自動化安裝轉換成 Dockerfile 的過程是痛苦的,需要對日誌配置、使用者許可權和祕鑰管理等進行大量繁瑣的編輯。
即便我們順利的解決了這些問題,為了除錯生產上的問題,我們的工程師團隊又不得不學習如何跟 Docker 連線互動。我們認為更快地遷移程式碼並不應該重新執行整個基礎架構自動化和編排層。所以我們繼續調查其他方案。
PEX
PEX 是 Twitter 開發的一個智慧工具,它允許 Python 程式碼以可執行壓縮檔案進行傳送。這是一個很酷的想法,關於這個主題我們建議去看Brian Wickman 在推特大學的演講。
設定 PEX 比 Docker 還簡單,因為他只需要執行生成好的可執行壓縮檔案,但是構建 PEX 檔案卻是一項巨大的工程。我們在構建第三方庫需求時遇到問題,特別是當中包含了靜態檔案。我們也遭遇到 PEX 原始碼產生的混亂的堆疊跟蹤,使得除錯工作變得更加困難。這是個異份子,因為我們主要目標是改善工程效率,讓事情更加易懂。
使用 Docker 會增加執行時的複雜度。而 PEX 會增加構建時的複雜度。我們需要一個方案可以最小化整體複雜度,同時提供可靠的部署,所以我們繼續調查其他方案。
包:原始的“容器”
幾年前,Spotify 悄悄釋出了一個工具叫 dh-virtualenv,你可以用來構建內含 virtualenv 的 debian 包。我們覺得這很有意思,也已經有了很多 Debian 相關經驗並在生產環境上執行。(Christine,我們的聯合創始人之一,就是一個 Debian 的開發者。)
用dh-virtualenv
可以很簡單的建立一個 debian 包,它包含了 virtualenv 和羅列在requirement.txt 檔案裡的所有依賴。當在主機上安裝這個 debian 包時, 它會將 virtualenv 放置在/usr/share/pyton/
路徑下。就是它了。
這就是我們在 Nylas 上部署程式碼的關鍵。我們的持續整合伺服器 (Jenkins) 執行 dh-virtualenv 來構建包, 用 Python 的wheel 快取來避免對依賴重新構建。這就建立一個捆綁式工件(debian 包),然後對其進行大量的單元測試和系統測試。如果通過測試,則可認為生產上是安全的,可以上傳到 s3.
這個過程的關鍵部分是通過均衡 Debian 的內建包管理器 dpkg,我們可以最小化部署指令碼的複雜度。部署指令碼大致如下:
Shell1234 | temp=$(mktemp/tmp/deploy.deb.XXXXX)curl“https://artifacts.nylas.net/sync-engine-3k48dls.deb”-o$tempdpkg-i$tempsv reload sync-engine |
要回滾的話,我們只需要部署上一版本的工件。dpkg 工具可以免費幫你清除舊程式碼。
這個策略最重要的一方面是它實現了一致性和可靠性,同時匹配了我們的開發環境。我們的工程師已經在用virtualenv,而dh-virtualenv 只是一個將其遷往遠端主機的方式。如果我們選擇 Docker 或者 PEX,明顯需要改變我們本地開發的方式又增加了複雜度。我們同樣不希望給使用我們開原始碼的開發者帶來複雜度負擔。
現在,我們用 Debian 包來遷移我們所有的 Python 程式碼。完整構建我們程式碼庫(包含數十個依賴)只要不到2分鐘時間,部署更是數秒便完成。
DH-VIRTUALENV 入門
如果你受夠了 Python 部署的折磨,那就試試 dh-virtualenv吧。它會是你不錯的選擇!
配置 Debian 包對於初學者而言是棘手的,所以我們構建了 make-deb 工具來幫你入手。它會基於你 Python 專案裡的 setup.py 檔案生成 Debian 配置。
首先安裝make-deb
工具,然後在你專案的根目錄下執行它:
123 | cd/my/projectpip install make-debmake-deb |
如果你的 setup.py 檔案有缺失資訊的話,make-deb
會要求你新增。一旦它收齊所需的資訊,make-deb
會在你專案的根目錄下建立一個 debian 目錄,包含了 dh-virtualenv 需要的所有配置。
構建 Debian 包需要你在裝有 dh-virtualenv 的 Debian 系統上進行。如果你沒有 Debian 環境,我們建議你在 Mac 或者 Windows 上用 Vagrant 和 Virtualbox 安裝一個 Debian 的虛擬機器。你也可以參考我們放在 Git 倉庫下 sync-engine 專案裡的Vagrantfile 來作配置。
最後,執行dpkg-builpackage -us -uc
來建立 Debian 包。你不需要直接呼叫 dh-virtualenv,因為它已經在之前make-deb
建立好的配置規則裡了。當這條命令執行好後,你就構建好一個可部署的漂亮的工件。
一段簡單的部署指令碼如下:
Shell12345678 | scp my-package.debremote-host.example.org:ssh remote-host.example.org# Run the next commands on remote-host.example.orgdpkg-imy-package.deb/usr/share/python/myproject/bin/python>>>import myproject# it works! |
部署時,你需要將這個工件上傳到生產伺服器上。執行dpkg -i my-package.deb
命令來安裝。virtualenv 會被放在/usr/share/python/
目錄下,所有預設在 setup.py 檔案裡的指令碼檔案則會在bin
目錄裡。就是它了!你這就走上了簡易部署的光明大道。
總結
在構建大型系統時,專案難點往往是在尋求合適的工具,而非從頭開始重構一個新的系統。我們認為使用 Debian 基於包的部署是部署 Python 應用的一個極佳方案,最重要的是它可以幫我們平穩而快速的遷移程式碼。
請聯絡我們,如果你有任何的意見或建議,又或者是覺得這篇文章很有意思。感謝你閱讀這篇文章!
打賞支援我翻譯更多好文章,謝謝!
打賞譯者
打賞支援我翻譯更多好文章,謝謝!
任選一種支付方式
相關推薦
一種部署 Python 程式碼的新方法
在Nylas,我們喜歡使用Python進行開發。它的語法簡單並富有表現力,擁有大量可用的開源模組和框架,而且這個社群既受歡迎又有多樣性。我們的後臺是純用 Python 寫的,團隊也經常在 PyCon 和 meetups 上演講。你可以認為我們是 Python 的超級粉。 然而
Qt之自定義搜索框——QLineEdit裏增加一個Layout,還不影響正常輸入文字(好像是一種比較通吃的方法)
too 步驟 set box 文本 csdn sub void 鼠標 簡述 關於搜索框,大家都經常接觸。例如:瀏覽器搜索、Windows資源管理器搜索等。 當然,這些對於Qt實現來說毫無壓力,只要思路清晰,分分鐘搞定。 方案一:調用QLineEdit現
數據庫查詢速度慢了?是否是因為死鎖了?一種解決死鎖的方法。
-- 檢索 blog kill _id exe 進行 xxx 通過 --查詢哪些表被死鎖 select request_session_id spid,OBJECT_NAME(resource_associated_entity_id) tableName from sy
一種基於python的人臉識別開源系統
無意中 sdn 要求 測試用例 不出 例子 https bin 人臉識別 今天在搜索人臉識別的文章時,無意中搜到一個比較開源代碼,介紹說是這個系統人臉的識別率 是比較高的,可以達到:99.38%。這麽高的識別率,著實把我嚇了一跳。抱著實事求是的態度。個人 就做了一些驗證
排序_快速排序_另一種取劃分點的方法
交換 ++ new 改進 break value 進行 ins man 最基本的劃分點由數組的最後一個值來確定,現在是將數組的最後一個值的前一個數值作為劃分點,但是需要經過三項取一方法的變換,最後它位置上的值是三個中最大的。 public class ArrayIns {
insert into 的另一種添加插入新行方式
value insert lang sharp 實例 tab 多行 mon brush 語法 1 插入一行 insert into table (field1,field2.....) select value1,value2........; 2 插入多行
機器不學習:一種提升預測能力的方法-機器學習模型
範圍 和集 最重要的 機器 免費 現實 良好的 例子 永恒 機器不學習 jqbxx.com -機器學習好網站 沒有哪個機器學習模型可以常勝,如何找到當前問題的最優解是一個永恒的問題。 幸運的是,結合/融合/整合 (integration/ combinat
Kossel的一種滑塊位置計算方法
定義 運行 pos 平面 當前 並不是 post then 傳感器 做了一個小激光雕刻機之後,研究了一下這款3D打印機的結構和工作原理,一下就對這個運動過程很感興趣,這三個桿是怎麽聯動使得噴頭保持在一個平面上運動呢?打算先做一個架構,然後把激光器放在上面不是
一種生成動態口令的方法
JavaScript 動態口令 'use strict' let MD5 = require('blueimp-md5'); let UUIDv1 = require('uuid/v1'); const T = 30; let secret =
一種高效的QPS統計方法
循環數組 eset 指數 yun return hashmap await spa 全面 一、概述 對QPS的統計,通常是對一秒內各線程通過數據處理鏈中某一個切入點的次數進行累加計數。且不論采用何種方式都繞不開鎖,那如何結合QPS統計的場景,減少線程之間對鎖的競爭,是各實現
180720_一種有效的日期計數方法
2個 class 元素 年月日 ++ 多重 月份 存儲 lin 最近在學習C#,昨天老師布置了一個作業,輸入年月日,返回這一天是一年中的第幾天。 大致分析了一下,想出了一種方法,大致思路如下: 使用 switch 檢測月份得出該月長度; 根據年份決定二月長度;
數獨問題的一種簡單演算法程式碼實現
五一期間無聊時想起去年考研複試有一道上機題目當時沒作出來,於是一時興起想重新拾起看看是當時太緊張,還是自己能力不足。然後發現這道題目還真稍微有些難度,相當於一道數獨問題(sudoku)的簡化版。自己想來想去也只能想到兩種演算法,一種是拿剩餘元素做全排列測試,一種是回溯法測試。最後只實現了一個全排
一種快速卷積實現方法
本文基於論文Fast Algorithms for Convolutional Neural Networks,並且整理了相關知識點。 我們首先了解一下傅立葉變換: 對於連續型傅立葉變換的頻域核時域轉換公式: 對於離散的傅立葉變換: 關於傅立葉的理解 可以看這篇文章
【模式識別與機器學習】——3.9勢函式法:一種確定性的非線性分類方法
目的 用勢函式的概念來確定判別函式和劃分類別介面。 基本思想 假設要劃分屬於兩種類別ω1和ω2的模式樣本,這些樣本可看成是分佈在n維模式空間中的點xk。 把屬於ω1的點比擬為某種能源點,在點上,電位達到峰值。 隨著與該點距離的增大,電位分佈迅速減小,即把樣本xk附近空間x點上的電位分佈,看
一種呼叫dll的巧妙方法
直接上程式碼,後面說應用場景 新建一個專案,引入需要呼叫的dll,如下 class Program { [DllImport( "soft.dll" )] static extern int CreditTrans( StringBuilder strin,
SWA(隨機權重平均)——一種全新的模型優化方法
這兩天被朋友推薦看了一篇熱乎的新型優化器的文章,文章目前還只掛在arxiv上,還沒發表到頂會上。本著探索的目的,把這個論文給復現了一下,順便彌補自己在優化器方面鮮有探索的不足。 論文標題:Averaging Weights Leads to Wider Optima and Better Gen
Python - 除錯Python程式碼的方法
除錯(debug) 將可疑環節的變數逐步打印出來,從而檢查哪裡是否有錯。 讓程式一部分一部分地執行起來。從核心功能開始,寫一點,執行一點,再修改一點。 利用工具,例如一些IDE中的除錯功能,提高除錯效率。 Python CM
一種稀疏矩陣的實現方法
本文簡單描述了一種稀疏矩陣的實現方式,並與一般矩陣的實現方式做了效能和空間上的對比 矩陣一般以二維陣列的方式實現,程式碼來看大概是這個樣子: // C# public class Matrix { // methods // elements
SpringBoot的事務中一種奇怪問題以及處理方法
Transaction註解在Spring中是事務,事務呢,簡單來說,就是放在一起的一組SQL操作。 那麼事務和普通的SQL有什麼不太一樣的地方呢? 原子性 (要麼全做,要麼不做) 一致性 (事務中的資料要一致,在有些時候是會出現不一致的情況的) 永續性 (這
怎麼通過郵箱發超大附件?介紹一種基於雲服務的方法
合作伙伴第5次催促時,10G的CAD圖紙才傳了67%;又一次,寫好郵件上傳附件時,被通知檔案太大無法上傳;郵件傳送出去的會議資料,永遠不知道誰沒有檢視,還要電話通知一遍…… 工作中,你肯定遇到過上述類似的情況。檔案太大、傳輸緩慢、無法跟蹤檔案狀態,再加上懸在頭頂的deadline,隨便一種情況都足以讓我們焦