Wait a minute. You installed things in the Template, and in the AppVM you uninstalled them?
Yes. That’s the essence of the decremental approach.
You will have to repeat the uninstall every time you run the AppVM
Sure.
That seems like an awful lot of writes to disk
There are zero writes to disk if the volatile volume is on tmpfs and the root volume has rw=false.
The only 2 problems which remain are:
(A) The additional RAM for the CoW
(B) The extra time for uninstalling packages at each AppVM boot
(A) might not be a big problem with enough physical RAM. AFAIK, the RAM for dom0 can be increased through a GRUB parameter.
(B) seems significant only if lots of packages are removed. It is possible to have 2 templates (e.g. one for more minimalist stuff, another one for office-like bloatware) but that goes against the idea of having a single template (although 2 is still better than 20).
Another method I have tried:
In the template:
apt-get install package1 package2... --download-only
In AppVM X:
apt-get install packageX && apt-get clean
That is still incremental (nothing is actually installed in the template), and it does not solve (A) and (B). It only reverts (B) - more boot-up time for AppVMs using larger software packages. Additionally, it is not quite clear to me what would happen if a package is downloaded in cache (but not installed) and a system update is run. So, additional complication.
As a possible solution to (A) and (B), here is an ugly but effective method (note the time):
root@appvm-AAA:~ # mapfile -t files < <(dpkg -L libreoffice-calc)
root@appvm-AAA:~ # time (for i in "${files[@]}"; do if [ -f "${i}" ]; then ln -sfT /dev/null "${i}"; fi ; done)
real 0m0.177s
user 0m0.096s
sys 0m0.086s
The full test, symlinking all dependencies of libreoffice-calc as well, shows:
real 0m2.691s
user 0m1.302s
sys 0m1.280s
This also solves (A) because (IIUC) symlinking does not modify actual data blocks (resulting in CoW). My test shows that the usage of the 1 GiB RAM based pool, storing the volatile volume, is 0.07% at VM boot (before symlinking) and increases to 0.34% (after symlinking). That is less than 3.5 MiB.
There is only the additional complexity of having to symlink dependencies without damaging any common ones. For example, if package1 and package2 both depend on package3, and AppVM2 needs package2 but removes package1, the automation system should not attempt to symlink package3’s files. I need to learn how to do this (tips are welcome).
Although this is somewhat hacky (and I don’t know if there may be any side effects), it should work for the purpose of reducing the attack surface (the whole point of the current multi-template exercise). No files = nothing to attack, so as long as rc.local runs early enough, we should be OK. With this approach we can have just an unitary template, where we can install whatever we plan to use, and multiple custom-minified AppVMs.
What do you think?
(I am still working on the automation system, so it is not quite polished yet. Maybe something new will come out along the way)