在“ git pull”我的 Django 项目之后重新启动/重新加载 Gunicorn (通过 Upstart)的更好方法

进出口寻找一些比 sudo restart projectname更好的每次我发布一个 git pull origin master,这拉下我最新的变化,一个 Django 项目。我相信,这个 restart命令与 Upstart 有关,我用它来启动/顶部我的 Gunicorn 服务器进程。

此重新启动导致短暂停机。登录网络服务器(nginx)的用户将获得500分,因为 Gunicorn 仍在重启。事实上,它似乎可以立即重新启动,但加载页面需要几秒钟。

有什么想法如何使这个无缝? 理想情况下,我想发布我的 git pull和独角兽自动重新加载。

96180 次浏览

你可以像这样通过 HUP信号告诉 Gunicorn 优雅地重新装弹:

kill -HUP <pid>

(详情见 常见问题)

我使用 主管来控制我的 Gunicorn 服务器,它允许我在部署之后使用这种(有点古怪的)重新加载 Gunicorn 的方式:

supervisorctl status gunicorn | sed "s/.*[pid ]\([0-9]\+\)\,.*/\1/" | xargs kill -HUP

很明显,你可以用 pidof或者 ps来达到类似的效果。

这实际上是从 布料脚本运行的,所以我根本不需要登录到服务器。

为了更好地重新加载,你应该使用 Upstart 的 reload命令,例如:

sudo reload jobname

根据 initctl (Upstart) 手册reload将向进程发送一个 HUP信号:

reload JOB [KEY=VALUE]...


Sends the SIGHUP signal to running process of the named JOB instance.

... 对于 Gunicorn 将触发一个优雅的重新启动(见 常见问题)。

对于那些不使用上级记录的人: 罗伯说,它也适用于 ps,

ps aux |grep gunicorn |grep projectname | awk '{ print $2 }' |xargs kill -HUP

我们在主管的领导下运行独角兽,但这是我们发现的最简单、最干净的方法,在独角兽迷惑时优雅地重新装弹:

sudo pkill -HUP -f gunicorn.*master

Systemd,gunicorn & Ubuntu

如果您正在使用 系统运行您的 Gunicorn 服务,这里是一行程序。

systemctl status gunicorn |  sed -n 's/.*Main PID: \(.*\)$/\1/g p' | cut -f1 -d' ' | xargs kill -HUP

细节一步一步来

由于 枪角兽医生告诉我们正确的方法是使用 kill -HUP <Main PID>(其中 <Main PID>是主进程的进程 id)优雅地重新加载工作线程,因此我们使用 systemctl 提取主 PID,然后运行 kill -HUP <Main PID>

1)使用服务的名称从 systemd 获取有关进程的信息

systemctl status gunicorn

其中 gunicorn是位于 /etc/systemd/system/的服务名称。

输出示例:

ubuntu@ip-10-4-12-247:~$ systemctl status gunicorn
● gunicorn.service - Gunicorn server for yourproject.com
Loaded: loaded (/etc/systemd/system/gunicorn.service; enabled; vendor preset: enabled)
Active: active (running) since Sat 2017-11-04 19:16:24 UTC; 1h 15min ago
Main PID: 10673 (gunicorn)
CGroup: /system.slice/gunicorn.service
├─10673 /home/ubuntu/site/venv/bin/python3 /home/ubuntu/site/venv/bin/gunicorn --workers 3 --bind unix:/tmp/yourproject.socket config.wsgi:application
├─11069 /home/ubuntu/site/venv/bin/python3 /home/ubuntu/site/venv/bin/gunicorn --workers 3 --bind unix:/tmp/yourproject.socket config.wsgi:application
├─11070 /home/ubuntu/site/venv/bin/python3 /home/ubuntu/site/venv/bin/gunicorn --workers 3 --bind unix:/tmp/yourproject.socket config.wsgi:application
└─11071 /home/ubuntu/site/venv/bin/python3 /home/ubuntu/site/venv/bin/gunicorn --workers 3 --bind unix:/tmp/yourproject.socket config.wsgi:application


