天天看點

使用 Docker 容器化 Python 應用程式的最佳實踐(譯文-來自:snyk)

作者:閃念基因

通過閱讀許多 Python Docker 容器部落格,我們發現大多數文章都提供了如何獨立于其架構(Django、Flask、Falcon 等)容器化 Python 應用程式的示例。例如,您可能會看到如下内容:

1FROM python
2WORKDIR /usr/app
3COPY . .
4RUN pip install -r requirements.txt
5CMD [ "python", "app.py" ]           

使用此 Dockerfile,我們可以建構并運作 Python Flask 應用程式:

1docker build -t flask-application .
2docker run -p 8080:5000 flask-application           

兩個簡單的步驟,它工作得很好,對吧?

雖然此示例對于示範和入門教程來說簡單且有用,但它遺漏了許多重要的問題。是以,考慮到這一點,在這篇文章中,我們将關注這些問題,并了解使用 Docker 容器化 Python 應用程式時的 6 條最佳實踐。我們将探讨為什麼您應該:

  1. 為容器化的 Python 應用程式使用明确且确定的 Docker 基礎映像标簽。
  2. 将依賴項與源代碼分開。
  3. 使用 Python WSGI 進行生産。
  4. 以盡可能低的權限運作容器(永遠不要以 root 使用者身份)。
  5. 處理應用程式的不健康狀态。
  6. 查找并修複 Python Docker 應用程式映像中的安全漏洞。

1. 為容器化的 Python 應用程式使用顯式和确定性的 Docker 基礎鏡像标簽

雖然将其用作python我們的 Dockerized Python 應用程式的基礎映像似乎合乎邏輯,但它留下了使用哪個版本的 Python 的問題。

在撰寫本文時,上述基礎鏡像是指Dockerfile使用 Python 3.10 的基礎鏡像。原因?由于我們沒有添加特定的标簽,它預設為該基礎鏡像的版本,如果我們檢視Docker Hub 的官方鏡像頁面,:latest它恰好是3.10

由于我們想控制我們容器化的 Python 版本,是以我們應該始終在 Dockerfile 中提供該版本資訊。

是以既然我想使用 Python 3.10 版,我隻需要将标簽添加:3.10到我的 Dockerfile 中,對吧?

好吧……不完全是。

的 Docker 基礎鏡像标簽 :3.10是一個成熟的作業系統,安裝了 Python 3.10,其中包含大量您可能永遠不會使用的庫。此外,它包含如此大量的軟體這一事實有一個副作用:由于這些庫中存在安全漏洞,它會增加您的安全攻擊面。

如果你引入了一個大的 Python Docker 鏡像,你将很難維護和保持所有這些庫版本是最新的。

如果我們使用Snyk Advisor 工具檢查 Python 基礎鏡像,我們可以看到 Docker 基礎鏡像python:3.10有 12 個高嚴重性問題、27 個中等嚴重性問題和 132 個低嚴重性問題。是以,預設情況下,Python Docker 映像将以至少 171 個安全漏洞開始——我們甚至還沒有添加任何内容!

此外,由于我們有效地引入了一個完整的作業系統,是以對于我們的 Python 應用程式伺服器而言,基礎映像的大小将非常大,這将導緻建構速度變慢并且需要更大的空間。通常,在選擇基礎鏡像時,規則很少,但有兩個是關鍵。

選擇 Python Docker 鏡像的最佳實踐

  1. 選擇滿足您所有要求的最小基礎映像,然後在此基礎上進行建構。較小的圖像包含較少的漏洞、較少的資源占用和較少的不必要的包。
  2. 使用命名标簽不足以確定您始終使用相同的基礎圖像。確定這一點的唯一方法是使用圖像摘要。

有了這些知識,讓我們重新通路Snyk Advisor并檢查它推薦的替代标簽。該工具對基礎鏡像的漏洞和大小進行了很好的概述,這将極大地幫助我們做出決定。

