Multi-platform Docker images with GoReleaser, Podman and GitHub Actions
A few months ago, I published a post on Multi-platform Docker images with GoReleaser and GitHub …
If you run Python inside containers, chances are you have seen Linux’s OOMKiller working at least a couple of times.
This happens because Python sees the entire host’s resources as if they were available for its use.
Then, it may try to allocate more memory than it is allowed to, which causes Linux to kill the process.
To fix that, we may read the actual limits from /sys/fs/cgroup/memory/memory.limit_in_bytes
and set it as the process max address space area.
Example:
import resource
import os
import time
if os.path.isfile('/sys/fs/cgroup/memory/memory.limit_in_bytes'):
with open('/sys/fs/cgroup/memory/memory.limit_in_bytes') as limit:
mem = int(limit.read())
resource.setrlimit(resource.RLIMIT_AS, (mem, mem))
x = bytearray(900*1024*1024) # allocate 900mb
print('ok')
time.sleep(20)
Save it as mem.py
, and lets run some tests:
$ docker run \
--rm \
-m 1G \
-v $PWD:/tmp \
python:rc-alpine \
python /tmp/mem.py
If you run docker stats
in another container, you’ll see it takes ~900Mb of RAM, and everything is fine.
This should work with or without setting the RLIMIT_AS
.
Now, let’s try to change:
-x = bytearray(900*1024*1024) # allocate 900mb
+x = bytearray(4000*1024*1024) # allocate 4000mb
And we’ll see:
$ docker run --rm -m 1G -v $PWD:/tmp python:rc-alpine python /tmp/mem.py
Traceback (most recent call last):
File "/tmp/mem.py", line 10, in <module>
x = bytearray(4000*1024*1024) # allocate 4000mb
MemoryError
OK, but what if we don’t set RLIMIT_AS
? Lets test:
docker run \
--rm \
-m 1G \
-v $PWD:/tmp \
python:rc-alpine \
python -c "x = bytearray(4000*1024*1024); print('ok')"
You’ll see the container gets killed without printing ‘ok’.
I think most of the time you’ll rather have a MemoryError
instead of a SIGKILL
, if that’s the case, running the first snipped in the __init__
of your code might be a good workaround.
I think Python should probably copy something from Java, and either make this the default behavior or hide it behind a flag.
In my perception, most people would expect this to be the default… as well as a lot of other tools (top
for example, but that’s a matter for another post).
As stated before, this is just a workaround.
Its possible it doesn’t work on all distributions, or that it stops working in the future.
Use it carefully.