Reputation: 497
I'm building a web server using NodeJS, and I'm using the Docker Tools that Nix provides to build images for my server.
I have the following Dockerfile that I'm tring to convert into a .nix
file
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" ]
However, I don't know how to copy my source code into the Docker image to be built. This is what I have so far
{ 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"];
};
}
How could I copy my source code into the image before running npm run build
?
Upvotes: 0
Views: 957
Reputation: 7369
Inside Nix, you can't run npm install
. Each step can only do one of two things:
These constraints ensure that the build is highly likely to be reproducible.
npm install
needs access to the network in order to fetch its dependencies, which puts it in the fixed output derivation category. However, dockerTools.buildImage
will execute it in a regular derivation, so it will fail to contact the npmjs repository.
For this reason, we generally can't map a Dockerfile directly to a series of buildImage
calls. Instead, we can build the software with the Nix language infrastructures, like yarn2nix
, node2nix
or the various tools for other languages.
By doing so, your build becomes reproducible, it tends to be more incremental and you don't have to worry about source files or intermediate files ending up in your container images.
I'd also recommend to limit the contents
parameter to a pkgs.buildEnv
or pkgs.symlinkJoin
call, because the contents are copied to the root of the container while also remaining in its store.
*: sufficiently simple excludes anything beyond fetching a single resource, because that tends to be too fragile. If, for any reason, the fixed output derivation builder produces a different result and the only way to fix it is by changing the output hash, your entire build is essentially not reproducible.
Upvotes: 3