[solved] Setting up systemd service (e.g. mysql) in machinectl container with a `/var/lib/mysql` bind mount?

I can run mysql in a container like this:

  containers.whatever = {
    ephemeral = true;
    autoStart = true;
    privateNetwork = true;
    config = ./container.nix;
    extraFlags = [ "--private-users=pick --private-users-ownership=auto" ];

    hostAddress = "192.168.100.10";
    localAddress = "192.168.100.11";
  };
}

then in container.nix:

 services.mysql = {
    enable = true;
    package = pkgs.mariadb;

};

This works fine on its own. But:

  • The container is ephemeral ( I want it this way)
  • Even if it wasn’t my system is running impermanence so the contents will get lost on reboot anyway

What I’d do in docker is mount /var/lib/mysql inside the container so the data gets written to persistent storage outside the container like so:

  containers.whatever = {
    ephemeral = true;
    autoStart = true;
    privateNetwork = true;
    config = ./container.nix;
    extraFlags = [ "--private-users=pick --private-users-ownership=auto" ];
    bindMounts = {
      "/var/lib/mysql" = {
        hostPath = "/persist/mysql";
        isReadOnly = false;
      };
    };
    hostAddress = "192.168.100.10";
    localAddress = "192.168.100.11";
  };
}

The problem is that when its a bind mount, whatever I do with file permissions outside the container, if /var/lib/mysql is a bind mount mysql in the container gives me:

mysql.service: Failed to set up special execution directory in /var/lib

I played around setting uids on the mysql service on the container and setting DynamicUsers=off on the systemd service but faced the same issue.

A workaround is to bind mount /var/lib but then the persisted directory gets filled with anything in the container that writes to /var/lib and not just mysql’s data.

I’d like a solution that works for any service, not just mysql.

Is there a clean way to do this? Thanks!

edit: A little more debugging:

The bind mount inside the container is always owned by uid 65534 (nobody) inside the container but 0 (root) outside the container. That’s certainly the issue, how can I set the ownership of the bind mount?

typically I worked out the answer to my own question.

Turn off private users, which is slightly annoying.

It would be better if I could find a way to set the UIDs inside/outside the container so that the uids aren’t shared beyond that

edit: to follow up again, to also utilise private users:

  1. Pick a specific starting uid for the container to use extraFlags = [ "--private-users=65536 --private-users-ownership=auto" ];
  2. Outside the container change the ownership of the file you’re bind mounting to that ID, it’ll map to 0 (root) in the container: chown 65536:65536 /persist/mysql