How to synchronize files between a NixOS declarative container and local system path (equivalent of docker-compose volumes functionality)?

I have NixOS 22.11 set up on a local workstation.

I use extra-container package, which can run declarative NixOS containers like imperative containers, without system rebuilds.

I’m trying to run a demo container. It downloads and uzips woocommerce inside container and i want to synchronize these files between the container and my local system path. The main purpose is to learn nix better. In a docker-compose I can could have used config like this:

volumes:
  - <local-path>:<container-path>

How can I achieve it in a NixOS container that does not use docker?

I tried these configs, but my local system directory remains empty:

fileSystems."/var/www/demo/wp-content/plugins/woocommerce" = {
    device = "/root/woocommerce";
    options = [ "bind" ];
    # noCheck = true;
  }; 
};


serviceConfig = {
  BindPaths = [ "/var/www/demo/wp-content/plugins/woocommerce:/root/woocommerce" ]
};

full config of woo.nix

{ pkgs, ... }:

{
  containers.demo = {
    config = {
      fileSystems."/var/www/demo/wp-content/plugins/woocommerce" = {
        device = "/root/woocommerce";
        options = [ "bind" ];
        # noCheck = true;
      };
      users.users.demo = {
        isSystemUser = true;
        createHome = true;
        group = "demo";
      };
      users.groups.demo = { };

      systemd.services.woo = {
        wantedBy = [ "multi-user.target" ];
        path = with pkgs; [ coreutils wget gzip curl unzip ];
        script = ''
          /run/current-system/sw/bin/curl -L https://downloads.wordpress.org/plugin/woocommerce.7.4.1.zip -o /root/woocommerce.zip &&
          unzip /root/woocommerce.zip -d /root &&
          rm /root/woocommerce.zip
        '';
        serviceConfig = {
          BindPaths = [ "/var/www/demo/wp-content/plugins/woocommerce:/root/woocommerce" ];
          # ReadWriteDirectories = [ "/root/woocommerce" ];
        };
      };
    };
  };
  environment.systemPackages = [ pkgs.coreutils pkgs.wget pkgs.gzip pkgs.curl pkgs.unzip ];
}

I run it with the command:

sudo extra-container create --start <<EOF
$(cat woo.nix)
EOF

What is the best way synchronize files between a NixOS declarative container and a local system?

You are looking for the containers.<name>.bindMounts option:

containers.abc = {
  bindMounts = {
    "/path/in/container" = {
      hostPath = "/path/on/host";
      isReadOnly = true;
    };
  };
  # config = ...
};
1 Like

Thank you it worked! However, it seems to prioritize the state of host directory. I mean this scenario:

  • [on host] directory woocommerce is empty
  • [in container] initial shell script downloads and unpacks woocommerce.zip to “/root/woocommerce”

Expected result: Directory on host should be have the contents of unpacked woocommerce zip.
Observed result: Directory on host was empty and it deleted the contents of woocommerce direcotry in the container.

When i login into container with sudo nixos-container root-login demo and run the shell commands to unpack the zip manually from inside of container, i got the expected result on host: my local directory is populated with the contents from the container path “/root/woocommerce”

Any ideas how can i get the contents form zip downloaded inside container synced without any manual steps?