由于我們有興趣在我們的應用程式中使用 Python 3.10,是以我們将查找該特定标記。

使用 Docker 容器化 Python 應用程式的最佳實踐(譯文-來自:snyk)

除了上述漏洞外,我們還可以看到該鏡像的基本大小約為 350 MB,它基于 Debian 11,并安裝了 427 個軟體包。我們會認為這張圖檔對于我們的小 Python 應用程式來說有點太多了。

另一方面,還有用于 Python 的 Docker 基礎映像:3.10-slim有 1 個高嚴重性問題、1 個中等嚴重性問題和 35 個低嚴重性問題。Docker 基礎大小為 46.2 MB,也是基于 Debian 11 的作業系統,并安裝了 106 個軟體包。簡單地為我們的 Python 應用程式伺服器選擇這個 Docker 基礎鏡像而不是預設鏡像将減少安全漏洞的數量、磁盤大小和安裝的庫數量——同時滿足我們對 :3.10.

就這樣吧!我隻需添加标簽 :3.10-slim 就可以了!

幾乎!我們滿足了第一條規則——我們有一個小的 Docker 基礎鏡像來滿足我們的要求——但我們仍然需要解決第二個問題。我們需要確定每次建構我們的 Python 應用程式伺服器時,我們都會實際使用準确的 Docker 基礎鏡像。

為此,我們有幾種選擇:

  1. 從 Docker Hub 擷取 Docker 基礎鏡像摘要。
  2. 使用 将 Docker 鏡像下載下傳到我們的計算機上docker pull python:3.10-slim,這會顯示 Docker 鏡像摘要:
13.10-slim: Pulling from library/python
27d63c13d9b9b: Pull complete
36ad2a11ca37b: Pull complete
41d79bc863ed3: Pull complete
5c72b5f03bec8: Pull complete
60c3b0c5ce69b: Pull complete
7Digest: sha256:2bac43769ace90ebd3ad83e5392295e25dfc58e58543d3ab326c3330b505283d
8Status: Downloaded newer image for python:3.10-slim
9docker.io/library/python:3.10-slim           

如果我們的計算機上已經有 Python Docker 鏡像,我們可以使用以下指令從磁盤上目前存在的鏡像中擷取鏡像摘要docker images --digests | grep python:

1python    3.10-slim    sha256:2bac43769ace90ebd3ad83e5392295e25dfc58e58543d3ab326c3330b505283d           

一旦我們有了基礎鏡像摘要,我們就可以将它添加到前面提到的 Dockerfile 中:

檔案

1FROM python:3.10-slim@sha256:2bac43769ace90ebd3ad83e5392295e25dfc58e58543d3ab326c3330b505283d
2WORKDIR /usr/app
3COPY . .
4RUN pip install -r requirements.txt
5CMD [ "python", "app.py" ]           

這種做法確定每次我們為這個 Python 應用程式重建 Docker 鏡像時,都使用相同的底層作業系統和庫版本。這提供了一個确定性的建構。

2.将依賴與源碼分離

第二個最佳實踐可以防止涉及具有依賴項的項目的任何類型的 Docker 映像中最常見的錯誤之一。首先,這是不好的做法:

  1. 将項目檔案夾中的所有内容複制到圖像上下文中。
  2. 安裝依賴項。
  3. 運作應用程式。

嗯,它有效,但還有很多需要改進的地方。對于初學者來說,當你在本地開發一個項目時,你隻在依賴項發生變化時才安裝它們,對吧?是以,不要每次更改最細微的代碼行時都強制您的 Docker 映像下載下傳并安裝它們。

這個最佳實踐是關于優化 Docker 鏡像中的層。如果我們想在 Docker 建構期間利用緩存系統,我們在編寫 Dockerfile 時應該始終牢記一件事:層應該始終根據它們更改的可能性來排序。

讓我們來看看我們一直攜帶到現在的Dockerfile。每次我們建構該 Python 應用程式映像時,Docker 軟體都會檢查不同的層并回答以下問題:是否發生了某些變化,或者我可以隻使用我以前做過的嗎?

