dockerTools.buildImage how to use apt and install packages

basically title

    packages."${system}".default = pkgs.dockerTools.buildImage {
      name = "test-image";
      tag = "latest";
      diskSize = 4096;
      buildVMMemorySize = 1024;

      fromImage = pkgs.dockerTools.pullImage {
      ...
      };

      runAsRoot = '' # this fails due no internet
        apt-get update
        apt-get install -y --no-install-recommends ...
        apt-get clean
        rm -rf /var/lib/apt/lists/*
        pip install --no-cache-dir ...
        '';
      };

Is it possible to use package managers such as apt-get while building the image? Internet access doesn’t seem possible inside nix build and I don’t know if there is a workaround

No, and you should not want to. Nix provides repeatable builds. If you used apt the build would no longer be repeatable because what you get would depend on the current state of the apt repositories.

Instead, you should use nix to put the packages you want in the container to begin with. Or just not use nix if you don’t care about the properties nix gives you.

If you clarify what exactly you are trying to achieve with this we could help you figure out how to do that.

2 Likes

Thank you for the explanation, it makes sense and it’s what I was thinking about it.

My use case is using a single flake for developing, building a docker image and a VM for a test environment. So, a flake with devShells, packages and nixosConfigurations, where the configuration has the build result as virtualisation.oci-containers.containers.<name>.imageFile:

    devShells."${system}".default = pkgs.mkShell {
      ...
    };

    packages."${system}".default = pkgs.dockerTools.buildImage {
      ...
      };

    nixosConfigurations."testVM" = nixpkgs.lib.nixosSystem {
      system = system;
      modules = [
        ...
        {
          virtualisation.docker.enable = true;
          virtualisation.oci-containers.containers."buildResult".imageFile = self.packages."${system}".default;
        }
      ];
    };

But I guess I’m just going to use a VM to build and test the image if there is no easy way to integrate package installation in the buildImage.

Maybe I don’t understand what you want to do but what prevents your from installing the packages into the image ‚the nix way‘ as shown in the wiki: Docker - NixOS Wiki or in the manual Nixpkgs Reference Manual?

I don’t want to install anything in my host machine. The idea is to build and test a Dockerfile, so I’m trying to make the build nix based with dockerTools and then assign it to a VM system configuration. This way, when I execute nixos-rebuild build-vm the Dockerfile will be built and the VM will start with the container to be tested.

Ok I think I understood.

I tried finding a way to build an image from a Dockerfile the other day (wanted to run an image from a main branch of a project I was not in control of) and was not successful.

You could however define a systemd service in your vm that builds and loads the image defined by the Dockerfile.

1 Like

I was hoping to put the Dockerfile build in the toplevel of the flake so I could also test the build without the VM execution. Unfortunately, I didn’t think about package management and so I looked for help.

The systemd service seems like a good approach to automate it. Thanks for the idea!

But if you want to test it locally (without vm) why not just manually run the build or write a short script that does the loading as well and you put that into your devshell?

The devShells are just for LSP availability in my neovim setup and sometimes other linting/formatting tools.

I could indeed just run docker build and start in my own machine. That wouldn’t affect me much but I don’t want to mess my own user docker images/containers list.
I’m going to use the VM to build and run the container just for the sake of trying to seal everything hermetically.

I understand.Then building it with nix would not have helped because you would load and run it on your local system as well. So I guess the systemd approach is probably the best there is.

From my understanding using packages."${system}".default = pkgs.dockerTools.buildImage wouldn’t have loaded the result into my own docker runtime, since my own nixosConfiguration would be untouched. The approach could indeed incur into some assets being present in the nix store but not available in the docker daemon or ran as containers.

The nixosConfiguration I’m using here is just one for nixos-rebuild build-vm, named “testVM” before.

You could also skip the docker container and deploy a neovim setup with nix into your VM instead?

I don’t wan’t to edit anything inside the VM, neovim would be used to edit Dockerfiles, docker-compose, flake.nix, etc. After the development, the VM is built together with the image.

Building and testing the Dockerfile is the final product. Development takes place before and in a different environment: my own machine.

As far as I understand it just builds the image and puts it into the store. You then have to manually load it and run it. This would be done on your local system. You don’t touch your local config but it still would influence your local state.

Yes, but I would only load it in the VM using nixosConfigurations."testVM", nixos-rebuild build-vm and then running the VM.

  • the docker daemon of the host stays untouched
  • the host store indeed is changed
  • the VM has a fresh docker daemon with only the image desired

Right, so you have:

  • A set of packages you want to download
  • You want to bundle them together in a docker container
  • You want to run said packaged docker container in a VM

You can do all of this with nix just fine. You just need to replace apt-get install <pkg> with putting <pkg> in the contents list of the dockertools.buildImage args.

1 Like