I realise this is now an old thread, but recently I was struggling to get a Rails app to reliably run on Alpine in a standard 256Mb fly VM, and after following the advice given here to add swap, the app has been running perfectly.
Now that it’s working, I’d like to understand a bit more about the specific formula used here to calculate the size of the swapfile (just to satisfy my own curiosity).
Apologies if I get some of the Bash / POSIX terminology wrong here.
Breaking it down:
fallocate -l <length in bytes> _swapfile
fallocate
allocates space on disk
-l <length>
is the number of bytes to allocate
_swapfile
is the file name to assign to the allocated space
The length argument comes from the result of an arithmetic expansion (double parentheses), i.e. $(( ))
.
The arithmetic expression comes from the output of another (non-arithmetic) expansion, $( )
.
The command in that subshell is:
stat -f -c <format> .
stat
displays file or filesystem status
-f
indicates that we’re interested in the filesystem (not file) status
-c <format>
specifies a format for the output
.
is the current directory
Finally, the format itself is:
"(%a*%s/10)*7"
%a
is the number of free blocks available to non-superuser
%s
is the block size (e.g. 4096)
10
is a constant
7
is a constant
…which can be rewritten as:
( <free blocks> * <block size> / 10 ) * 7
<free blocks> * <block size>
obviously computes the total amount of free space (in bytes) available.
Am I right in assuming that the subsequent division by 10 and multiplication by 7 is simply a way of saying:
please allocate 70% of all remaining available space for swap
And I’m guessing that reasons for allocating a percentage of remaining available space (as opposed to allocating a fixed value, such as fallocate -l 512MB
) are:
- Removes the risk of not having enough space left to allocate (assuming that
fallocate
will fail if the specified length exceeds available free space)
- Unused disk space in containers is basically wasted, so might as well use most of it for swap? (especially for web servers/apps that don’t write much, if anything, to disk after booting)
I suppose the only downside is that, since this has to be one of the last lines in the Dockerfile
(as it needs to calculate available space after all of the code & dependencies are copied, that layer can’t be cached?