使用Docker部署Python應用的一些最佳實踐

jopen 9年前發布 | 39K 次閱讀 Docker

本篇文章源自作者團隊在長期開發過程中總結的寶貴經驗,其中Supervisor、Gunicorn以及Nginx更是在使用Python開發Web應用 時最常用的軟件,因此對于打算使用Docker部署Python應用的讀者而言,這些最佳實踐是很有參考價值。同時希望各位在日常實踐過程中,也能將各自 踩到過的“坑”以及寶貴的經驗分享出來,大家共同進步!

我們可以使用Docker簡單而高效的部署Python應用,同時,也有一些最佳實踐來幫助我們愉快的完成部署。當然,也不是說這些最佳實踐就是 完成部署的唯一方式,只不過我們團隊發現它們具有高可用性,并且容易維護。注意本文中大多數內容都只是代表我的立場,基于Docker的實現方式有很多, 你可以隨便選擇。本文中我不會過多的介紹Volume,因為它可能需要一個單獨的話題來解釋。我們通常會使用Volume將源代碼復制到容器中,而不是在 每次運行時都重新構建。

DEBIAN_FRONTEND

Docker用戶應該都很熟悉這個環境變量,它告知操作系統應該從哪兒獲得用戶輸入。如果設置 為"noninteractive",你就可以直接運行命令,而無需向用戶請求輸入(譯者注:所有操作都是非交互式的)。這在運行apt-get命令的時 候格外有用,因為它會不停的提示用戶進行到了哪步并且需要不斷確認。非交互模式會選擇默認的選項并以最快的速度完成構建。

請確保你只在Dockerfile中調用的RUN命令中設置了該選項,而不是使用ENV命令進行全局的設置,因為ENV命令在整個容器運行過程中都會生效,所以當你通過BASH和容器進行交互時,如果進行了全局設置那就會出問題。例子如下:

# 正確的做法 - 只為這個命令設置ENV變量
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y python3

 錯誤地做法 - 為接下來的任何命令都設置ENV變量,包括正在運行地容器

ENV DEBIAN_FRONTEND noninteractive RUN apt-get install -y python3</pre>

requirements.txt

相比于基本的代碼(codebase),應用的依賴很少發生變化,因此我們可以在 Dockerfile中安裝項目依賴,這也可以加快之后的構建速度(之后的構建只需要構建變更的代碼)。Docker容器的層級構建可以緩存依賴安裝的過 程,所以之后的的構建速度會非常快,因為它不需要重新下載和構建依賴。

文件順序

按照上面的思路(利用緩存)來推斷,文件添加到容器的順序至關重要。我們應該把頻繁變更的文件放置到Dockerfile的下 方,以便充分使用緩存來加速Docker的構建過程。例如,應用配置、系統配置和依賴都很少改變,我們就可以把它們放到Dockerfile的頂部。而源 文件,比如路由文件、視圖(views)和數據庫代碼會經常發生改變,所以我們就可以把它們放在Dockerfile的下方,注意是Docker配置命令 (EXPOSE、ENV等)的下方。

另外,不要考慮如何將你的文件拷貝到Docker,它不會加快你的構建速度,因為大多數的文件根本不會用到,比如應用源文件。

應用密鑰

之前我們一直不知道如何把應用密鑰安全的傳遞給應用,后來我們發現可以使用docker run命令中的env-file參數。我們會把所有的密鑰和配置都放在app_config.list文件中,然后通過這個文件交付給應用。具體如下:

docker run -d -t -—env-file app_config.list <image:tag>

這個方法允許我們簡單地改變應用設置和密鑰,而無需重建一個容器。

注意:請務必確保app_config.list在.gitignore文件的記錄中,不然它不會被檢錄到源文件中。

Gunicorn

我們使用Gunicorn作為容器內部的應用服務器,Gunicorn非常的穩定并且性能很好,它有非常多的配置選項,比如指定worker數量和類型(green threads、gevent等)的能力,你可以根據負載來調整應用,以獲得最佳性能。

啟動Gunicorn很簡單:

# 安裝
pip3 install gunicorn

 運行服務器

gunicorn api:app -w 4 -b 127.0.0.1:5000</pre>
最后是在Nginx后面運行你的應用服務器,這樣你可以進行負載均衡。

supervisord

你是不是想過在容器中運行多個進程?我想Supervisord絕對是你的最佳輔助工具。假設我們想部署這樣一個容器,它包含Nginx反向代理以及Gunicorn應用。你通過BASH腳本可能就能實現,但是讓我們想更加簡潔一點。

Supevisor是“一個進程控制系統,它支持用戶在類UNIX操作系統上,監視并控制一些進程”。聽起來很完美!你需要先在你的Docker容器內安裝Supervisor。

RUN DEBIAN_FRONTEND=noninteractive apt-get install -y
supervisor

為了讓Supervisor知道該運行什么以及如何管理進程,我們接下來需要為它寫一個配置文件。

[supervisord]
nodaemon = true  # 這個會讓supervisord運行在前端

[program:nginx]  # 你想運行的第一個程序的命名 command = /usr/sbin/nginx  # nginx可執行程序的路徑 startsecs = 5  # 如果nginx保持開啟5s,我們視為啟動成功

[program:app-gunicorn] command = gunicorn api -w 4 -b 127.0.0.1:5000 startsecs = 5</pre>
這是非常基本的配置,它還有很多的配置項,比如控制日志、stdout/stderr重定向、重啟策略等。這個工具真不錯。

一旦你完成了配置,請確保Docker將其復制到了容器中。

ADD supervisord.conf /etc/supervisord.conf

讓Supervisor作為容器的自啟動命令。

CMD supervisord -c /etc/supervisord.conf

它將會在容器啟動的時候,運行Gunicorn和Nginx。如果已經配置過了,那將會按需重啟它們。

學到的東西以及未來的目標

我們已經花了很長時間在Docker中部署代碼,并且接下來會投入更多的時間。在使用Docker的過程中, 我們學到的最重要經驗就是如何最小化思考(think minimally)。在一個容器中運行你的整個系統真的很誘人,但是在應用各自的容器中運行應用進程卻更容易維護。一般情況下,我們會在容器中運行 Nignx和Web服務器,并且在一些場景中,使用單獨的容器來運行Nginx卻沒有任何優勢,它可能只會增加復雜度。我們發現對于大多數情況,它在容器 中的開銷是可接受的。

我希望這些信息對各位有價值!當我們團隊學到更多最佳實踐時,我會更新這篇文章。

原文鏈接:Deploying Python with Docker(翻譯:孫科 校對:李穎杰)

====================
譯者介紹
學生一枚,擼代碼站點維護者,專注于Linux系統編程和編譯技術。熱衷于學習各種語言和技術。目前正在開發一個Java Web框架(畢設)和一個web服務器(D語言編寫)。

來自:http://dockerone.com/article/185

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!