首页 > 解决方案 > 如何在 Nix Docker Tools 映像中包含我的源代码?

问题描述

我正在使用 NodeJS 构建 Web 服务器,并且正在使用 Nix 提供的Docker 工具为我的服务器构建图像。

我有以下要转换为.nix文件的 Dockerfile

FROM node:12.20.0-alpine3.11 as build-deps
WORKDIR /hedwig-app
COPY ["package.json", "package-lock.json*", "./"]
RUN npm install
COPY . .
RUN npm run build
EXPOSE 8080
CMD [ "node", "build/index.js" ]

但是,我不知道如何将我的源代码复制到要构建的 Docker 映像中。这是我到目前为止所拥有的

{ pkgs ? import <nixpkgs> {} }:

let
    baseImage = pkgs.dockerTools.pullImage {
        imageName = "alpine";
        imageDigest = "sha256:3c7497bf0c7af93428242d6176e8f7905f2201d8fc5861f45be7a346b5f23436";
        sha256 = "119pbb2nrhs6nvbhhpcd52fqy431ag46azgxvgdmyxrwii97f4ah";
        finalImageName = "alpine";
        finalImageTag = "3.12";
    };
    sourceFiles = builtins.toString ./.;
    gitignoreSrc = pkgs.fetchFromGitHub { 
        owner = "hercules-ci";
        repo = "gitignore";
        # put the latest commit sha of gitignore Nix library here:
        rev = "c4662e662462e7bf3c2a968483478a665d00e717";
        # use what nix suggests in the mismatch message here:
        sha256 = "sha256:1npnx0h6bd0d7ql93ka7azhj40zgjp815fw2r6smg8ch9p7mzdlx";
    };
    inherit (import gitignoreSrc { inherit (pkgs) lib; }) gitignoreSource;
    src = gitignoreSource ./.;
in
    pkgs.dockerTools.buildImage {
        name = "hedwig-api";
        tag = "latest";

        fromImage = baseImage;
        contents = [ pkgs.nodejs ];
        runAsRoot = ''
        mkdir /hedwig-app
        cp -r ${src} /hedwig-app
        npm install
        npm run build
        '';

        config = {
            ExposedPorts = {
                "8080/tcp" = {};
            };
            WorkingDir = "/hedwig-app";
            Cmd = ["node" "build/index.js"];
        };
    }

如何在运行之前将我的源代码复制到图像中npm run build

标签: node.jsdockernix

解决方案


在 Nix 内部,你不能运行npm install. 每个步骤只能做以下两件事之一:

  • 要么在没有网络访问的情况下计算新的存储路径:常规推导
  • 或使用可以访问网络的足够简单的过程产生满足硬编码哈希的输出:固定输出推导

这些约束确保构建极有可能是可重现的。

npm install需要访问网络以获取其依赖项,这将其置于固定输出推导类别中。但是,dockerTools.buildImage将在常规派生中执行它,因此它将无法联系 npmjs 存储库。

出于这个原因,我们一般不能将一个 Dockerfile 直接映射到一系列buildImage调用。相反,我们可以使用 Nix 语言基础架构(如yarn2nixnode2nix或其他语言的各种工具来构建软件。通过这样做,您的构建变得可重现,它往往更具增量性,您不必担心源文件或中间文件最终会出现在您的容器映像中。

我还建议将contents参数限制为 apkgs.buildEnvpkgs.symlinkJoin调用,因为内容被复制到容器的根目录,同时也保留在其存储中。


*:足够简单不包括获取单个资源之外的任何内容,因为这往往太脆弱了。如果出于任何原因,固定输出派生构建器产生了不同的结果,并且修复它的唯一方法是更改​​输出哈希,那么您的整个构建基本上是不可重现的。


推荐阅读