在我們目前形式的 Dockerfile 内容中,對我們的項目檔案夾的任何更改都将重新觸發指令COPY- 以及随後 - 其餘建構層。這真的沒有意義,它為優化和加速留下了很大的空間。

讓我們使用以下 Dockerfile 改進它:

1FROM python:3.10-slim@sha256:2bac43769ace90ebd3ad83e5392295e25dfc58e58543d3ab326c3330b505283d
2WORKDIR /usr/app
3
4COPY requirements.txt .
5RUN pip install -r requirements.txt
6
7COPY . .
8CMD [ "python", "app.py" ]           

有了這個新的 Dockerfile,下次 Docker 檢查層是否可以重用時,如果發現檔案沒有變化requirements.txt,它會“跳轉”直達指令COPY,幾秒鐘内解決。通過這個微小的變化,我們加快了很多建構過程——每次我們修改代碼中的某些内容時,建構之間不再需要等待幾分鐘。

請務必注意,并非所有依賴項都打包為wheels ,這一點很重要。在這種情況下,需要在您的映像上安裝編譯器。

但是您告訴我們要使用盡可能小的圖像來運作應用程式!

你是對的,這就是為什麼我們要向你展示另一個驚人的 Docker 特性:多階段建構。

多階段建構

多階段建構意味着我們使用帶有更多工具的 Docker 鏡像來編譯那些所需的依賴項,然後我們隻需将所需的工件複制到實際使用的 Python Docker 鏡像中。

基于 Node.js 的應用程式示例如下:

1FROM node:latest AS build
2ARG NPM_TOKEN
3WORKDIR /usr/src/app
4COPY package*.json /usr/src/app/
5RUN npm install
6
7FROM node:lts-alpine@sha256:b2da3316acdc2bec442190a1fe10dc094e7ba4121d029cb32075ff59bb27390a
8WORKDIR /usr/src/app
9COPY --from=build /usr/src/app/node_modules /usr/src/app/node_modules
10COPY . .
11CMD ["node", "server.js"]           

注意:這是一個簡單的示例,僅用于示範多階段的功能。如果您想學習正确容器化 Node.js 應用程式的最佳實踐,請參閱 Liran Tal(這個名字看起來很熟悉……)和 Yoni Goldberg 的這篇文章。

Node.js 的多階段建構非常容易處理,因為node_modules檔案夾将與實際項目位于同一檔案夾中,但是,當我們處理 Python 應用程式時情況并非如此。

如果我們隻是運作pip install,我們會在很多地方安裝很多東西,導緻無法執行多階段建構。為了解決這個問題,我們有兩個可能的解決方案:

  1. 使用pip install --user
  2. 用一個virtualenv

使用pip install --user似乎是一個不錯的選擇,因為所有包都将安裝在~/.local目錄中,是以将它們從一個階段複制到另一個階段非常容易。但這會産生另一個問題:您會将我們用于編譯依賴項的映像中的所有系統級依賴項添加到最終的 Docker 基礎映像中——我們不希望這種情況發生(記住我們的最佳實踐是盡可能小的 Docker 基礎鏡像)。

排除第一個選項後,讓我們探讨第二個選項:使用virtualenv. 如果我們這樣做,我們最終會得到以下 Dockerfile。

1FROM python:3.10-slim as build
2RUN apt-get update
3RUN apt-get install -y --no-install-recommends \
4	      build-essential gcc 
5
6WORKDIR /usr/app
7RUN python -m venv /usr/app/venv
8ENV PATH="/usr/app/venv/bin:$PATH"
9
10COPY requirements.txt .
11RUN pip install -r requirements.txt
12
13FROM python:3.10-slim@sha256:2bac43769ace90ebd3ad83e5392295e25dfc58e58543d3ab326c3330b505283d
14WORKDIR /usr/app/venv
15COPY --from=build /usr/app/venv ./venv
16COPY . .
17
18ENV PATH="/usr/app/venv/bin:$PATH"
19CMD [ "python", "app.py" ]           