Nov 04 20:27:04 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:27:04 +0000] [11047] [INFO] Booting worker with pid: 11047
Nov 04 20:27:04 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:27:04 +0000] [11048] [INFO] Booting worker with pid: 11048
Nov 04 20:32:16 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:32:16 +0000] [10673] [INFO] Handling signal: hup
Nov 04 20:32:16 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:32:16 +0000] [10673] [INFO] Hang up: Master
Nov 04 20:32:16 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:32:16 +0000] [11046] [INFO] Worker exiting (pid: 11046)
Nov 04 20:32:16 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:32:16 +0000] [11047] [INFO] Worker exiting (pid: 11047)
Nov 04 20:32:16 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:32:16 +0000] [11048] [INFO] Worker exiting (pid: 11048)
Nov 04 20:32:16 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:32:16 +0000] [11069] [INFO] Booting worker with pid: 11069
Nov 04 20:32:16 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:32:16 +0000] [11070] [INFO] Booting worker with pid: 11070
Nov 04 20:32:16 ip-10-4-12-247 gunicorn[10673]: [2017-11-04 20:32:16 +0000] [11071] [INFO] Booting worker with pid: 11071

2)获取主进程的进程 ID (PID)

翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳命令的工作原理如下: sed 's/<search this>/<replace with this>/g'

  • s表示 代课老师命令,g表示搜索整个输入 全球范围内
  • -n标志告诉 sed 没有打印每一行(或者实际上不打印任何内容)
  • 最后的 p告诉 sed 为 打印匹配的行
  • 我们搜索 .*Main PID: \(.*\)$,这是一个正则表达式模式,它包含以下部分: .*匹配任何字符(.)零次或更多次(*)。然后我们搜索 Main PID:后跟任何字符,重复0次或更多次(.*)。为了捕获 Main PID:-text 之后的所有字符,我们将 .*放入括号中,用反斜杠转义: \(.*\)$指示线端。
  • Sed 命令的“ place with this”部分就是 \1,这意味着第一个捕获的字符集。

输出示例:

ubuntu@ip-10-4-12-247:~$ systemctl status gunicorn |  sed -n 's/.*Main PID: \(.*\)$/\1/g p'
10673 (gunicorn)

3)去掉多余的字符

管道输出到 cut -f1 -d' '意味着,

  • 字符串是空格分隔的: 这里 -d确定分隔符,它是紧跟在 -d之后的字符。因为分隔符是空格,所以我们用引号括起来。
  • -f意味着只使用分隔符(而不是字节)进行剪切,而 -f1意味着我们要删除列表的第一个元素。

输出示例:

ubuntu@ip-10-4-12-247:~$ systemctl status gunicorn |  sed -n 's/.*Main PID: \(.*\)$/\1/g p' | cut -f1 -d' '
10673

4)使用主 PID

管道到 Xargs意味着只运行带有左侧管道参数的命令。既然我们只是把主 PID 传给了 xargs,

 systemctl status gunicorn-django |  sed -n 's/.*Main PID: \(.*\)$/\1/g p' | cut -f1 -d' ' | xargs kill -HUP

基本上和

echo <Main PID > | xargs kill -HUP

翻译过来就是

kill -HUP <Main PID >

剪辑

一个更加健壮的解决方案是在 cut -f1 -d' '前面使用 cut -f1 -d$'\n'grep -m1 "",只挑选比赛的第一行。但我想不出任何情况下 Main PID:会有两个匹配。

也许这不是问题的直接答案,但是对于那些正在寻找重新启动 gunicorn Web 服务器的人来说,您可以使用 killall gunicorn,然后执行命令重新启动 gunicorn。例如:

killall gunicorn
gunicorn --bind 0.0.0.0:80 --reload app:app

注意: killall gunicorn将立即终止所有 Gunicorn 进程,所以请确保您明白自己在做什么。

使用 cmd 重新启动 Gunicorn 服务
systemctl restart gunicorn

否则重新启动 Gunicorn 服务并重新创建袜子文件。

sudo systemctl restart gunicorn

如果运行的是 端口 gunicorn而不是套接字,则可以 使用 fuser 命令查找 gunicorn 的进程 id (pid)。

命令 fuser 8000/tcp将使用 tcp 端口8000列出所有进程的进程 ID。

fuser -k 8000/tcp会不恰当地终止那些不推荐的进程。

  • fuser -k -HUP 8000/tcp将迫使 Gunicorn 使用 tcp 端口8000到 通过发送 HUP 信号重载代码。

使用 systemd 时

电话:

systemctl restart gunicorn

导致了502个坏的网关错误。深入研究 nginx 日志,我们发现套接字文件没有找到。呼叫

systemctl restart gunicorn.socket

在重新启动枪角兽后,重新启动插座并使服务器重新上线。

当 gunicorn 重新启动(在 dev/test env 中)需要很长时间才能重新启动时,这会有所帮助。

下面的命令杀死工人。

$ sudo kill -9 `sudo lsof -n -i | grep gunicorn | awk '{print $2}'`


$ sudo service gunicorn restart