將 Docker-in-Docker 用於 CI 或測試環境前請慎重考慮

將 Docker-in-Docker 用於 CI 或測試環境前請慎重考慮

Docker-in-Docker 是一個虛擬化的 Docker 守護程式環境,在容器本身內執行以建置容器映像。 建立 Docker-in-Docker 的主要目的是幫助開發 Docker 本身。 很多人用它來運行 Jenkins CI。 乍一看這似乎很正常,但隨後出現的問題可以透過在 Jenkins CI 容器中安裝 Docker 來避免。 本文告訴您如何執行此操作。 如果您對沒有詳細資訊的最終解決方案感興趣,請閱讀本文的最後一部分「解決問題」。

將 Docker-in-Docker 用於 CI 或測試環境前請慎重考慮

Docker-in-Docker:“好”

兩年多前我投入了 Docker ——有特權並寫道 dind 的第一個版本。 目標是幫助核心團隊更快開發 Docker。 在 Docker-in-Docker 出現之前,典型的開發週期如下所示:

  • 駭客攻擊;
  • 建造;
  • 停止正在執行的 Docker 守護程式;
  • 啟動新的 Docker 守護程式;
  • 測試;
  • 重複循環。

如果你想製作一個漂亮的、可複製的元件(即在容器中),那麼它就會變得更加複雜:

  • 駭客攻擊;
  • 確保 Docker 的工作版本正在運作;
  • 使用舊 Docker 建置新 Docker;
  • 停止 Docker 守護程式;
  • 啟動一個新的 Docker 守護程式;
  • 測試;
  • 停止新的 Docker 守護程式;
  • 重複。

隨著 Docker-in-Docker 的出現,這個過程變得更加簡單:

  • 駭客攻擊;
  • 組裝+發射一站式完成;
  • 重複循環。

這樣不是好很多嗎?

將 Docker-in-Docker 用於 CI 或測試環境前請慎重考慮

Docker-in-Docker:“糟糕”

然而,與普遍看法相反,Docker-in-Docker 並不是 100% 的明星、小馬和獨角獸。 我的意思是,開發人員需要注意幾個問題。

其中之一涉及 LSM(Linux 安全模組),例如 AppArmor 和 SELinux:運行容器時,「內部 Docker」可能會嘗試套用與「外部 Docker」發生衝突或混淆的安全性設定檔。 這是在嘗試合併 –privileged 標誌的原始實現時最難解決的問題。 我的更改有效,所有測試都會在我的 Debian 機器和 Ubuntu 測試虛擬機上通過,但它們會在 Michael Crosby 的機器上崩潰並燒毀(我記得他有 Fedora)。 我不記得問題的確切原因,但這可能是因為 Mike 是使用 SELINUX=enforce 的聰明人(我使用了 AppArmor),而我的更改沒有考慮 SELinux 設定檔。

Docker-in-Docker:“邪惡”

第二個問題與 Docker 儲存驅動程式有關。 當您執行 Docker-in-Docker 時,外部 Docker 在常規檔案系統(EXT4、BTRFS 或任何您擁有的系統)之上運行,而內部 Docker 在寫入時複製系統(AUFS、BTRFS、Device Mapper)之上運行等等)。,取決於配置為使用外部Docker 的內容)。 這會產生許多不起作用的組合。 例如,您將無法在 AUFS 之上執行 AUFS。

如果您在 BTRFS 之上運行 BTRFS,它首先應該可以工作,但是一旦存在嵌套子卷,刪除父子卷將失敗。 Device Mapper 模組沒有命名空間,因此如果多個 Docker 實例在同一台電腦上運行它,它們都將能夠看到(並影響)彼此以及容器備份設備上的映像。 這不好。

有一些解決方法可以解決其中許多問題。 例如,如果你想在 Docker 內部使用 AUFS,只要將 /var/lib/docker 資料夾變成一個磁碟區就可以了。 Docker 已向 Device Mapper 目標名稱添加了一些基本命名空間,這樣如果多個 Docker 呼叫在同一台電腦上運行,它們就不會互相干擾。

然而,這樣的設定一點也不簡單,從這些可以看出 用品 在 GitHub 上的 dind 儲存庫中。

Docker-in-Docker:情況變得更糟

建置緩存怎麼樣? 這也可能相當困難。 人們經常問我「如果我運行 Docker-in-Docker,我如何使用主機上託管的映像,而不是將所有內容拉回我的內部 Docker 中」?