現在,我們擁有所有必需的依賴項,但沒有編譯它們所需的額外包。

容器化 Python 應用程式的多階段建構的已知問題

目前,有一個已知的問題,pre-stages not being cached。解決此問題的最簡單方法是使用BuildKit并将參數添加BUILDKIT_INLINE_CACHE=1到建構過程。

我們将在第一次正常建構,但後續建構将使用以下指令:

1export DOCKER_BUILDKIT=1
2docker build -t flask-application --cache-from flask-application --build-arg BUILDKIT_INLINE_CACHE=1 .           

您将需要環境變量,DOCKER_BUILDKIT=1以便 Docker 知道在建構過程中使用 BuildKit。也可以通過在 Docker 軟體配置檔案中添加以下設定來啟用它/etc/docker/daemon.json(這樣就不需要環境變量):

1{ "features": { "buildkit": true } }           

3. 使用 Python WSGI 進行生産

為生産而建構的啟用調試模式的 Python 應用程式是一個很大的禁忌- 并且等待發生的安全事件。不幸的是,這是我們在許多關于容器化 Python Flask 應用程式和其他 WSGI Python 應用程式架構的部落格文章中看到的一個常見錯誤。

調試器允許從浏覽器執行任意 Python 代碼,這會帶來巨大的安全風險。這可以在一定程度上得到保護,但它始終是一個漏洞。為了安全起見,再說一次:不要在生産環境中運作開發伺服器或調試器!這也适用于您的容器化 Python 應用程式。

我們知道在調試模式下部署 Python Flask 應用程式比設定 WSGI 伺服器和 Web/代理更容易,但隻有在您必須解釋為什麼您的應用程式被黑客入侵時才會更容易。

那麼如何解決呢?首先,您應該決定要使用哪個 WSGI 伺服器實作。Python應用常用的主要有這四種:

  • Green Unicorn (Gunicorn) — 從 Ruby 的 Unicorn 項目移植的預分叉勞工模型。
  • uWSGI — 一種多功能、高性能和低資源使用的 WSGI 伺服器實作。
  • mod_wsgi — 一個 Apache 子產品,可以托管任何支援 Python WSGI 規範的 Python Web 應用程式。
  • CherryPy — Pythonic,面向對象的 HTTP 架構,也可用作 WSGI 伺服器。

在本文中,我們将使用Gunicorn作為示例,但請随意閱讀所有這些工具的文檔和資訊,以便您可以選擇最适合您需要的工具。在這篇文章中,我們不會檢視配置,因為它完全取決于用例。

對于容器化部分,我們隻需要:

  1. 将gunicorn依賴項包含在requirements.txt
  2. 更改 Python 應用程式容器的入口點(請參閱CMD此更改的說明):
1FROM python:3.10-slim as build
2RUN apt-get update
3RUN apt-get install -y --no-install-recommends \
4	build-essential gcc 
5
6WORKDIR /usr/app
7RUN python -m venv /usr/app/venv
8ENV PATH="/usr/app/venv/bin:$PATH"
9
10COPY requirements.txt .
11RUN pip install -r requirements.txt
12
13FROM python:3.10-slim@sha256:2bac43769ace90ebd3ad83e5392295e25dfc58e58543d3ab326c3330b505283d
14WORKDIR /usr/app
15COPY --from=build /usr/app/venv ./venv
16COPY . .
17
18ENV PATH="/usr/app/venv/bin:$PATH"
19CMD [ "gunicorn", "--bind", "0.0.0.0:5000", "manage:app" ]           

在我們基于這個新的 Dockerfile 重建 Python 應用程式之後,我們可以運作并測試 Flask 應用程式是否已準備好處理請求:

1docker run -p 8080:5000 flask-application           

