Flake-part (haskell) and dockerTools.buildImage

It’s been a while since I had the pleasure of working with Nix (and Haskell), so instead of just continue writing flakes as I did a couple of years ago I looked around and found https://flake.parts/. I have to say I think I really like it!

Just one little problem I ran into that I can’t figure out on my own: how do I build a Docker image that actually works?

My flake.nix looks like this

{
  nixConfig = {
    extra-substituters = [ "https://magthe-fabled.cachix.org" ];
    extra-trusted-public-keys = [
      "magthe-fabled.cachix.org-1:tx/C7RcEutcCxnAiSRgA94h2LYwKFAW6pCvrtzjJo4E="
    ];
  };

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs?ref=nixpkgs-unstable";
    systems.url = "github:nix-systems/default";
    flake-parts.url = "github:hercules-ci/flake-parts";
    haskell-flake.url = "github:srid/haskell-flake";
  };

  outputs = inputs:
    inputs.flake-parts.lib.mkFlake { inherit inputs; } {
      systems = import inputs.systems;
      imports = [ inputs.haskell-flake.flakeModule ];

      perSystem = { self', system, lib, config, pkgs, ... }:
        let hsPkgs = pkgs.haskell.packages.ghc96;
        in {
          haskellProjects.default = {
            basePackages = hsPkgs;
            packages = { };
            devShell = { hlsCheck.enable = false; };
            autoWire = [ "packages" ];
          };

          devShells.default = pkgs.mkShell {
            name = "tehst custom development shell";
            inputsFrom = [ config.haskellProjects.default.outputs.devShell ];
            nativeBuildInputs = with pkgs; [
              hsPkgs.cabal-fmt
              hsPkgs.haskell-language-server
              hsPkgs.hlint
            ];
          };

          packages.app = self'.packages.tehst;
          packages.default = pkgs.dockerTools.buildImage {
            name = "tehst";
            tag = "latest";
            created = "now";
            copyToRoot = pkgs.buildEnv {
              name = "image-root";
              paths = [ self'.packages.tehst ];
              pathsToLink = [ "/bin" ];
            };
            config = {
              Cmd = [ "/bin/tehst" ];
              ExposedPorts = { "8080/tcp" = { }; };
              WorkdingDir = "/";
            };
          };
        };
    };
}

An image is built and it has the expected contents, I can run podman import result tehst:latest to get it into the local store. However, the image can’t be started:

> podman run localhost/tehst:latest
Error: no command or entrypoint provided, and no CMD or ENTRYPOINT from image

and indeed, when looking at the image using podman inspect there’s no mention of anything that I’ve specified in config for dockerTools.buildImage. What’s happening here? (Could the problem be that there’s an argument to perSystem that’s called config? Yes, I’m guessing wildly.)

Quite possibly I’m going about this in the wrong way. What am I missing? What should I change to make it work?

I tend to use podman load < result. I believe podman import doesn’t preserve the image metadata.

1 Like

That’s indeed the case. I’ve just recently started using podman and I have to say this thing was very surprising.

1 Like