Gunicorn: ์ž‘์—…์ž ๋ถ€ํŒ… ์‹คํŒจ

์— ๋งŒ๋“  2012๋…„ 04์›” 25์ผ  ยท  36์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: benoitc/gunicorn

virtualenv์—์„œ ์‹คํ–‰๋˜๋Š” ํ•ฉ๋ฆฌ์ ์œผ๋กœ ๊ฐ„๋‹จํ•œ Django ์‚ฌ์ดํŠธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ./manage.py runserver๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ์ž˜ ์‹คํ–‰๋˜์ง€๋งŒ gunicorn์œผ๋กœ ์‹คํ–‰ํ•˜๋ ค๊ณ  ํ•˜๋ฉด ์ถ”๊ฐ€ ์„ค๋ช… ์—†์ด ์ž‘์—…์ž ๋ถ€ํŒ… ์‹คํŒจ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

tijs<strong i="6">@python</strong>:~/projects/hoogtij.net$ sudo ./runscript.sh 
2012-04-25 14:02:08 [12681] [INFO] Starting gunicorn 0.14.1
2012-04-25 14:02:08 [12681] [INFO] Listening at: http://127.0.0.1:8001 (12681)
2012-04-25 14:02:08 [12681] [INFO] Using worker: sync
2012-04-25 14:02:08 [12696] [INFO] Booting worker with pid: 12696
2012-04-25 14:02:08 [12697] [INFO] Booting worker with pid: 12697
2012-04-25 14:02:08 [12698] [INFO] Booting worker with pid: 12698
Traceback (most recent call last):
  File "/home/tijs/.virtualenvs/hoogtij/bin/gunicorn_django", line 8, in <module>
    load_entry_point('gunicorn==0.14.1', 'console_scripts', 'gunicorn_django')()
  File "/home/tijs/.virtualenvs/hoogtij/local/lib/python2.7/site-packages/gunicorn/app/djangoapp.py", line 129, in run
    DjangoApplication("%prog [OPTIONS] [SETTINGS_PATH]").run()
  File "/home/tijs/.virtualenvs/hoogtij/local/lib/python2.7/site-packages/gunicorn/app/base.py", line 129, in run
    Arbiter(self).run()
  File "/home/tijs/.virtualenvs/hoogtij/local/lib/python2.7/site-packages/gunicorn/arbiter.py", line 184, in run
    self.halt(reason=inst.reason, exit_status=inst.exit_status)
  File "/home/tijs/.virtualenvs/hoogtij/local/lib/python2.7/site-packages/gunicorn/arbiter.py", line 279, in halt
    self.stop()
  File "/home/tijs/.virtualenvs/hoogtij/local/lib/python2.7/site-packages/gunicorn/arbiter.py", line 327, in stop
    self.reap_workers()
  File "/home/tijs/.virtualenvs/hoogtij/local/lib/python2.7/site-packages/gunicorn/arbiter.py", line 413, in reap_workers
    raise HaltServer(reason, self.WORKER_BOOT_ERROR)
gunicorn.errors.HaltServer: <HaltServer 'Worker failed to boot.' 3>

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๋ฉด ์–ด๋””๋กœ ๊ฐ€์•ผ ํ•ฉ๋‹ˆ๊นŒ?

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

๋™์ผํ•œ ๋ฌธ์ œ์— ์ง๋ฉดํ•œ ์‚ฌ๋žŒ์—๊ฒŒ ๋ฌธ์ œ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ django ์ž์ฒด์— ์žˆ๋Š” ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค.
venv๋ฅผ ํ™œ์„ฑํ™”ํ•˜๊ณ  ./manage.py runserver๋ฅผ ์‹คํ–‰ํ•˜์‹ญ์‹œ์˜ค.

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ผ๋ฐ˜์ ์œผ๋กœ ๋” ์ž์„ธํ•œ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

๋ชจ๋“  36 ๋Œ“๊ธ€

