Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Gunicorn graceful stopping with docker-compose

Tags:

I find that when I use docker-compose to shut down my gunicorn (19.7.1) python application, it always takes 10s to shut down. This is the default maximum time docker-compose waits before forcefully killing the process (adjusted with the -t / --timeout parameter). I assume this means that gunicorn isn't being gracefully shut down. I can reproduce this with:

docker-compose.yml:

version: "3"
services:
  test:
    build: ./
    ports:
      - 8000:8000

Dockerfile:

FROM python

RUN pip install gunicorn

COPY test.py .

EXPOSE 8000
CMD gunicorn -b :8000 test:app

test.py

def app(_, start_response):
    """Simplest possible application object"""
    data = b'Hello, World!\n'
    status = '200 OK'
    response_headers = [
        ('Content-type', 'text/plain'),
        ('Content-Length', str(len(data)))
    ]
    start_response(status, response_headers)
    return iter([data])

Then running the app with:

docker-compose up -d

and gracefully stopping it with:

docker-compose stop

version:

docker-compose version 1.12.0, build b31ff33

I would prefer to allow gunicorn to stop gracefully. I think it should be able to based on the signal handlers in base.py.

All of the above is also true for updating images using docker-compose up -d twice, the second time with a new image to replace the old one.

Am I misunderstanding / misusing something? What signal does docker-compose send to stop processes? Shouldn't gunicorn be using it? Should I be able to restart my application faster than 10s?

like image 295
Jon G Avatar asked Apr 24 '17 09:04

Jon G


1 Answers

TL;DR

Add exec after CMD in your dockerfile: CMD exec gunicorn -b :8000 test:app.

Details

I had the same issue, when I ran docker exec my_running_gunicorn ps aux, I saw something like:

gunicorn     1  0.0  0.0   4336   732 ?        Ss   10:38   0:00 /bin/sh -c gunicorn -c gunicorn.conf.py vision:app
gunicorn     5  0.1  1.1  91600 22636 ?        S    10:38   0:00 /usr/local/bin/python /usr/local/bin/gunicorn -c gunicorn.conf.py vision:app
gunicorn     8  0.2  2.5 186328 52540 ?        S    10:38   0:00 /usr/local/bin/python /usr/local/bin/gunicorn -c gunicorn.conf.py vision:app

The 1 PID is not the gunicorn master, hence it didn't receive the sigterm signal.

With the exec in the Dockerfile, I now have

gunicorn     1 32.0  1.1  91472 22624 ?        Ss   10:43   0:00 /usr/local/bin/python /usr/local/bin/gunicorn -c gunicorn.conf.py vision:app
gunicorn     7 45.0  1.9 131664 39116 ?        R    10:43   0:00 /usr/local/bin/python /usr/local/bin/gunicorn -c gunicorn.conf.py vision:app

and it works.

like image 90
deterralba Avatar answered Sep 25 '22 10:09

deterralba