日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

从安全到镜像流水线,Docker 最佳实践与反模式一览

發布時間:2024/8/23 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 从安全到镜像流水线,Docker 最佳实践与反模式一览 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

作者 |?Timothy Mugayi

譯者 |?彎月,責編 | 夕顏

封圖 | CSDN付費下載自視覺中國

出品 | CSDN(ID:CSDNnews)

在使用Docker的大部分時間里,我們并不關心其內部的工作原理。僅憑啟動一個Docker容器并且讓應用程序運行良好,并不能說明你已經實現了一個良好的解決方案。有時,由于時間限制,我們只能復制粘貼Docker鏡像,卻沒能真正理解實現細節以及如何構建Docker鏡像的細微差別。

?

在本文中,我們將探討Docker的最佳實踐和反模式。反模式是人們對于反復出現的問題的一般解決方案,這些方案沒有效率,甚至會完全抵消Docker技術棧帶來的好處。

?

下面我們來看看我們的哪些做法不可取。

?

我們需要的標簽

?

標簽是必不可少的,我們需要通過標簽傳達有關Docker鏡像的信息。你可以將標簽視為Docker鏡像ID的別稱。Git標簽負責標記特定的提交,而Docker標簽與之類似,可以給不同時間點上的Docker鏡像添加版本。忘記打標簽是小事,但會帶來一些弊端,具體來講,如果未指定標記,則默認鏡像將被標記為latest。

?

FROM your_image_name:latest

?

如果你頻繁執行該操作,那么很有可能鏡像不是最新的,可能指向的是舊版本。因此,請使用適當的標簽并遵守某個版本控制標準,例如語義版本控制。這樣,Docker鏡像使用者才能確保Docker鏡像的兼容性并時刻保持最新,還可以有計劃地使用正確的版本。

?

還有一個情況應該避免。你可以利用最新的默認標簽(如FROM python3:latest),從Docker鏡像倉庫中提取最新的鏡像。乍一看,這種做法似乎是個好主意,但卻有一些意想不到的副作用:每個最新的請求可能都會派生出與以前的構建完全不同的Docker鏡像。弄明白Docker鏡像損壞的原因將會變得很困難,因為鏡像本應該是不可變的。因此,我強力建議使用特定的標簽來標記鏡像(例如:python3:1.0.1)。這種方法可以確保你的Dockerfile保持不變。

?

在同一個容器中運行多個服務

?

雖然你可以在同一個容器中運行多個服務,但我并不建議你這么做,原因有兩個。在使用Docker服務時,我們應該努力維持責任單一性。最佳做法是,組成應用程序的每個服務都應在各自的容器中運行,請務必將每項獨立的功能都打包到單獨的獨立容器鏡像中。

?

將多個服務添加到一個Docker鏡像的做法似乎很誘人,但是你不應該將容器鏡像視為虛擬機。一個容器包含多個服務,可能會導致你的應用程序很難水平擴展。Docker容器核心概念是,它們都是瞬態的,專為分發而設計,這對于現代Web應用程序來說很理想,因為它的瞬態特性、擴展和并發會非常容易。添加多個服務會增加管理分發的難度。

?

另外,單個容器上的多個服務還會加大管理安全性的難度。龐大的鏡像可能會降低CI/CD的速度,你需要小心。

?

使用LABEL對鏡像進行分類

?

這并不能說是反模式,但我認為值得一提。我在處理各種Docker鏡像時注意到了一件事:有時這些鏡像的創建者沒有使用LABEL maintainer標簽。這個標簽可在事件中設置鏡像的Author字段,當出現問題或需要澄清時,這個標簽可以方便大家了解該與何人內部聯系;如果鏡像是公開共享的,也可以知道該與哪個外部的人聯系。

?

這絕不是唯一可以使用的標簽。你可以根據需要定義各種標簽,來對鏡像進行分類,定義許可信息,也可以定義標簽來幫助自動化。

?

除了maintainer,還可以使用多行標簽:

# Set one or more individual labels LABEL com.example.version="0.0.1-beta" LABEL vendor1="RBTSB Incorporated" LABEL vendor2=TIPTAPCODE\ Incorporated LABEL com.example.release-date="202-04-02" LABEL com.example.version.production="0.0.1"

Docker 1.10之前的單行標簽會創建新的docker層,如果你使用的是最新版的Docker,則不必擔心創建額外的層。

LABEL vendor=ACME\ Incorporated \ com.example.is-beta= \ com.example.is-production="" \ com.example.version="0.0.1-beta" \ com.example.release-date="2015-02-12"