gunicorn์ด virtualenv ๋‚ด๋ถ€์— ์„ค์น˜๋˜์–ด ์žˆ์Šต๋‹ˆ๊นŒ ์•„๋‹ˆ๋ฉด ์™ธ๋ถ€์— ์„ค์น˜๋˜์–ด ์žˆ์Šต๋‹ˆ๊นŒ?

๋‚ด๋ถ€์—. ์ง€๊ธˆ์ฏค์ด๋ฉด ๋Œ€๋ถ€๋ถ„์˜ ์„ค์ •์„ ๋ฒ„๋ฆด ๋•Œ gunicorn์ด ์‹œ์ž‘๋˜๊ธฐ ๋•Œ๋ฌธ์— ์•ฑ ๋ฌธ์ œ๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ํ•ด๋‹น ์ถœ๋ ฅ์„ ๋ณผ ๋•Œ ๋ฌด์—‡์ด โ€‹โ€‹์‹คํŒจํ–ˆ๋Š”์ง€ ์•Œ ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ๋ฟ์ž…๋‹ˆ๋‹ค.

"--debug --log-level debug"๋กœ ์‹œ๋„ํ•˜์‹ญ์‹œ์˜ค. ์ถ”๊ฐ€ ์ •๋ณด๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”.

์ด๊ฒƒ์€ ๋‚ด๊ฐ€ ๋‘๋ ค์›Œํ•˜๋Š” ๋””๋ฒ„๊ทธ ๋กœ๊ทธ ์ˆ˜์ค€์˜ ์ถœ๋ ฅ์ž…๋‹ˆ๋‹ค.

:์‹ค๋งํ•œ:
์•„์ง ๋ฌด์Šจ ์ผ์ด ์ผ์–ด๋‚˜๊ณ  ์žˆ๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. "Booting worker" ๋ฉ”์‹œ์ง€ ๋’ค์— ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ "Exception in worker process"๊ฐ€ ํ‘œ์‹œ๋  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ•ฉ๋‹ˆ๋‹ค. ์ž์ •์ด ์กฐ๊ธˆ ๋„˜์—ˆ์ง€๋งŒ ์ž ์„ ์ž๊ณ  ๋ญ”๊ฐ€ ์ƒ๊ฐํ•ด๋‚ผ ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ณ ๋งˆ์›Œ, ๋‚ด๊ฐ€ ์Šค์Šค๋กœ ์•Œ์•„๋‚ด๋ฉด ์•Œ๋ ค์ค„๊ฒŒ. ๋‚˜๋Š” ์ด์ œ ์˜ค๋ฅ˜๊ฐ€ ๋‹ค์‹œ ๋ฐœ์ƒํ•  ๋•Œ๊นŒ์ง€ settings.py๋ฅผ ํ†ตํ•ด ์ž‘์—…ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ฌ๋“œ ์Šค์ฟจ ๋””๋ฒ„๊น… :)

@benoitc log.exception ์ด ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

๋‚˜๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์ด๊ฒƒ์ด ์˜๋ฏธ๊ฐ€์žˆ๋Š” ๊ฒฝ์šฐ ํŒŒ์ด์ฌ ์ผ๋ฟ์ด๋ฏ€๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์ข‹์•„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ฑฐ๊ธฐ์— ๋” ์ ์ ˆํ•œ ๋””๋ฒ„๊ทธ ์‚ฌ์šด๋“œ. ๊ฑฐ๊ธฐ์— ์ง„์งœ ์ถ”๊ฐ€๋Š” ์—ญ์ถ”์ ์ž…๋‹ˆ๋‹ค :)

