Swap memory

Hi. Is there a way to configure swap memory for a Fly app? Or is this something that should configured in the Docker image (I’m using alpine:3.13)? I just SSHed into my instance and it looks like there is no swap configured.

# free -m
              total        used        free      shared  buff/cache   available
Mem:            228          83          69          35          74         117
Swap:             0           0           0

Thanks :slight_smile:

2 Likes

Hi, I’ve just confirmed a deploy based on alpine using this as the final line in my Dockerfile:

CMD if [[ ! -z "$SWAP" ]]; then fallocate -l $(($(stat -f -c "(%a*%s/10)*7" .))) _swapfile && mkswap _swapfile && swapon _swapfile && ls -hla; fi; free -m; /app/run

You then need to set SWAP="true" in your fly.toml to enable the swap partition. That flag is needed to allow the container to run correctly under your local docker server.

7 Likes

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:

  1. Removes the risk of not having enough space left to allocate (assuming that fallocate will fail if the specified length exceeds available free space)
  2. 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?

2 Likes

FYI, if people run fly launch on a Rails app these days, they get the following:

In other words, no formula, just a fixed size. One that can be tailored.

2 Likes