Nix會替代Docker嗎? - Replit

banq發表於2021-11-30

Docker是用於構建和部署容器的工具包,Nix是包和配置管理器。這些工具確實有一些重疊:它們都可以用於建立可重現的環境。可重現的環境是可以以相同的方式(最好是逐位)從頭開始重新建立的環境。實際上,這意味著在環境之間具有相同的工具、版本和配置。

可重現的環境有助於確保專案中的所有開發人員都擁有完全相同的工具集。此外,您可以在與生產環境類似的環境中進行開發——從而減少部署時的意外情況。

這兩種工具都可以解決“它在我的機器上可以工作”的古老問題。

雖然這兩種工具都旨在解決這個問題,但它們採用了不同的方法。

 

使用 Docker 的可複製環境

Docker 提供了建立容器映象的工具。映象儲存容器的內容和配置。這通常是檔案系統、一些環境變數和執行命令。

從映象中,您可以建立功能相同的新容器,即使在不同的機器上也是如此。

您可以將映象分發給其他開發人員,為他們提供相同的環境,或者您可以使用它們將您的服務交付到生產環境。

Docker 映象可以通過Dockerfile. 該檔案告訴 docker 執行以構建映象的命令。這可能包括從主機系統複製檔案或使用包管理器(如 apt 或 apk)安裝包。

FROM node:12-alpine
RUN apk add --no-cache python g++ make
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]

Docker 將建立一個用於構建映象的新容器。在Dockerfile執行命令之前,將為每個命令建立一個新的檔案系統層。Docker 使用聯合檔案系統,它允許堆疊多個檔案系統或目錄以顯示為單個檔案系統。

由於每個命令都有自己的層,Docker 可以檢測哪些層仍然有效,哪些層在對專案進行更改後需要重建。正確排序命令將導致更快的 docker 映象重建。

每個層也可以跨多個映象共享。當從同一個基礎 Docker 映象構建多個 docker 映象時,這很有用。例如,上面Dockerfile有node:12-alpine作為基礎 Docker 映象。來自的層node:12-alpine只需要存在於一個地方,並且可以被其他 Docker 映象共享。

構建映象後,可以對其進行命名、標記和上傳到映象登錄檔,以便輕鬆與他人共享。

雖然映象允許可重現的 Docker 容器,但 Docker 不保證建立的映象是可重現的——如果你docker build用同一個Dockerfile映象執行兩次,你可能會得到 2 個以不同方式執行的映象。例如,第三方包可能會悄悄更新並導致 損壞。積極固定依賴版本有幫助,但並不能完全防止這個問題。

另一個值得注意的是,Docker 只允許通過從單個層繼承來組合映象。您可以在 中為新映象指定基本映象Dockerfile,但不能拍攝 2 張​個映象並將它們組合起來。如果您想要一個帶有nodeand的容器rustc,則不能組合node和rust映象。您必須從node映象開始並在 中rustc手動安裝,Dockerfile反之亦然。

 

Nix 的可重現環境

Nix 採用第一原則方法進行可重複構建和包管理。Nix 提供了一個完整的構建系統,允許以隔離的方式構建包。

要構建任何包,您需要:

  1. 使用構建包所需的所有工具構建環境。
  2. 執行構建指令碼以執行所有構建步驟。

對每個包重複此過程,Nix 竭盡全力確保內建包的每個環境都是可重現的。Nix 將限制網路訪問、檔案系統訪問,有時甚至在構建過程中在沙盒容器中執行,以防止在包構建過程中受到任何型別的外部影響。

包可以依賴於其他包,這會建立一個大型依賴圖,Nix 將在此過程中遍歷並構建包。

碰巧的是,您可以通過向該圖中新增新節點來建立新的可重現環境。然後你可以使用 Nix 來完成包構建的第 1 部分:構建環境。

在開發中,您可能不希望或不需要 Nix 執行第 2 步。相反,您可以讓 Nix 將您放入 bash shell,您可以在其中自己執行構建命令。

Nix 附帶了一個名為的工具nix-shell,它可以為您做到這一點。將shell.nix檔案新增到專案的根目錄,然後nix-shell將您帶入一個包含所有指定輸入包可用的環境。

例子:

{ pkgs ? import <nixpkgs> {} }:

pkgs.mkShell {
    nativeBuildInputs = [ pkgs.rustc pkgs.cargo ];
}

Nix 在這裡不使用容器,它只修改環境變數。例如,將二進位制包新增到PATH環境變數中。

由於 Nix 為可重複性提供了強有力的保證,因此共享這shell.nix一切就是為開發人員提供功能等效的開發環境所需要的1

與 Docker 不同,Nix 是一個成熟的包管理器。這使得組合環境變得微不足道。以上面來自 Docker 的示例為例,如果我們希望 node 和 rust 在同一環境中,只需告訴 Nix 它們都是構建輸入:

{ pkgs ? import <nixpkgs> {} }:

pkgs.mkShell {
    nativeBuildInputs = [ pkgs.rustc pkgs.cargo pkgs.nodejs-16_x ];
}

 

你應該使用哪個?

在考慮這個問題之前,我們應該回到開頭:Docker 和 Nix 是完全不同的工具。

Docker 映象只是 Docker 提供的一小部分。Docker 為整個容器生態系統提供工具。

而 Nix 主要設計用於以可重複的方式構建包和環境。

如果您只追求可複製的開發環境,Nix 將為您提供良好的服務。

如果您正在尋找一種方法來構建、打包和部署您自己的服務。Docker 將提供更豐富的工具。畢竟,容器是當今部署 Web 服務的事實上的方式。

即便如此,docker 映象構建仍有很多不足之處。幸運的是,我有一張王牌:Nix 可用於構建 Docker 映象。

{ pkgs ? import <nixpkgs> { }
, pkgsLinux ? import <nixpkgs> { system = "x86_64-linux"; }
}:

pkgs.dockerTools.buildImage {
  name = "cowsay-container";
  config = {
    Cmd = [ "${pkgsLinux.cowsay}/bin/cowsay" "I'm a container" ];
  };
}

也許我們可以兩全其美:

  • 通過 Nix 可重現的 Docker 映象
  • 通過容器簡化部署

 

Nix 會替代 Docker 嗎?

不,這些工具實現了不同的目標,但是它們可以結合使用以提供兩全其美的效果:可重複構建和容器化部署。

 

相關文章