์‚ฌ์‹ค ๋‚˜๋„ ๋น„์Šทํ•œ ๋ฌธ์ œ๊ฐ€ ์žˆ๊ณ  ๋กœ๊ทธ ํŒŒ์ผ์— ๋Œ€ํ•œ ์“ฐ๊ธฐ ๊ถŒํ•œ๊ณผ ๊ด€๋ จ์ด ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋กœ๊ทธ ํŒŒ์ผ(stderr ๋ฐ stdout)์„ ๊ณต๊ฐœ์ ์œผ๋กœ ์“ฐ๊ธฐ ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“ค๋ฉด ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋‚ด๊ฐ€ supervisord์—์„œ gunicorn์„ ์ฒ˜์Œ ์‹œ์ž‘ํ•  ๋•Œ gunicorn์ด ์ธ๊ณ„๋ฐ›๊ธฐ ์ „์— ๋ฃจํŠธ ์•„๋ž˜์— ๋กœ๊ทธ ํŒŒ์ผ์ด ์ƒ์„ฑ๋˜๋Š”์ง€์— ๋Œ€ํ•œ ์งˆ๋ฌธ์„ ํ•˜๊ฒŒ ๋˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋กœ๊ทธ ํŒŒ์ผ์ด Supervisord๊ฐ€ ์•„๋‹Œ gunicorn์— ์˜ํ•ด ์ƒ์„ฑ๋˜๋„๋ก ๊ด€๋ฆฌํ•˜๋Š” ๊ฐ€์žฅ ์ข‹์€ ๋ฐฉ๋ฒ•์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

์–ด๋–ป๊ฒŒ gunicorn์„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๊นŒ? ๋งˆ์ง€๋ง‰ ๋จธ๋ฆฌ๋กœ ์žฌํ˜„ํ•ฉ๋‹ˆ๊นŒ?

๋‚˜๋Š” ๊ฐ๋…์ž์™€ ํ•จ๊ป˜ ๊ทธ๊ฒƒ์„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ์€ Supervisord์— ๋Œ€ํ•œ ๋‚ด gunicorn ๊ตฌ์„ฑ์ž…๋‹ˆ๋‹ค.

[ํ”„๋กœ๊ทธ๋žจ:์Šฌ๋ผ์ด์Šค์›น]
๋””๋ ‰ํ† ๋ฆฌ = /opt/src/slicephone/webapp/webapp/
๋ช…๋ น = /opt/src/slicephone/webapp/scripts/gunicorn.sh
stdout_logfile = /opt/logs/supervisord.stdout.log
stderr_logfile = /opt/logs/supervisord.stderr.log

๊ทธ๋ฆฌ๊ณ  ์‹ค์ œ gunicorn ์Šคํฌ๋ฆฝํŠธ(๋‚ด๊ฐ€ gunicorn ์‚ฌ์šฉ์ž/๊ทธ๋ฃน์— ๋กœ๊ทธ ํŒŒ์ผ์„ ํ„ฐ์น˜ํ•˜๊ณ  chownํ•˜๋Š” ๋ฐฉ๋ฒ• ์ฐธ๊ณ ):

!/bin/bash

์„ธํŠธ -e
DATASTORE_SOFTWARE="XXXXX"
ACCESS_LOGFILE=/opt/logs/gunicorn.slice.access.log
ERROR_LOGFILE=/opt/logs/gunicorn.slice.error.log
๋กœ๊ทธ ํŒŒ์ผ=/opt/logs/gunicorn.slice.log
LOGDIR=$(๋””๋ ‰ํ† ๋ฆฌ ์ด๋ฆ„ $LOGFILE)
WEBAPPDIR=$(๋””๋ ‰ํ„ฐ๋ฆฌ ์ด๋ฆ„ $0)/../
NUM_WORKERS=3
DEBUG_FLAGS="--debug --๋กœ๊ทธ ์ˆ˜์ค€ ๋””๋ฒ„๊ทธ"

์‹คํ–‰ํ•  ์‚ฌ์šฉ์ž/๊ทธ๋ฃน

USER=www-data
๊ทธ๋ฃน=www-data
cd $WEBAPPDIR/webapp
ํ…Œ์ŠคํŠธ -d $LOGDIR || mkdir -p $LOGDIR
์—์ฝ” WebAppDir: $WEBAPPDIR
echo "์‚ฌ์šฉ์ž: $USER"
echo "๊ทธ๋ฃน: $GROUP"