我們應該將盡可能多的元數據添加到不可變的Docker鏡像,以方便追蹤,提高可見性和可維護性。

?

避免構建依賴特定環境的鏡像

?

在構建Docker鏡像時,我們應始終牢記不變性。最好不要使用帶有dev、test、staging和production的鏡像,因為這會破壞單一來源的原則。另一個問題是,如果在不同環境上驗證或調試,則這種做法無法保證鏡像的相似。

?

為什么要使用非Root容器?

?

在默認情況下,Docker容器以root身份運行。以root用戶身份運行的Docker容器可以完全控制主機系統。然而,出于安全考慮,我并不推薦這種做法。使用非root運行的Docker容器鏡像可以多一層保護,在生產環境中通常建議使用非root容器。但是,由于這些容器由非root用戶運行,因此無法執行需要特殊權限的任務。如果需要利用USER指令指定非root用戶(如以下示例所示),則需要進行一些上下文切換。

?

FROM python:3.6-slim-buster LABEL maintainer="Timothy Mugayi <timothy.mugayi@gmail.com>"RUN apt-get update && apt-get install -y --no-install-recommends \ wget && rm -rf /var/lib/apt/lists/*# Dumb init RUN wget -O /usr/local/bin/dumb-init https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64 RUN chmod +x /usr/local/bin/dumb-initRUN pip install --upgrade pipWORKDIR /usr/src/appCOPY requirements.txt .RUN pip install -r requirements.txtCOPY helloworld.py .USER 1001ENTRYPOINT ["/usr/local/bin/dumb-init", "python3", "-u", "./helloworld.py"]?

如果你使用的基礎鏡像不是由root生成的,但需要切換回root,則可以執行以下操作:

FROM <namespace>/<image>:<tag_version>USER root

不要在單個容器內運行太多進程

?

容器的優點以及容器相對于虛擬機的優勢在于,通過多個相互交互的容器組成一個完整的應用程序。我們無需在單個容器中運行完整的應用程序。相反,我們應盡可能將應用程序分解為多個服務,并將服務分布到多個容器上。這樣可以最大程度地提高靈活性和可靠性。

?

不要在容器內安裝操作系統

?

使用一段時間Docker后,你就有可能遇到這種情況。雖然你可以在容器內安裝和運行完整的Linux操作系統。但是你應該這樣做嗎?

?

這可能不是一個好主意。Docker鏡像是使用層的概念構建的,因此添加的東西越多,鏡像就會膨脹得越大。一個完整的操作系統并不是Docker的理想使用情況。在理想情況下,你的容器內部只應該加載必要的組件。

?

不要在容器內運行不必要的服務

?

為了充分利用容器的優勢,你應該盡可能保持容器精簡。這樣可以最大程度地提高性能,并最大程度地降低安全風險。因此,請避免運行并非絕對必要的服務。例如,若非必要請不要在容器內運行SSH服務,你可以選用其他方式(例如Docker exec)登錄到容器。

?

不要在容器內加載不必要的程序

?

你必須知道這種反模式。在使用Docker時,很多人傾向于在鏡像中加載sonar之類的工具,來確保代碼覆蓋率等。

?

使用從Docker CE 17.05+開始支持的多階段構建(Multistage builds)模式,你可以在Dockerfile中使用多個FROM stage。臨時構建的階段容器將被丟棄,因此最終的運行時容器鏡像都很精簡。舉個例子,當你需要從源文件編譯一些二進制文件,然后在第二個階段中將二進制文件復制到最終鏡像中。

?

優點:

?

  • 構建速度更快,精簡的鏡像可以讓CI/CD過程更快,鏡像通過網絡進行傳輸時花費的時間也更少。

  • 需要的存儲空間更少。

  • 冷啟動(拉取鏡像)更快。

  • 潛在的受攻擊面更少。

?

缺點:

?

  • 容器內的工具較少,但這是保證容器的精簡所需付出的一點小小的代價。

在容器內加入供觀察的工具

?

即便沒有監視解決方案,你也可以照常運行容器,但需要牢記,從本質上來說,你很難知道容器內部發生了什么,特別是隨著容器數量的增加。

?

Docker本身自帶了許多指標,能夠公開每個運行容器的CPU、內存、網絡和I/O使用情況,可通過Docker遠程API的/stats端點訪問。App dynamics 和 Newrelic 是兩個現成的程序,可以與Docker鏡像一起打包,幫助你從應用程序級別了解應用程序和容器的運行狀況。

?

基礎鏡像的愛恨交織

?

“你知道是誰構建了這個景象,里面都添加了什么嗎?”

?

這里說的都是可追溯性。牢記安全性是所有軟件開發人員都應努力的方向。你需要了解如何跟蹤Docker鏡像的源,并了解里面有什么。

?

你需要時刻牢記以下幾點:

?

  • 鏡像是怎樣創建的。

  • 驗證鏡像在創建后未經更改。

  • 驗證鏡像的內容。

  • 掃描鏡像是否有安全漏洞。

?

我們可以通過一些工具對容器進行靜態分析。這些工具涉及方方面面,已超出了本文的范圍,但是我建議你花一些時間來學習。

?

Clair是一個有趣的工具,可為你的Docker應用程序提供自動容器漏洞和安全掃描。掃描基于常見的漏洞和公開(CVE)的數據庫。如果你本地運行Docker,則可以下載Postgres,然后將Clair連接到Postgres上。以下是啟動和運行Clair所需的最低配置:

$ mkdir $PWD/clair_config $ curl -L https://raw.githubusercontent.com/coreos/clair/master/config.yaml.sample -o $ PWD/clair_config/config.yaml $ docker run -d -e POSTGRES_PASSWORD="" -p 5432:5432 postgres:9.6 $ docker run --net=host -d -p 6060-6061:6060-6061 -v PWD/clair_config:/config quay.io/coreos/clair:latest -config=/config/config.yaml

如果你想更改Postgres的端口,請確保同時修改config.yaml文件。如果你的系統上已經運行了另一個Postgres,請注意不要將docker端口更改為5432以外的端口。

?

clair: database: # Database driver type: pgsql options: # PostgreSQL Connection string # https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING source: host=localhost port=5432 user=postgres password=123456 sslmode=disable statement_timeout=60000

在鏡像啟動并執行后,你可以運行Docker ps來確認容器已啟動且正常運行:

你需要注意Clair沒有Web UI或CLI。你只能通過REST API或第三方CLI工具來使用。

?

Bayan Collector是一款輕巧的靜態分析應用程序,可以從鏡像倉庫啟動容器以進行靜態分析,可以運行任意腳本并收集有用的信息(例如已安裝的軟件包),強制執行策略,以及對鏡像進行校驗。

?

Docker Bench for Security是由Docker團隊創建的工具,它會在Docker的宿主上運行一個安全最佳做法清單,并標記發現的任何問題。

?

不要在容器鏡像中存儲敏感數據

?

請一定避免這個錯誤。如果你的鏡像對外公開,或者開發人員無意中將鏡像推送到公共的Docker鏡像倉庫中,那么就會導致隱私和敏感信息的泄露。切記永遠不要在Dockerfile中對敏感信息使用COPY或`。

?

為了避免這種情況,請將敏感數據存儲在安全文件系統上,并讓容器進行連接。一般情況下,這個文件系統應該在容器所在的宿主上,或者可通過AWS Elastic Block Storage(EBS)等塊存儲或S3等對象存儲服務來使用。

?

此外,你應避免在Docker鏡像中存儲安全憑證。作為開發人員,有時我們會采用偷懶的做法,在代碼中硬編碼密碼和私鑰。你需要習慣使用-e參數在運行時為Docker容器指定環境變量。

?

你也可以通過env-file,從文件中讀取環境變量。通過CMD或`從第三方來源獲取憑據的自定義腳本也可用于獲取Docker容器所需的相關憑據。

?

不要在容器內存儲數據或日志

?

容器化改變了日志的性質。容器是瞬態、無狀態應用程序的理想選擇。本質上,存儲在運行容器中的所有數據都應該是短暫的,你可能已經注意到,當容器關閉時,數據將丟失。因此,將數據存儲在Docker容器之外的做法更值得推崇。有一些工具可以幫助你提取Docker日志,并將其放在更永久的數據存儲中。

?

在處理Docker日志時需要牢記一點:Docker至少擁有三個級別的日志記錄,即Docker容器、Docker服務和宿主操作系統,你選擇的日志記錄方法應該能夠提取所有級別的日志。

?

不要寫入容器的文件系統

?

每次將內容寫入容器的文件系統都會激活“寫時復制”策略。這會使用存儲驅動程序(deviermapper、overlayfs或其他驅動)創建新的存儲層。在實際應用中,這會給存儲驅動帶來巨大的壓力,特別是使用Devicemapper或BTRFS的情況下。

?

確保容器只向卷中寫入數據。對于小型的臨時文件可以寫入tmpfs,因為tmpfs是僅存在于內存或交換分區中的臨時文件系統。

?

不要運行PID 1

?

這是許多人都不知道的常見問題。

?

Docker中的進程運行時沒有init進程負責清理子進程,所以容器可能會出現僵尸進程,導致意料之外的錯誤。

?

使用tini或dumb-init

?

PID 1在Unix中很特殊,因此在init系統中忽略它通常會導致進程和信號處理錯誤。這會導致類似于容器無法優雅地停止,或本應摧毀的容器出現泄露等問題。

?

僵尸進程指的是運行已經停止,但依然在進程表中占據位置的進程,因為它們的父進程沒有調用wait系統調用進行回收。理論上,每個結束的進程都會非常短暫地呈現僵尸狀態,但有些進程的僵尸狀態會持續很久。

?

如果某個進程會生成新進程,但信號處理的實現不好,無法捕獲子進程的信號并將其終止,那么可以使用Tini或dumb-init。例如,bash腳本就無法正確處理或釋放信號。

?

下面是運行dumb init的示例,其中prepare.sh可以是shell腳本,也可以是用于執行應用程序的命令:

RUN wget -O /usr/local/bin/dumb-init https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64RUN chmod +x /usr/local/bin/dumb-initENTRYPOINT ["/usr/local/bin/dumb-init", "/usr/bin/prepare.sh"]

或者如果你選擇tini,可以參考下面使用Python anaconda conda的示例:

?

RUN conda install --yes -c conda-forge tiniENTRYPOINT ["tini", "-g", "--", "/usr/bin/prepare.sh"]

?

最后,這里是一個更一般的示例,不依賴于任何編程語言:

?

FROM node:13.12.0-slimMAINTAINER?Timothy?Mugayi?<timothy.mugayi@gmail.com>ENV TINI_VERSION='v0.13.0' # Add tini init, see https://github.com/krallin/tini ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tiniRUN chmod +x /tini # Set tini as entrypoint ENTRYPOINT ["/tini", "--"]

在CI/CD中使用Dockerfile格式檢查

?

跟編程語言一樣,Docker也有格式檢查工具。

?

采用格式檢查工具有許多好處,因為它會強制你使用最佳實踐。在CI/CD過程中加入格式檢查,可以幫助團隊避免常見的錯誤,并在構建產品Docker鏡像時建立最佳實踐。可以從hadolint開始,這是一個用Haskell編寫的Dockerfile格式檢查工具,能夠解析Dockerfile成AST,并在AST上執行規則檢查。

?

我們來運行一個示例。要對Docker進行格式檢查,可以執行以下命令:

$ docker run --rm -i hadolint/hadolint < Dockerfile

?

格式檢查完成后會顯示以下結果:

?

上圖中的錯誤碼DL3008“Pin”來自hadolint的錯誤碼描述狀態。固定版本號可以強制構建時安裝特定版本的包,不論緩存中是什么。這個技巧可以減少依賴包意料之外的改變導致的構建錯誤。

?

最后的一點想法

?

在本文中,我們談了很多內容,覆蓋了從安全到Docker鏡像流水線的方方面面。

?

有許多技巧可以讓Docker鏡像更好、更安全。希望這篇文章可以給你帶來一些啟發,幫助你理解應該做什么、不應該做什么,并為你提供一些在構建內部或外部Docker容器鏡像時可以應用的方案。

??

原文鏈接:

https://medium.com/better-programming/docker-best-practices-and-anti-patterns-e7cbccba4f19

本文為CSDN翻譯文章,轉載請注明出處。?


推薦閱讀

  • 大促下的智能運維挑戰:阿里如何抗住“雙11貓晚”?

  • 20萬個法人、百萬條銀行賬戶信息,正在暗網兜售

  • 當莎士比亞遇見Google Flax:教你用字符級語言模型和歸遞神經網絡寫“莎士比亞”式句子

  • Hyperledger Fabric 和企業級以太坊,誰才是企業首選?

  • 面試時遇到「看門狗」脖子上掛著「時間輪」,我就問你怕不怕?

  • 同期兩篇 Nature:運行溫度高于 1K 的量子計算平臺問世!

  • GitHub 標星 10,000+,Apache 頂級項目 ShardingSphere 的開源之路

    真香,朕在看了!

總結

以上是生活随笔為你收集整理的从安全到镜像流水线,Docker 最佳实践与反模式一览的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。