This article presents my approach with the example of deploying a Openresty-based server-side program.
Technical information
Os:centos 6.3
Server Software: Openresty
Development language: Lua
noun explanation
Servers: server hardware + OS
Server-side programs: Openresty Processes in servers
Server-side code: The Lua source program deployed in Openresty
One, git service end hook type
Pre-receive
Executes first when the client pushes, and can be used to reject the push of the client.
Update
Similar to pre-receive, but will be performed once per branch.
Post-receive
Executed after the client push completes.
According to my needs, I choose post-receive hook to do this thing. Because I don't want to reject the push of the client (so programmers may not know what to do). The push always succeeds, but the command is unsuccessful. When the command is unsuccessful, the client only needs to push a correct command again.
The configuration of the command is detailed later.
two, git repostories
I set up 2 git warehouses to complete this task. The advantage of partitioning into 2 warehouses is that the server-side code is updated and the server-side program is not disturbed.
On the development server, I can shut down Openresty's Lua file cache. This will take effect immediately after the service-side code is updated, without restarting the server-side program.
And if the server-side program is wrong, just update its status (Reopen/reload, etc.), and do not need to update the server-side code.
Server.git
This warehouse holds the server-side logic code, and the client's folder structure is as follows:
Server
├──readme.md
└──src
└──main.lua
Each time the code is submitted, a specific command can be included in the submission, and when the commit is pushed, the GIT server hook works and updates the submitted code to the appropriate location.
If there are no specific commands in the submission, then this is an ordinary push.
In this case, the hook does what it does to update all the code in the Src/folder to the server program.
Serverctrl.git
This warehouse is empty and will never have content. By including specific commands in the submission information, the GIT server hook will perform a given operation on our service-side program.
third, use the hook to restart the server program
Process Control of Openresty
Use the-s parameter provided by Nginx to control the server-side program:
nginx-s [Stop|quit|reopen|reload]-p/path/to
Without the-s parameter is the start function:
Nginx-p/path/to
Command
Serverctrl is an empty project and it is impossible to have any content. Therefore, I require the submission of information directly to write operation commands.
To control server-side program restart, you only need to do this commit and push:
git commit--allow-empty-m ' reopen ' && git push Origin Zrong
implementation of [Start|stop|quit|reload] is also the same reason.
Specific code
The following code shows the contents of the post-receive hooks in the Serverctrl project. Hooks can be written in any scripting language that the operating system can recognize. I'm using Python (2.7 and 3.4 generic) here.
The following code and comments are very clear, I say a few points to note.
In the Callnginx method, the stderr parameter of the Subprocess.check_output method needs to be set to STDOUT. Because if you perform nginx error, the error message is written to the STDERR by default, and if you do not make such a modification, the input information returned when the error occurs is empty.
You need to set the Nginx program as well as the '/opt/openresty/nginx ' entire folder and owner of the file below it as a git user, otherwise the hook will not have permission to start the nginx process.
The owner of the Post-receive Hook itself will also be set up as a git user and given execution privileges.
If there is already a nginx process running with the-p parameter (prefix), note that it ends first. Otherwise, the GIT user may not have permission to close the process.
-
#!/usr/bin/env python
Import Sys
Import OS
Import subprocess
# prefix configuration path
Openresty = '/opt/openresty/nginx '
# Execute File path
Nginx = openresty + '/sbin/nginx '
# signals that can be identified
Signals = (' Start ', ' Stop ', ' Quit ', ' reopen ', ' reload ')
# Supported branches (user)
Branches = (' Master ', ' Allen ', ' Zrong ', ' Xiefei ', ' ZM ')
def Getgitargs (*args):
If args:
return [' Git ', '--bare ', '--git-dir ', OS.GETCWD ()] + list (args)
return []
def callgit (*args):
return Subprocess.check_output ([' Env ', '-i '] + Getgitargs (*args),
Universal_newlines=true)
def Callnginx (Action):
args = [Nginx, ' P ', openresty]
If action!= ' start ':
args + = [' s ', action]
Return Subprocess.check_output (args,
Stderr=subprocess. STDOUT, Universal_newlines=true)
# The Hook will write the information from STDIN and read the information into the variable
Oldrev,newrev,refname = Sys.stdin.readline (). Strip (). Split (")
# for our program, only the branch name is useful
Branch = Refname.split ('/') [-1]
Print (' oldref:%s, newrev:%s, refname:%s '% (Oldrev, Newrev, refname))
If not branch in branches:
Print (' The branch '%s ' is not in available list! '
' The list is%s '% (branch, str (branches))
Exit (1)
Try
# get the latest submissions under the branch currently available
commitmsg = callgit (' Log ', branch, '--oneline ', '-1 ') [8:-1]
Print (branch+ ' +commitmsg)
If commitmsg in signals:
Callnginx (COMMITMSG)
Print (' =======%s%s SUCCESS ======= '% (branch, commitmsg))
Else
Print (' The signal '%s ' is not in available list! '
' The list is%s '% (commitmsg, str (signals))
Except Subprocess. Calledprocesserror as ERR:
Print (' =======%s%s '%s ERROR ======= '% (branch, commitmsg, Err.output))
Exit (1)
Exit (0)
Iv. Deploying the server-side code from git bare repostory
In this example, I assume that the Git warehouse and the test server are on the same server. This is also a relatively common situation for small team development.
Structure of the service-side code
The server-side code is located in the/opt/openresty/nginx/lua folder. In this folder there is a subfolder based on the user name (branch name), which allows multiple developers to operate independently of the server code.
The following folder structure shows that two developers master and Zrong have deployed their own server-side code.
/opt/openresty/nginx/lua/
├──master
│└──main.lua
└──zrong
└──main.lua
Programmers can even choose to deploy other people's code into their own folders. It only needs to provide the branch name of the user you want to deploy (or simply provide a git commit SHA1) when you execute the command, and you can achieve this effect.
Command
The server contains the service-side code, and commands need to differentiate between the code-content push-back and the code-deployment push, or both.
The command is designed as follows:
If the first line of submissions contains up words, it is a command push. If there are other submissions at the same time, you can write a newline.
If it's just an ordinary submission, then write directly.
Assuming that the current Git library is located in the Zrong branch and that the current git warehouse is clean, here are a few examples:
Sample 1
Push the submitted code to the server and update the service-side code:
git commit--allow-empty-m ' up ' && git push Origin Zrong
Sample 2
To update the contents of the Allen branch in the server warehouse to/opt/openresty/nginx/lua/zrong:
git commit--allow-empty-m ' up Allen ' && git push Origin Zrong
Sample 3
Update the content in the commit SHA1 for 7ebbf4f3151e2dfd5bdcbe9fe276fc9b6afd25e7 to the/opt/openresty/nginx/lua/zrong:
git commit--allow-empty-m ' up 7ebbf4f ' && git push Origin Zrong
Export the contents of a bare warehouse
A git warehouse located on a server, usually bare, has no work-tree and cannot update the service-side code directly by copying it.
But we can use the git archive command to first export the code in the warehouse into a package, and then unpack the package to the appropriate deployment path to implement the server-side code update.
The following code does a few things:
Find server.git this bare warehouse;
Handle Zrong Branch;
Package the src/folder as a Src.tar file.
-
git--git-dir server.git archive-o src.tar zrong src/
If you want only one of these files, we can use git show to output the contents of this file to a file:
Git--git-dir server.git show Zrong:src/main.lua > Main.lua
Specific code
The following code shows the contents of the Post-receive hook in the server project.
#!/usr/bin/env python import sys import re Import os import subprocess import shutil luahome = '/opt/openresty/nginx/lua ' # uses the regular get command code and the branching information to be processed actionfmt = r ' ^up ? (\w+) $ ' branches = (' master ', ' Allen ', ' Zrong ', ' Xiefei ', ' ZM ') def Getgitargs (*args): if args: return [' git ', '--bare ', '--git-dir ',  OS.GETCWD ()] + list (args) return [] Def callgit (*args): return subprocess.check_output ([' Env ' , ' i '] + getgitargs (*args), universal_ Newlines=true, stderr=subprocess. STDOUT) # The true branch Def getref (branch) to be processed from the submission information: commitmsg = callgit (' Log ', branch, '--oneline ', '-1 ') [8:-1] matchobj = re.search (actionfmt, commitmsg) if matchobj: if matchobj.group (1): return matchobj.group (1) return
Branch return none # server/src Backup to a file def archive (refname): tarfile = '%s/%s.tar '% (luahome, refname) callgit (' Archive ', ' o ', tarfile, refname, ' src/') return tarfile # Unzip backup files to the correct folder Def tarxf (tarfile, refname, branch): refdir = os.path.join (Luahome, branch) if os.path.exists (refdir): shutil.rmtree (refdir) args = [' tar ', ' XF ', &Nbsp;tarfile, '-C ', luahome] output = subprocess.check_output (args, stderr=subprocess. Stdout, universal_newlines=true) shutil.move (Os.path.join (luahome, ' src/'), refdir) os.remove (tarfile) return output Oldrev,newrev , Refname = sys.stdin.readline (). Strip (). Split (' ') print (' oldref:%s, newrev:%s, refname:%s '% (oldrev, newrev, refname)) branch = refname.split ('/') [-1] if not Branch in branches: print (' the branch '%s ' is not in available list! ' ' the list is % S. '% (branch, str (branches))) exit (1) Try: refname = getref (Branch) if refnAme: tarfile = archive (refname)      SUCC = TARXF (Tarfile, refname, branch) print (' update [%s] by [%s] success. '% ( Branch, refname) ) print (' ======= update [% s] by [%s] success ======= '% (branch, refname)) except subprocess. Calledprocesserror as err: print (' update [%s] by [%s] error: %s '% (branch, refname, err.output)) print (' ======= update
[%s] by [%s] error ======= '% (branch, refname)) exit (1) Exit (0)