$ACCESS_LOGFILE $ERROR_LOGFILE $LOGFILE ํ„ฐ์น˜
chown -R $USER:$GROUP $ACCESS_LOGFILE $ERROR_LOGFILE $LOGFILE

๋‚ด๋ณด๋‚ด๊ธฐ DATASTORE_SOFTWARE=$DATASTORE_SOFTWARE ; exec /opt/virtenvs/django_slice/bin/gunicorn_django $DEBUG_FLAGS -w $NUM_WORKERS --user=$USER --group=$GROUP --log-level=debug --log-file=$LOGFILE --access-logfile= $ACCESS_LOGFILE --error-logfile=$ERROR_LOGFILE

์ตœ์‹  ํ—ค๋“œ์— ๋Œ€ํ•œ ์ข‹์€ ์งˆ๋ฌธ์ž…๋‹ˆ๋‹ค. pip freeze๋Š” 0.14.1๋กœ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค(.2๊ฐ€ ์ตœ์‹  ๋ฒ„์ „์ด ์•„๋‹Œ๊ฐ€์š”?)

๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๊นŒ? ๋‚˜๋Š” ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ์žˆ์œผ๋ฉฐ ํ˜„์žฌ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ชจ๋ฆ…๋‹ˆ๋‹ค.

๋„ค ํ•ด๊ฒฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์–ด๋–ค ๋ฒ„์ „์˜ gunicorn์„ ์‹คํ–‰ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ? ์žฌํ˜„ํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌ์„ฑ์— ๋Œ€ํ•œ ์ถ”๊ฐ€ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ๊ฐ์‚ฌ ํ•ด์š”.

@panyam 0.14.3์œผ๋กœ ์‹œ๋„ ํ–ˆ์Šต๋‹ˆ๊นŒ?

@benoitc ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค ์นœ๊ตฌ

๋ช…ํ™•ํžˆํ•˜๊ธฐ ์œ„ํ•ด ๋‚˜๋Š” ์ด๊ฒƒ์ด gunicorn ๋ฌธ์ œ๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. @anyeguyue - ์ด๊ฒƒ์„ ํ™•์ธํ•˜๋Š” ๊ฐ€์žฅ ์ข‹์€ ๊ณณ์€ ๊ฐ๋…์ž ๋กœ๊ทธ ๋˜๋Š” gunicorn ๋กœ๊ทธ(์ผ๋ฐ˜์ ์œผ๋กœ /var/log/gunicorn/....์— ์žˆ์Œ)๋ฅผ ์‚ดํŽด๋ณด๊ณ  ๊ฑฐ๊ธฐ์— "๊ถŒํ•œ ๊ฑฐ๋ถ€๋จ" ์˜ค๋ฅ˜๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ฐฉ๊ธˆ ๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์—ฌ ์ฒซ ๋ฒˆ์งธ 'python manage.py syncdb'๋กœ ํ•ด๊ฒฐ๋˜์–ด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ํ•ด๋‹น ์„ค์ • ๋ฌธ์ œ๋ฅผ ์ˆ˜์ •ํ•œ ํ›„ gunicorn์ด ์ž‘๋™ํ–ˆ์Šต๋‹ˆ๋‹ค(nginx๋ฅผ ๋‹ค์‹œ ์‹œ์ž‘ํ•œ ํ›„).

