自动部署Django项目详解(2)

在上一篇自动部署Django项目详解(一):开发配置与生产配置,已经给出了通过环境变量来实现不同配置选择的解决方案。既然是环境变量,那就可以通过shell脚本或者Python脚本来实现。
接下来,我将通过使用python编写的Git Hooks来实现在向生产服务Git推送的时候完成自动部署。

准备

首先明确Git Hooks要完成哪些任务:

明确要完成的任务之后,还有几点利用Python编写Git Hooks要注意的地方:

杀掉Python debug server进程

如果server 进程运行在9999端口,使用linux提供的命令如何杀掉进程呢?
首先通过lsof命令观察9999端口是否有进程运行,如果有则获取该进程的pid,得到以后通过kill命令杀掉该进程。因此,我们要在Python中完成对lsof命令输出的截取。
其中,subprocess.call()调用会返回命令执行的状态,1表示错误,0表示正常执行。

import subprocess import os import signal # kill the python debug server server_status = subprocess.call(lsof_command, shell=True) if server_status == 0: server_res_bytes = subprocess.check_output("lost -i:9999 | tail -n 1", shell=True) server_res = server_res_bytes.split() python_server_pid = int(server_res[1]) try: os.kill(python_server_pid, signal.SIGKILL) except OSError: pass 更新前端和后端分支

在确认Python debug server已经被杀掉的基础上,可以进行对分支的pull和checkout了。

# checkout the FrontEnd branch os.chdir(frontend_path) subprocess.call("git fetch --all", shell=True) subprocess.call("git reset --hard origin/" + fronend_branch, shell=True) # checkout the BackEnd branch os.chdir(backend_path) subprocess.call("git fetch --all", shell=True) subprocess.call("git reset --hard origin/" + backend_branch, shell=True)

OK,但是在这里我遇到了一个神秘的错误:

remote: fatal: Not a git repository: '.'

这是为什么呢?原来Git Hooks在执行的时候会设置$GIT_DIR变量为.而并非.git,这会导致Git会去寻找./HEAD,而并非.git/HEAD,因此在hooks脚本一开始需要执行unset GIT_DIR或者把GIT_DIR设置成.git。
在一开始的时候,我直接调用了subprocess.call(‘unset GIT_DIR’, shell=True),然而并不起作用,这是因为subprocess只是在子进程中unset了变量,而并非当前的Python进程,因此我要通过os.environ影响当前Python进程衍生的子进程。

# didn't work subprocess.call('unset GIT_DIR', shell=True) # work fine os.unsetenv('GIT_DIR')

stackoveflow传送门:Git checkout in post-receive hook: “Not a git repository ‘.’”
以及Git如果在Git仓库中Git_DIR就会被设置成.git,而非git仓库的时候就是.,而Git命令在执行的时候会默认去寻找.git目录。传送门:Receiving “fatal: Not a git repository” when attempting to remote add a Git repo

重启Python debug server

最后只需要通过manage.py 重启debug server就可以了,但在这之前需要设置上一篇中提及在生产环境的环境变量。

# restart the python debug server os.putenv('DJANGO_PRODUCTION_SETTINGS', 'TRUE') try: subprocess.call("nohup python manage.py runserver 9999 &", shell=True) except Exception: pass

OK,通过nohup启动之后我尴尬地发现在提交的时候远程卡住了除非我发出了终止指令。。。
这是因为通过ssh启动的nohup必须要重定向stdin,stdout,stderr。
stackoveflow传送门:Use SSH to start a background process on a remote server, and exit session
简单说一下linux的重定向,0是标准输入,1是标准输出,2是错误输出,如今我想把1和2都输入到一个文件中,不能直接使用1> file 2> file,因为这会引起文件的接受混乱,必须用特殊的语法,比如2>&1。

# work fine subprocess.call("nohup python manage.py runserver 9999 > /nohup.out 2>&1 &", shell=True)

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/0c92a39958122c372d5deaf8b6be9c2a.html