注意:我們建議對于實際的生産就緒部署,您不應直接将Gunicorn公開的端口綁定到主機。相反,我們建議您在處理所有 HTTP 請求并提供靜态檔案的同一網絡中部署反向代理伺服器。

4. 以盡可能少的權限運作容器化的 Python 應用程式(永遠不要root)

最小權限原則是 Unix 早期的一個長期安全控制——當我們運作容器化的 Python 應用程式時,我們應該始終遵循這一點。

預設情況下,官方pythonDocker 鏡像不包含特權使用者,是以我們需要建立它以便能夠以最低特權使用者運作程序。

為此,我們将以下groupadd指令添加到實際運作該過程的最終映像(多階段建構的第二階段)中的 Dockerfile gunicorn:

1FROM python:3.10-slim@sha256:2bac43769ace90ebd3ad83e5392295e25dfc58e58543d3ab326c3330b505283d
2
3RUN groupadd -g 999 python && \
4    useradd -r -u 999 -g python python
5USER 999
6WORKDIR /usr/app
7
8COPY --from=build /usr/app/venv ./venv
9COPY . .
10
11ENV PATH="/usr/app/venv/bin:$PATH"
12CMD [ "gunicorn", "--bind", "0.0.0.0:5000", "manage:app" ]           

但是,問題在于,通過先前的修改,使用者python擁有由 Docker 執行的系統程序……複制檔案或WORKDIR目錄的檔案所有權如何?預設情況下,WORKDIR如果目錄不存在,Docker 編譯器将建立該目錄,但它會以root系統使用者作為其所有者來建立它,是以任何包括寫入該目錄的操作都可能導緻我們的應用程式出現緻命錯誤。root此外,如果我們不更改它們的行為,則預設情況下将擁有複制的檔案,即使我們已經更改了使用者。

讓我們修複它:

1FROM python:3.10-slim@sha256:2bac43769ace90ebd3ad83e5392295e25dfc58e58543d3ab326c3330b505283d
2
3RUN groupadd -g 999 python && \
4    useradd -r -u 999 -g python python
5
6RUN mkdir /usr/app && chown python:python /usr/app
7WORKDIR /usr/app
8
9COPY --chown=python:python --from=build /usr/app/venv ./venv
10COPY --chown=python:python . .
11
12USER 999
13
14ENV PATH="/usr/app/venv/bin:$PATH"
15CMD [ "gunicorn", "--bind", "0.0.0.0:5000", "manage:app" ]           

通過以上更新的COPY說明,我們可以防止目錄在檔案所有權方面出現意外行為WORKDIR,并確定所有檔案都屬于将要運作該程序的同一使用者。

5. 處理容器化 Python 應用程式的不健康狀态

在部署應用程式時,您需要注意可能導緻應用程式處于不健康狀态的未處理事件或問題:1) 它不再工作,但 2) 它不會終止程序。如果發生這種情況,您的容器将不會收到通知,并且您将有一個正在運作的 Python 應用程式伺服器不再響應 HTTP 請求。

為避免這種情況,我們要實施健康檢查端點。為了檢查容器化 Python 應用程式的運作狀況,我們始終建議包含一個monitoring或healthHTTP 端點,以確定應用程式仍然能夠成功處理使用者請求。使用一些 Python 的 Web 應用程式架構,如 Flask,這将是一項簡單的任務(下面的 Flask 示例),并且結合 Docker 的HEALTHCHECK指令,您将確定您的應用程式得到良好的健康狀态監控。

以下是添加/healthHTTP 端點的 Python Flask 應用程式片段:

[email protected]('/health', methods=['GET'])
2def health():
3	# Handle here any business logic for ensuring you're application is healthy (DB connections, etc...)
4    return "Healthy: OK"           

“一旦你在你的應用程式中有了那個端點,你隻需要HEALTHCHECK在你的 Dockerfile 中包含指令:

