Create docker container from nix shell

I have a nix shell which I use for cross compiling software to another system. After being able to compile locally I try to create a docker container from my nix shell to allow the ci (in my company we use https://concourse-ci.org/) to compile it every time I change the code.

However it seems as if it doesn’t create the same environment as in my shell (In the shell I can compile and it the container it complaints about missing binaries which I’m trying to add than if I can find out where they are)

My setup is

nix/env.nix whith shared content

{ pkgs, rust, target ? null }:

let
  baseDeps = with pkgs; [
    libusb1
  ];
 winDeps = with pkgs.pkgsCross.mingwW64; [
   windows.mcfgthreads
   windows.pthreads
   buildPackages.gcc
   buildPackages.binutils
 ];
in
{
  nativeBuildInputs = [
    rust

    pkgs.pkg-config
    pkgs.cmake

    # these I added because the container
    # complains of not having them while nix-shell does not
    pkgs.coreutils-full
    pkgs.bashInteractive
    pkgs.gnugrep
    pkgs.stdenv
    pkgs.gnutar
    pkgs.gzip
    pkgs.curl
    pkgs.wget
    pkgs.cacert.out
    pkgs.findutils
    pkgs.buildPackages.gcc
    pkgs.binutils
  ];
  buildInputs = if
    builtins.isNull target
   then
     baseDeps ++ [ pkgs.libudev0-shim ]
   else
     baseDeps ++ winDeps;

  # Here we can put Environment Variables
  CXXFLAGS="-I${pkgs.libusb1.dev}/include/libusb-1.0/";
  MCFGTHREAD_DLL = if
    builtins.isNull target
   then
     null
   else
     "${pkgs.pkgsCross.mingwW64.windows.mcfgthreads}/bin/";
}

shell.nix to create the shell for cross compiling

let
  sources = import ./nix/sources.nix;
  target = "x86_64-pc-windows-gnu";
  rust = import ./nix/rust.nix { inherit sources; target = target; };
  pkgs = import sources.nixpkgs {};
in

let
  enviroment = import ./nix/env.nix { pkgs=pkgs; rust=rust; target=target; };
in
  pkgs.pkgsCross.mingwW64.mkShell enviroment

docker-win.nix to create the same environment in a docker container

let
  sources = import ./nix/sources.nix;
  target = "x86_64-pc-windows-gnu";
  rust = import ./nix/rust.nix { inherit sources; target = target; };
  pkgs = import sources.nixpkgs {};
in

let
  enviroment = import ./nix/env.nix { pkgs=pkgs; rust=rust; target=target; };
in
  pkgs.dockerTools.buildImage {
    name = "rust-mingw";
    tag = "latest";
    contents = enviroment.buildInputs ++ enviroment.nativeBuildInputs;
    config = {
      Env = builtins.attrValues
        (builtins.mapAttrs
          (name: value: "${name}=${value}")
          (builtins.removeAttrs enviroment ["buildInputs" "nativeBuildInputs" ]));
    };
  }

there are some other files in the nix folder to setup rust and pinning (with niv).

Does anybody know how to adjust my docker-win.nix file to create the same environment as in nix-shell? I would love to be able to put something like pkgs.pkgsCross.mingwW64.mkShell in my container but have not found a way.

Any help is highly appreciated

I don’t know how to do this, but I’m also interested in creating docker containers identical to the nix shell you get from mkShell.

I found nix-mk-shell-bin which says it’s “nix shell but at build time”.

Well… since docker tools takes your derivation created at build time my thinking was that this would fix my problem easily.

It didn’t quite work for me, but maybe I have something wrong. Here is the issue describing my attempt, hope it helps!

https://github.com/rrbutani/nix-mk-shell-bin/issues/1

I haven’t made much progress with this so far (partly because I did not have much time). The best I’ve found to address this issue is this https://github.com/teamniteo/nix-docker-base. I think you can use a nix expression there and export it in a docker container.

Haven’t tried it yet, but maybe it helps you.

There are probably simpler answers since I haven’t tried to do this exact thing, but if nothing else you may be able to pull on how existing projects accomplish it:

1 Like

Bumping an old thread, but devenv 0.6 added a way to generate a shell/processes container from a developer environment.

1 Like

You are probably looking for buildNixShellImage/streamNixShellImage which has been added November 2022 in https://github.com/NixOS/nixpkgs/pull/172736.
See this examples file for ways how to use it.

This worked for me and seems to be what you usually want:

{
  pkgs ? import <nixpkgs> {},
}:
pkgs.dockerTools.streamNixShellImage {
  name = "name-of-the-image";
  tag = "latest";
  drv = (import ./shell.nix) { inherit pkgs; };
}

Build, load and run it like this:

nix-build docker-shell.nix && ./result | docker load && docker run --mount type=bind,source="$(pwd)",target=/build -it name-of-the-image:latest
1 Like