從零開始自動部署Django項目(二):使用Python編寫Git Hooks

引言

在上一篇從零開始自動部署Django項目(一):開發配置與生產配置,已經給出了通過環境變量來實現不同配置選擇的解決方案。既然是環境變量,那就可以通過shell腳本或者python腳本來實現。
接下來,我將通過使用python編寫的Git Hooks來實現在向生產服務Git推送的時候完成自動部署。
不太瞭解Git Hooks的同學可以參考我這篇文章: 服務端自動部署靜態項目的幾種方法

準備

首先明確Git Hooks要完成哪些任務:

  • 判斷python debug server在centos系統服務器上是否運行在指定端口,如果在運行則殺掉該進程。
  • git pull 前端的release分支。
  • git pull 後端的release分支並通過nohup重啓python debug server。

明確要完成的任務之後,還有幾點利用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)
發佈了51 篇原創文章 · 獲贊 22 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章