์ด ๋ฌธ์ œ๋„ ํ•ด๊ฒฐํ–ˆ์ง€๋งŒ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์œผ๋กœ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค. gunicorn_django ํŒŒ์ผ์˜ ์ฒซ ๋ฒˆ์งธ ์ค„์€ ๋‚ด ๊ฐ€์ƒ ํ™˜๊ฒฝ ํŒŒ์ด์ฌ ๊ฒฝ๋กœ์˜ ๊ฒฝ๋กœ์ธ "#!/opt/django/env/mysite/bin/python"์ด์—ˆ์Šต๋‹ˆ๋‹ค. "#!/usr/bin/env python"์œผ๋กœ ๊ต์ฒดํ•˜์—ฌ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์—ˆ์ง€๋งŒ ๋‘˜ ๋‹ค ๋™์ผํ•œ ํŒŒ์ด์ฌ ์ธํ„ฐํ”„๋ฆฌํ„ฐ๋ฅผ ์‚ฌ์šฉํ–ˆ์ง€๋งŒ PYTHONPATH ์ฐจ์ด๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด์ „์— ์‹คํŒจํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@anyeguyue ๋‚˜๋Š” gunicorn 0.14.5 ๋ฐ Django 1.4์—์„œ ๋™์ผํ•œ ๋ฌธ์ œ์— ์ง๋ฉดํ–ˆ์ง€๋งŒ ๋” ๋‚˜์œ ์ฆ์ƒ์ด ์žˆ์Šต๋‹ˆ๋‹ค. gunicorn_django -b 0.0.0.0:8000 ์‹คํ–‰์ด ๊ฑฐ๋ถ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ˆ˜์ • ์‚ฌํ•ญ์€ ์ž‘๋™ํ•˜๊ณ  ๋งค์šฐ ๋ถ„๋ช…ํ•ฉ๋‹ˆ๋‹ค. ํ•ญ์ƒ /usr/bin/env which python ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค! ๊ฐ์‚ฌ ํ•ด์š”.

@asimihsan, ๋„์›€์ด ๋˜์–ด์„œ ๊ธฐ์ฉ๋‹ˆ๋‹ค

๋‚˜๋Š” ๋˜ํ•œ์ด ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ๋‹ค. ๋‚ด ์ฝ”๋“œ์—์„œ ์ž˜๋ชป๋œ ๊ฐ€์ ธ์˜ค๊ธฐ์— ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ๊ฒƒ์œผ๋กœ ๋‚˜ํƒ€๋‚ฌ์Šต๋‹ˆ๋‹ค. ๋””๋ฒ„๊ทธํ•˜๋ ค๋ฉด gunicorn_django --preload๋ฅผ ์‹คํ–‰ํ•ด ๋ณด์‹ญ์‹œ์˜ค. ๊ทธ๋Ÿฌ๋ฉด ์˜ฌ๋ฐ”๋ฅธ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

๋™์ผํ•œ ๋ฌธ์ œ์— ์ง๋ฉดํ•œ ์‚ฌ๋žŒ์—๊ฒŒ ๋ฌธ์ œ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ django ์ž์ฒด์— ์žˆ๋Š” ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค.
venv๋ฅผ ํ™œ์„ฑํ™”ํ•˜๊ณ  ./manage.py runserver๋ฅผ ์‹คํ–‰ํ•˜์‹ญ์‹œ์˜ค.

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ผ๋ฐ˜์ ์œผ๋กœ ๋” ์ž์„ธํ•œ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

:+1: @fergalmoran ๋‚ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋˜์—ˆ์Šต๋‹ˆ๋‹ค(PIL์˜ ๋ฌธ์ œ์˜€์Šต๋‹ˆ๋‹ค).

๊ฐ™์€ ๋ฌธ์ œ์— ์ง๋ฉดํ•ด ์žˆ๋Š”๋ฐ... ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

@pythdasch ์—ฌ๊ธฐ์—์„œ ์ด์•ผ๊ธฐํ•œ ๋ช‡ ๊ฐ€์ง€ ๋‹ค๋ฅธ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ถ”๊ฐ€ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ ์ƒˆ ํ‹ฐ์ผ“์„ ์—ด๊ฑฐ๋‚˜ ๋ฉ”์ผ๋ง ๋ฆฌ์ŠคํŠธ์— ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋‚ด๋ฉด ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์ด ๋””๋ฒ„๊น…์„ ๋„์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

#gunicorn ์—์„œ @pythdasch์˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐ @pythdasch , ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

Berker ๋•๋ถ„์— ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค :)

