This is a workaround, I don't really like but it works
To allow cloning templates with bind mounts (Useful if you have folders that are shared, so you know that the folder will be accessible in clones), open /usr/share/perl5/PVE/API2/LXC.pm
and find this part of the code (in my current version, it is line 1413)
foreach my $opt (keys %$src_conf) {
next if $opt =~ m/^unused\d+$/;
my $value = $src_conf->{$opt};
if (($opt eq 'rootfs') || ($opt =~ m/^mp\d+$/)) {
my $mp = PVE::LXC::Config->parse_volume($opt, $value);
if ($mp->{type} eq 'volume') {
my $volid = $mp->{volume};
my ($sid, $volname) = PVE::Storage::parse_volume_id($volid);
$sid = $storage if defined($storage);
my $scfg = PVE::Storage::storage_config($storecfg, $sid);
if (!$scfg->{shared}) {
$sharedvm = 0;
warn "found non-shared volume: $volid\n" if $target;
}
$rpcenv->check($authuser, "/storage/$sid", ['Datastore.AllocateSpace']);
if ($full) {
die "Cannot do full clones on a running container without snapshots\n"
if $running && !defined($snapname);
$fullclone->{$opt} = 1;
} else {
# not full means clone instead of copy
die "Linked clone feature for '$volid' is not available\n"
if !PVE::Storage::volume_has_feature($storecfg, 'clone', $volid, $snapname, $running, {'valid_target_formats' => ['raw', 'subvol']});
}
$mountpoints->{$opt} = $mp;
push @$vollist, $volid;
} else {
# TODO: allow bind mounts?
die "unable to clone mountpint '$opt' (type $mp->{type})\n";
}
} elsif ($opt =~ m/^net(\d+)$/) {
# always change MAC! address
my $dc = PVE::Cluster::cfs_read_file('datacenter.cfg');
my $net = PVE::LXC::Config->parse_lxc_network($value);
$net->{hwaddr} = PVE::Tools::random_ether_addr($dc->{mac_prefix});
$newconf->{$opt} = PVE::LXC::Config->print_lxc_network($net);
} else {
# copy everything else
$newconf->{$opt} = $value;
}
}
After finding this part of the code, go to the # TODO: allow bind mounts?
section and add this check:
if ($mp->{type} eq 'bind') {
$newconf->{$opt} = $value;
} else {
# TODO: allow bind mounts?
die "unable to clone mountpint '$opt' (type $mp->{type})\n";
}
This will copy the bind mount as is! Keep in mind that this may cause issues when you clone LXC with bind mounts that should not be cloned in a different LXC container.
End result:
foreach my $opt (keys %$src_conf) {
next if $opt =~ m/^unused\d+$/;
my $value = $src_conf->{$opt};
if (($opt eq 'rootfs') || ($opt =~ m/^mp\d+$/)) {
my $mp = PVE::LXC::Config->parse_volume($opt, $value);
if ($mp->{type} eq 'volume') {
my $volid = $mp->{volume};
my ($sid, $volname) = PVE::Storage::parse_volume_id($volid);
$sid = $storage if defined($storage);
my $scfg = PVE::Storage::storage_config($storecfg, $sid);
if (!$scfg->{shared}) {
$sharedvm = 0;
warn "found non-shared volume: $volid\n" if $target;
}
$rpcenv->check($authuser, "/storage/$sid", ['Datastore.AllocateSpace']);
if ($full) {
die "Cannot do full clones on a running container without snapshots\n"
if $running && !defined($snapname);
$fullclone->{$opt} = 1;
} else {
# not full means clone instead of copy
die "Linked clone feature for '$volid' is not available\n"
if !PVE::Storage::volume_has_feature($storecfg, 'clone', $volid, $snapname, $running, {'valid_target_formats' => ['raw', 'subvol']});
}
$mountpoints->{$opt} = $mp;
push @$vollist, $volid;
} else {
if ($mp->{type} eq 'bind') {
$newconf->{$opt} = $value;
} else {
# TODO: allow bind mounts?
die "unable to clone mountpint '$opt' (type $mp->{type})\n";
}
}
} elsif ($opt =~ m/^net(\d+)$/) {
# always change MAC! address
my $dc = PVE::Cluster::cfs_read_file('datacenter.cfg');
my $net = PVE::LXC::Config->parse_lxc_network($value);
$net->{hwaddr} = PVE::Tools::random_ether_addr($dc->{mac_prefix});
$newconf->{$opt} = PVE::LXC::Config->print_lxc_network($net);
} else {
# copy everything else
$newconf->{$opt} = $value;
}
}
And that's it! This doesn't fix container cloning via the the dashboard but it does work via the command line interface. Tested with pve-manager/6.2-15/48bd51b6 (running kernel: 5.4.65-1-pve)