1FROM python:3.10-slim@sha256:2bac43769ace90ebd3ad83e5392295e25dfc58e58543d3ab326c3330b505283d
2
3RUN groupadd -g 999 python && \
4    useradd -r -u 999 -g python python
5
6RUN mkdir /usr/app && chown python:python /usr/app
7WORKDIR /usr/app
8
9COPY --chown=python:python --from=build /usr/app/venv ./venv
10COPY --chown=python:python . .
11
12USER 999
13
14ENV PATH="/usr/app/venv/bin:$PATH"
15CMD [ "gunicorn", "--bind", "0.0.0.0:5000", "manage:app" ]
16HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD curl -f http://localhost:5000/health           

如果您在 Kubernetes 上進行部署,那麼您應該知道 DockerfileHEALTHCHECK指令會被忽略。YAML 中需要相應的Kubernetes 活性、就緒性和啟動探測。

是以,要解決上述HEALTHCHECK指令的 Kubernetes 部署問題:

1...
2   livenessProbe:
3     httpGet:
4       path: /health
5       port: 5000
6     initialDelaySeconds: 5
7     periodSeconds: 30
8     timeoutSeconds: 30
9     failureThreshold: 3
10...           

請注意,此配置将嵌套在container specpod 或部署 YAML 檔案的一部分中。always現在,使用或 的重新開機政策unless_stopped,如果我們的 Python 應用程式容器進入不健康狀态,它将始終重新開機。

6. 查找并修複 Python Docker 應用程式映像中的安全漏洞

我們已經确定,更大的 Docker 基礎映像會帶來許多問題,例如我們需要維護的大型軟體堆棧、與安全修複程式保持同步等等。

我們還探索了使用Snyk Advisor來确定不同基礎映像中的大小和漏洞名額。但 Advisor 隻是冰山一角。Snyk 是一個免費的開發人員安全平台,您可以使用它來測試任何東西,從您自己的 Python 代碼到您的 Python 依賴項(例如 中的依賴項requirements.txt)、運作您的應用程式的 Python 容器映像,甚至是編排這一切的 Terraform 或 Kubernetes 配置。

Snyk 最好的一點是它為它發現的漏洞提供了建議的修複。是以,它不僅會告訴您存在哪些安全漏洞,還會自動建立修複 PR 或提供補救建議。這一切都是在您現有的工具(IDE、CLI、Docker 等)和工作流(Git、CI/CD 等)中完成的。

示例:使用 Snyk 掃描我們的容器化 Python 應用程式

python:3.8當我們使用 的 Python Docker 映像建構此示例 Python Flask 應用程式時,讓我們看看 Snyk CLI 是如何工作的。

Snyk 已經內建到 Windows、macOS 和 Linux 作業系統(通過 docker-ce)上的 Docker Desktop 中,并且它有一個内置指令——你可以docker scan運作它來掃描你的 Docker 鏡像。

如果您安裝了 Snyk CLI,您可以使用它來掃描您的 Python 項目依賴項、您的 Python 代碼等。是以,首先,我們安裝 Snyk CLI。如果你有一個 Node.js 環境,你可以使用npm包管理器來完成它,如下所示:

1npm install -g snyk           

或者如果你在 macOS 或 Linux 上,并且正在使用 Homebrew,你可以像這樣安裝它:

1brew tap snyk/tap
2brew install snyk           

對于其他安裝方法,請參閱我們關于如何安裝 Snyk CLI 的指南。

接下來,我們需要從 CLI 進行身份驗證,以擷取有效的 API 令牌來查詢漏洞資料庫:

1snyk auth           

以上完成後,我們就可以繼續用基礎鏡像建構Python應用的本地Docker鏡像了python:3.8:

1❯ docker build . -t python-flask-app
2FROM python:3.8 as build
3[+] Building 5.2s (8/13)
4 => [internal] load build definition from Dockerfile
5 => => transferring dockerfile: 513B
6 => [internal] load .dockerignore
7 => => transferring context: 2B
8 => [internal] load metadata for docker.io/library/python:3.8
9 => [auth] library/python:pull token for registry-1.docker.io
10 => [internal] load build context
11...           