一些有進取心的人嘗試將 /var/lib/docker 從主機綁定到 Docker-in-Docker 容器。 有時他們會與多個容器共用 /var/lib/docker 。

將 Docker-in-Docker 用於 CI 或測試環境前請慎重考慮
您想破壞您的資料嗎? 因為這正是會損壞您的資料的原因!

Docker 守護程式顯然被設計為具有對 /var/lib/docker 的獨佔存取權。 其他任何東西都不應「觸摸、戳或戳」位於此資料夾中的任何 Docker 檔案。

為什麼會這樣呢? 因為這是開發 dotCloud 時學到的最慘痛教訓之一的成果。 dotCloud 容器引擎透過讓多個進程同時存取 /var/lib/dotcloud 來運作。 諸如原子檔案替換(而不是就地編輯)、使用諮詢鎖和強制鎖定填充程式碼以及 SQLite 和 BDB 等安全系統的其他實驗等狡猾的技巧並不總是有效。 當我們重新設計容器引擎(最終成為 Docker)時,重大設計決策之一是將所有容器操作整合到單一守護程序下,以消除所有並發廢話。

不要誤會我的意思:完全有可能製造出涉及多個流程和現代並行控制的優質、可靠和快速的東西。 但我們認為使用 Docker 作為唯一的參與者來編寫和維護程式碼更簡單、更容易。

這表示如果您在多個 Docker 實例之間共用 /var/lib/docker 目錄,則會出現問題。 當然,這是可行的,尤其是在測試的早期階段。 “聽著,媽媽,我可以作為 docker 運行 ubuntu!” 但嘗試一些更複雜的事情,例如從兩個不同的實例中提取相同的圖像,你會看到世界在燃燒。

這意味著,如果您的 CI 系統執行建置和重建,則每次重新啟動 Docker-in-Docker 容器時,您都有可能將核武放入其緩存中。 這一點都不酷!

解決方案

讓我們退後一步。 您真的需要 Docker-in-Docker 還是您只是希望能夠運行 Docker 並從 CI 系統建置和運行容器和映像,而 CI 系統本身位於容器中?

我敢打賭大多數人都想要後一種選擇,這意味著他們希望像 Jenkins 這樣的 CI 系統能夠運行容器。 最簡單的方法就是將 Docker 套接字插入 CI 容器中,並將其與 -v 標誌關聯起來。

簡而言之,當您執行 CI 容器(Jenkins 或其他)時,請勿與 Docker-in-Docker 一起破解某些內容,而是使用以下行啟動它:

docker run -v /var/run/docker.sock:/var/run/docker.sock ...

該容器現在可以存取 Docker 套接字,因此能夠運行容器。 除了運行“子”容器之外,它將啟動“兄弟”容器。

使用官方 docker 映像(包含 Docker 二進位)嘗試此操作:

docker run -v /var/run/docker.sock:/var/run/docker.sock 
           -ti docker

它的外觀和工作方式類似於 Docker-in-Docker,但它不是 Docker-in-Docker:當此容器建立其他容器時,它們將在頂級 Docker 中建立。 您不會遇到嵌套的副作用,並且程序集快取將在多個呼叫之間共用。

注意:本文的先前版本建議將 Docker 二進位檔案從主機連結到容器。 現在這已經變得不可靠了,因為 Docker 引擎不再涵蓋靜態或近靜態庫。

因此,如果您想使用 Jenkins CI 中的 Docker,您有 2 個選擇:
使用基本映像打包系統(即,如果您的映像是基於 Debian,則使用 .deb 套件)和 Docker API 安裝 Docker CLI。

一些廣告🙂

感謝您與我們在一起。 你喜歡我們的文章嗎? 想看更多有趣的內容? 通過下訂單或推薦給朋友來支持我們, 面向開發人員的雲 VPS,4.99 美元起, 我們為您發明的入門級服務器的獨特模擬: VPS (KVM) E5-2697 v3(6 核)10​​4GB DDR480 1GB SSD 19Gbps XNUMX 美元或如何共享服務器的全部真相? (適用於 RAID1 和 RAID10,最多 24 個內核和最多 40GB DDR4)。

Dell R730xd 在阿姆斯特丹的 Equinix Tier IV 數據中心便宜 2 倍? 只有這裡 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 電視低至 199 美元 在荷蘭! Dell R420 - 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB - 99 美元起! 閱讀 如何建設基礎設施公司同級使用價值730歐元的Dell R5xd E2650-4 v9000服務器一分錢?

來源: www.habr.com

添加評論