๋‚ด wsgi๋Š” ๋‚ด manage.py์™€ ๊ฐ™์€ ํด๋”์— ์žˆ์œผ๋ฏ€๋กœ ํ”„๋กœ์ ํŠธ๊ฐ€ ์•„๋‹Œ wsgi:application ๊ฒฝ๋กœ๋ฅผ ๋„ฃ์–ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค. wsgi:์‘์šฉ ํ”„๋กœ๊ทธ๋žจ

(wsgi์— ๋Œ€ํ•œ ์ž˜๋ชป๋œ ๊ฒฝ๋กœ์˜€์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ project.wsgi:application ๋Œ€์‹  wsgi:application์ด์–ด์•ผ ํ•จ)

@tilgovi ๋„ค ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค irc ์ฑ„๋„ gunicorn์— ๊ฐ€์„œ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค :)

์–ด์ œ gunicorn 0.18 ๋ฐ ๋‹ค์Œ ํ˜ธ์ถœ์—์„œ ๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.

gunicorn 'app:create_app()' --name X --workers 5 --user=apprunner --group=apprunner --bind='0.0.0.0:5000' --log-config=resource/config/di/logging.conf --timeout=360 --debug --log-level debug

๋‚ด Flask ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์˜ ImportError ๋•Œ๋ฌธ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ์ ์€ ์ž‘์—…์ž๊ฐ€ ๋ถ€ํŒ… ์‹œ ์ถฉ๋Œํ•˜๋Š” ๊ฒฝ์šฐ gunicorn์ด ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์˜ ์—ญ์ถ”์ ์„ ํ‘œ์‹œํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์ œ ๋ฌธ์ œ๋ฅผ ํ™•์ธํ•˜๋ ค๋ฉด Flask ์•ฑ์„ โ€‹โ€‹์ˆ˜๋™์œผ๋กœ ์‹œ์ž‘ํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์‹ค์ œ ์—ญ์ถ”์ ์„ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๋งค์šฐ ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. IMO ๋‹ค์Œ์œผ๋กœ ์ข‹์€ ๋ฐฉ๋ฒ•์€ ์›๋ณธ ํŠธ๋ ˆ์ด์Šค๋ฐฑ์„ ํ‘œ์‹œํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ ์‹ค์ œ ์˜ค๋ฅ˜๋ฅผ ์ฐพ๊ธฐ ์œ„ํ•ด gunicorn์„ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€์‹  ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์„ ์ง์ ‘ ์‹คํ–‰ํ•˜๋ผ๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ํฌํ•จํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ฌธ์ œ๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ดํ•ดํ–ˆ๋‹ค๋ฉด Gunicorn์€ ์ด๋ฏธ ImportError์™€ ๊ฐ™์€ ์˜ˆ์™ธ ๋ฉ”์‹œ์ง€๋ฅผ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.

$ gunicorn a:app --error-logfile=- --access-logfile=-
[2014-12-10 17:13:31 +0000] [12176] [INFO] Starting gunicorn 19.2.0
[2014-12-10 17:13:31 +0000] [12176] [INFO] Listening at: http://127.0.0.1:8000 (12176)
[2014-12-10 17:13:31 +0000] [12176] [INFO] Using worker: sync
[2014-12-10 17:13:31 +0000] [12181] [INFO] Booting worker with pid: 12181
[2014-12-10 17:13:31 +0000] [12181] [ERROR] Exception in worker process:
Traceback (most recent call last):
  File "/home/berker/projects/gunicorn/gunicorn/arbiter.py", line 517, in spawn_worker
    worker.init_process()
  File "/home/berker/projects/gunicorn/gunicorn/workers/base.py", line 117, in init_process
    self.wsgi = self.app.wsgi()
  File "/home/berker/projects/gunicorn/gunicorn/app/base.py", line 67, in wsgi
    self.callable = self.load()
  File "/home/berker/projects/gunicorn/gunicorn/app/wsgiapp.py", line 65, in load
    return self.load_wsgiapp()
  File "/home/berker/projects/gunicorn/gunicorn/app/wsgiapp.py", line 52, in load_wsgiapp
    return util.import_app(self.app_uri)
  File "/home/berker/projects/gunicorn/gunicorn/util.py", line 355, in import_app
    __import__(module)
  File "/home/berker/projects/testdjango/a.py", line 1, in <module>
    from flask import Flask