現在,讓我們通過運作以下指令使用 Snyk 對其進行掃描:

1snyk container test python-flask-app           

輸出産生以下結果(故意縮短,因為輸出很大):

1Testing python-flask-app...
2
3✗ Low severity vulnerability found in tiff/libtiff5
4  Description: Out-of-bounds Read
5  Info: https://snyk.io/vuln/SNYK-DEBIAN11-TIFF-514595
6  Introduced through: imagemagick@8:6.9.11.60+dfsg-1.3, imagemagick/libmagickcore-dev@8:6.9.11.60+dfsg-1.3
7  From: imagemagick@8:6.9.11.60+dfsg-1.3 > imagemagick/imagemagick-6.q16@8:6.9.11.60+dfsg-1.3 > imagemagick/libmagickcore-6.q16-6@8:6.9.11.60+dfsg-1.3 > tiff/[email protected]
8  From: imagemagick/libmagickcore-dev@8:6.9.11.60+dfsg-1.3 > imagemagick/libmagickcore-6.q16-dev@8:6.9.11.60+dfsg-1.3 > tiff/[email protected] > tiff/[email protected]
9  From: imagemagick/libmagickcore-dev@8:6.9.11.60+dfsg-1.3 > imagemagick/libmagickcore-6.q16-dev@8:6.9.11.60+dfsg-1.3 > tiff/[email protected] > tiff/[email protected] > tiff/[email protected]
10  and 3 more...
11
12✗ High severity vulnerability found in imagemagick/imagemagick-6-common
13  Description: Information Exposure
14  Info: https://snyk.io/vuln/SNYK-DEBIAN11-IMAGEMAGICK-1246513
15  Introduced through: imagemagick/libmagickcore-dev@8:6.9.11.60+dfsg-1.3, imagemagick/libmagickwand-dev@8:6.9.11.60+dfsg-1.3, imagemagick@8:6.9.11.60+dfsg-1.3
16  From: imagemagick/libmagickcore-dev@8:6.9.11.60+dfsg-1.3 > imagemagick/imagemagick-6-common@8:6.9.11.60+dfsg-1.3
17  From: imagemagick/libmagickwand-dev@8:6.9.11.60+dfsg-1.3 > imagemagick/imagemagick-6-common@8:6.9.11.60+dfsg-1.3
18  From: imagemagick@8:6.9.11.60+dfsg-1.3 > imagemagick/imagemagick-6.q16@8:6.9.11.60+dfsg-1.3 > imagemagick/libmagickcore-6.q16-6@8:6.9.11.60+dfsg-1.3 > imagemagick/imagemagick-6-common@8:6.9.11.60+dfsg-1.3
19  and 24 more...
20
21✗ Critical severity vulnerability found in python3.9/libpython3.9-stdlib
22  Description: Improper Input Validation
23  Info: https://snyk.io/vuln/SNYK-DEBIAN11-PYTHON39-1290158
24  Introduced through: [email protected]
25  From: [email protected] > python3-defaults/[email protected] > python3-defaults/[email protected] > python3.9/[email protected]
26  From: [email protected] > python3-defaults/[email protected] > [email protected] > python3.9/[email protected]
27  From: [email protected] > python3-defaults/[email protected] > python3-defaults/[email protected] > python3.9/[email protected]
28  and 4 more...
29
30✗ Critical severity vulnerability found in glibc/libc-bin
31  Description: Use After Free
32  Info: https://snyk.io/vuln/SNYK-DEBIAN11-GLIBC-1296898
33  Introduced through: glibc/[email protected]+deb11u2, meta-common-packages@meta
34  From: glibc/[email protected]+deb11u2
35  From: meta-common-packages@meta > glibc/[email protected]+deb11u2
36  From: meta-common-packages@meta > glibc/[email protected]+deb11u2
37  and 1 more...
38
39Organization:      snyk-demo-567
40Package manager:   deb
41Project name:      docker-image|python-flask-app
42Docker image:      python-flask-app
43Platform:          linux/amd64
44Base image:        python:3.8.12-bullseye
45Licenses:          enabled
46
47Tested 427 dependencies for known issues, found 171 issues.
48
49Base Image              Vulnerabilities  Severity
50python:3.8.12-bullseye  171              6 critical, 6 high, 27 medium, 132 low
51
52Recommendations for base image upgrade:
53
54Alternative image types
55Base Image                   Vulnerabilities  Severity
56python:3.9-slim              37               1 critical, 0 high, 1 medium, 35 low
57python:3.11-rc-slim          37               1 critical, 0 high, 1 medium, 35 low
58python:3.8.12-slim-bullseye  37               1 critical, 0 high, 1 medium, 35 low
59python:3.10-slim-buster      70               2 critical, 9 high, 9 medium, 50 low           

