skip to Main Content

I have a flask application served by gunicorn.
All of this run inside a docker container.
When sending a POST request from the host (ubuntu) machine, on my computer, the server response is correct

On my VPS (debian 10), though, with the same docker image, I have an error from gunicorn (cf title)

[2024-02-28 17:08:13 +0000] [1] [CRITICAL] WORKER TIMEOUT (pid:538)
[2024-02-28 17:08:14 +0000] [1] [ERROR] Worker (pid:538) was sent SIGKILL! Perhaps out of memory?
[2024-02-28 17:08:14 +0000] [546] [INFO] Booting worker with pid: 546

Can you help me, I don’t know what to check… (maybe at docker level, but I don’t know how)

NB : I have a PostgresSQL database on the Host machine, and the access from within the container works fine (I can create the tables from inside the container with a flask db upgrade)

I tried to compare curl requests from MY ubuntu machine (correct response with a JSON indicating an invalid password)

curl -b "auth.strategy=local; auth.redirect=%2F; auth._token.local=false; auth._refresh_token.local=false" -d '{"email":"[email protected]","password":"12312312"}' -H "Content-Type: application/json" -X POST http://127.0.0.1:5000/icbf/api/v2/auth/login --verbose
*   Trying 127.0.0.1:5000...
* Connected to 127.0.0.1 (127.0.0.1) port 5000 (#0)
> POST /icbf/api/v2/auth/login HTTP/1.1
> Host: 127.0.0.1:5000
> User-Agent: curl/7.81.0
> Accept: */*
> Cookie: auth.strategy=local; auth.redirect=%2F; auth._token.local=false; auth._refresh_token.local=false
> Content-Type: application/json
> Content-Length: 47
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 401 UNAUTHORIZED
< Server: gunicorn
< Date: Wed, 28 Feb 2024 17:07:28 GMT
< Connection: close
< Content-Type: application/json
< Content-Length: 47
< Access-Control-Allow-Origin: *
< 
{"message": "Email ou mot de passe invalide."}
* Closing connection 0

and the one on the virtual server (VPS with debian 10), which is hanging for 20s before the error

curl -b "auth.strategy=local; auth.redirect=%2F; auth._token.local=false; auth._refresh_token.local=false" -d '{"email":"[email protected]","password":"12312312"}' -H "Content-Type: application/json" -X POST http://127.0.0.1:5000/icbf/api/v2/auth/login --verbose
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 5000 (#0)
> POST /icbf/api/v2/auth/login HTTP/1.1
> Host: 127.0.0.1:5000
> User-Agent: curl/7.64.0
> Accept: */*
> Cookie: auth.strategy=local; auth.redirect=%2F; auth._token.local=false; auth._refresh_token.local=false
> Content-Type: application/json
> Content-Length: 47
> 
* upload completely sent off: 47 out of 47 bytes
* Empty reply from server
* Connection #0 to host 127.0.0.1 left intact
curl: (52) Empty reply from server

I tried to check server memory with the free command from inside the VPS container, but it looks OK:

               total        used        free      shared  buff/cache   available
Mem:         1996412      441240      522812       34912     1032360     1357380
Swap:              0           0           0

I really don’t know where to look for…

EDIT : Strangely, gunicorn access log is empty…
Here is gunicorn complete configuration

gunicorn --print-config run:app
access_log_format                 = %(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"
accesslog                         = gunicorn_access_log
backlog                           = 2048
bind                              = ['0.0.0.0:5000']
ca_certs                          = None
capture_output                    = False
cert_reqs                         = 0
certfile                          = None
chdir                             = /api
check_config                      = False
child_exit                        = <ChildExit.child_exit()>
ciphers                           = None
config                            = ./gunicorn.conf.py
daemon                            = False
default_proc_name                 = run:app
disable_redirect_access_to_syslog = False
do_handshake_on_connect           = False
dogstatsd_tags                    = 
enable_stdio_inheritance          = False
errorlog                          = gunicorn_err_log
forwarded_allow_ips               = ['*']
graceful_timeout                  = 30
group                             = 0
initgroups                        = False
keepalive                         = 2
keyfile                           = None
limit_request_field_size          = 8190
limit_request_fields              = 100
limit_request_line                = 4094
logconfig                         = None
logconfig_dict                    = {}
logconfig_json                    = None
logger_class                      = gunicorn.glogging.Logger
loglevel                          = debug
max_requests                      = 0
max_requests_jitter               = 0
nworkers_changed                  = <NumWorkersChanged.nworkers_changed()>
on_exit                           = <OnExit.on_exit()>
on_reload                         = <OnReload.on_reload()>
on_starting                       = <OnStarting.on_starting()>
paste                             = None
pidfile                           = None
post_fork                         = <Postfork.post_fork()>
post_request                      = <PostRequest.post_request()>
post_worker_init                  = <PostWorkerInit.post_worker_init()>
pre_exec                          = <PreExec.pre_exec()>
pre_fork                          = <Prefork.pre_fork()>
pre_request                       = <PreRequest.pre_request()>
preload_app                       = False
print_config                      = True
proc_name                         = None
proxy_allow_ips                   = ['*']
proxy_protocol                    = False
pythonpath                        = None
raw_env                           = []
raw_paste_global_conf             = []
reload                            = False
reload_engine                     = auto
reload_extra_files                = []
reuse_port                        = False
secure_scheme_headers             = {'X-FORWARDED-PROTOCOL': 'ssl', 'X-FORWARDED-PROTO': 'https', 'X-FORWARDED-SSL': 'on'}
sendfile                          = None
spew                              = False
ssl_context                       = <NewSSLContext.ssl_context()>
ssl_version                       = 2
statsd_host                       = None
statsd_prefix                     = 
strip_header_spaces               = False
suppress_ragged_eofs              = True
syslog                            = False
syslog_addr                       = udp://localhost:514
syslog_facility                   = user
syslog_prefix                     = None
threads                           = 1
timeout                           = 30
tmp_upload_dir                    = None
umask                             = 0
user                              = 0
when_ready                        = <WhenReady.when_ready()>
worker_abort                      = <WorkerAbort.worker_abort()>
worker_class                      = sync
worker_connections                = 1000
worker_exit                       = <WorkerExit.worker_exit()>
worker_int                        = <WorkerInt.worker_int()>
worker_tmp_dir                    = /dev/shm
workers                           = 1
wsgi_app                          = None

2

Answers


  1. Chosen as BEST ANSWER

    I found the problem. 10 hours of tests just to realize the firewall is blocking part of the traffic to the db. with a sudo ufw allow from 172.16.0.0/12 to any port 5432 all containers have access to postgres and it 's all fine. Is there security issue with allowing all private ip range ??


  2. I have come across a similar situation. In my case, the problem was that at the time the workers started, they consumed more CPU power than was allowed for the virtual machine.
    There were possible 2 ways to solve the problem:

    1. Reducing the number of threads per worker, the number of requests per worker, or the number of workers themselves. (probably fewer workers will do just fine)

      gunicorn -w <lesser_workers> –threads <lesser_threads>

    2. Increasing the number of CPU cores for VM.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search