ImportError: No module named flask

๋ฐ ๊ธฐํƒ€ ์ข…๋ฅ˜์˜ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€:

$ gunicorn a:app --error-logfile=- --access-logfile=-
[2014-12-10 17:18:52 +0000] [12294] [INFO] Starting gunicorn 19.2.0
[2014-12-10 17:18:52 +0000] [12294] [ERROR] Connection in use: ('127.0.0.1', 8000)
[2014-12-10 17:18:52 +0000] [12294] [ERROR] Retrying in 1 second.
[2014-12-10 17:18:53 +0000] [12294] [ERROR] Connection in use: ('127.0.0.1', 8000)
[2014-12-10 17:18:53 +0000] [12294] [ERROR] Retrying in 1 second.
[2014-12-10 17:18:54 +0000] [12294] [ERROR] Connection in use: ('127.0.0.1', 8000)
[2014-12-10 17:18:54 +0000] [12294] [ERROR] Retrying in 1 second.

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์•ฑ์„ ์‹คํ–‰ํ•˜๋ ค๊ณ  ํ•  ๋•Œ๋„ ๋™์ผํ•œ ๋ฌธ์ œ์— ์ง๋ฉดํ–ˆ์Šต๋‹ˆ๋‹ค.

gunicorn app:application -b localhost:3000

๋ฌธ์ œ๋Š” app.py ํŒŒ์ผ ์™ธ์—๋„ app ๋ผ๋Š” ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ํŒŒ์ด์ฌ ํŒŒ์ผ์˜ ์ด๋ฆ„์„ ๋ฐ”๊พผ ํ›„์— ์ž‘๋™ํ–ˆ์Šต๋‹ˆ๋‹ค.

@brouberol ์ง€๊ธˆ๋„ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. Flask ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์— ๊ฐ€์ ธ์˜ค๊ธฐ ์˜ค๋ฅ˜๋ฅผ ์ผ์œผํ‚ค๋Š” ์ผ๋ถ€ ๋ชจ๋“ˆ์ด ์žˆ๋Š” ๊ฒฝ์šฐ Gunicorn์€ ์—ญ์ถ”์ ์„ ๊ธฐ๋กํ•˜์ง€ ์•Š์ง€๋งŒ Flask์˜ ๋‚ด์žฅ ์„œ๋ฒ„๋Š” ๊ธฐ๋กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๊ฐ€ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ Gunicorn์ด ์˜ค๋ฅ˜ ๋กœ๊ทธ์— ๋” ์ž์„ธํ•œ ์ •๋ณด ์—†์ด ์ž‘์—…์ž๋ฅผ ๋ถ€ํŒ…ํ•˜์ง€ ๋ชปํ•œ ๊ฒฝ์šฐ ๋จผ์ € Flask์˜ ๋‚ด์žฅ ์„œ๋ฒ„๋ฅผ ์‹œ๋„ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

--preload๋กœ guncorn์„ ์‹คํ–‰ํ•˜๋ฉด ์˜ค๋ฅ˜ ๋กœ๊ทธ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ €์—๊ฒŒ๋Š” Django runserver ์ž˜ ์ž‘๋™ํ–ˆ์Šต๋‹ˆ๋‹ค. gunicorn.conf.py ํŒŒ์ผ์—์„œ Django settings ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์ด ๋ฌธ์ œ์˜€์Šต๋‹ˆ๋‹ค. ํ•ด๋‹น ๊ฐ€์ ธ์˜ค๊ธฐ๋ฅผ ์ œ๊ฑฐํ•˜๋ฉด ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