是以,作為 Python 3.8 作業系統内容的一部分,我們以開源庫的形式引入了 427 個依賴項。由于我們選擇了python:3.8.

說到這裡,你可能會不解地問:“我該如何解決呢?” 對我們來說幸運的是,Snyk 提供了一些建議,我們可以更新或完全切換到哪些其他基礎映像,以降低攻擊面。

這是此基本圖像推薦建議的清晰可視化螢幕截圖:

使用 Docker 容器化 Python 應用程式的最佳實踐(譯文-來自:snyk)

現在我們可以做出明智的、資料驅動的決定來保護我們的 Python 應用程式。通過選擇 Snyk 推薦的任何替代 Docker 鏡像,我們可以顯着降低應用程式中捆綁軟體的攻擊面。

為了更好地控制應用程式的安全性,請将您的存儲庫連接配接到 Snyk UI以導入您的源代碼和 Dockerfile,這樣您不僅可以找到這些漏洞,還可以持續監控它們是否存在新的安全問題。這是來自 Snyk UI 的相同 Docker 基礎鏡像報告:

使用 Docker 容器化 Python 應用程式的最佳實踐(譯文-來自:snyk)

有什麼比監視和查找安全漏洞更好的呢?修複它們!:-)

如果您将 Git 存儲庫連接配接到 Snyk,我們還可以在您的存儲庫中建立拉取請求(自動!)以提供這些 Docker 基礎映像更新,就像您在此處看到的那樣:

使用 Docker 容器化 Python 應用程式的最佳實踐(譯文-來自:snyk)

如果您喜歡這篇文章,請檢視這篇關于使用 Dockerfile 拉取請求自動化容器安全性的後續文章。

Python 應用程式如何容器化?

Docker 是一種軟體虛拟化技術,它允許我們以基于 Python Docker 映像的容器化 Python 應用程式的形式建構可重用、跨平台和快速部署的軟體。這些應用程式通過基礎架構定義為帶有名為 Dockerfile 的檔案的代碼。

要建構和使用容器化 Python 應用程式,請運作以下指令:

docker build -t flask-application .

docker run -p 8080:5000 flask-application

針對開發人員的 Python 安全建議

這些最佳實踐應該可以幫助您更好地建立、管理和保護您的容器化 Python 應用程式。如果您喜歡閱讀這些最佳實踐,并且重視應用程式安全和對整體安全的擁護,那麼我們建議您将以下資源作為後續閱讀材料:

  • Daniel Berman 的Snyk 安全 Python 開發入門
  • Brian Vermeer 的Snyk CLI 秘密和一個很棒的備忘單
  • 由 Liran Tal 和 Yoni Golberg 編寫的針對 Docker 基礎應用程式的全面 Node.js 最佳實踐
  • 最後,對于您的 Java 朋友,這個Docker for Java developers: 5 things you need to know to not fail your security by Brian Vermeer。
  • Frank Fischer 的Python 安全最佳實踐備忘單
  • 關于Python 項目中常見安全問題的功能齊全且見解豐富的報告

作者:Liran Tal

出處:https://snyk.io/blog/best-practices-containerizing-python-docker/