利用 GitHook 構建持續交付和部署
原文地址: https://blog.coding.net/blog/GitHook-for-delivery-and-deployment
1、為什么要打造可持續交付和部署
軟件發布是一個令人頭痛的過程,非常耗時且風險很高。對于小團隊來說一般分為兩種:“簽入時交付”和“定時交付”。
“簽入時交付”策略的優勢在于 馬上產生的滿足感 。根據代碼庫的規模,從簽入新功能代碼到能夠在交付準備服務器上測試,一兩分鐘就夠了。
這種方式的主要問題在于:交付準備服務器會被蹂躪得不穩定。很多時候,我見到有人試圖測試某個功能,突然新的版本推到交付準備服務器上了,破壞了正在運行的測試。更糟糕的是:交付準備服務器常常作為演示服務器使用,在某些重要的演示時,很可能出現嚴重的后果。
定期交付策略更易于預測。所有人都知道交付何時啟動,并可以規劃自己的代碼簽入是在交付之前還是之后進行。 典型做法是一天構建/交付一次或兩次。
由于架構的特殊性,服務器將會越來越多。試想一下你要在幾十臺服務器上更新代碼是一件多么繁瑣的事情。對于我們公司來說面臨著嚴重的如何更快交付和部署代碼的問題。
我們需要將經歷過測試的代碼能夠迅速部署到服務器上,本來考慮過jekins,但jekins對我們來說又太過繁瑣。
2、交付與部署過程
目前我們使用的是阿里云服務,阿里云服務有個很方便的地方就是鏡像,一次制作整個集群都可以使用。
工程師將代碼上傳到開發環境的庫中,通過GitHook自動讓測試用的服務器更新代碼,測試完成后只要將相關的代碼稍稍修改為生產環境的配置并上傳到生產環境的Git庫,通過GitHook所有與這個庫有關的服務器都會自動更新代碼。
測試的具體過程就不在此論述了。
3、GitHook
我們來看下官方解釋:
鉤子(hooks)是一些在"$GIT-DIR/hooks"目錄的腳本, 在被特定的事件(certain points)觸發后被調用。當"git init"命令被調用后, 一些非常有用的示例鉤子文件(hooks)被拷到新倉庫的hooks目錄中; 但是在默認情況下這些鉤子(hooks)是不生效的。 把這些鉤子文件(hooks)的".sample"文件名后綴去掉就可以使它們生效了。
簡單地來說有點類似回調,就是特定事情完成后回調執行事件。
4、如何搭建
我們公司使用的是coding、服務器上是已經裝好jetty的ubuntu,不過github、gitlab跟這個的配置方法類似。
Git-SSH
首先現在coding上建立一個代碼庫,然后在生產環境上的代碼部署的地方git clone剛剛新建的代碼庫。
沒有git的要安裝git,ubuntu下是apt-get install git
為了讓git能夠自動更新代碼庫而不需要輸入賬號密碼,這時候就需要用到git-ssh了。
如果是第一次使用要先設置git的名字和郵箱(自己隨便取個名字和郵箱就行):
git config --global user.name "test"
git config --global user.email "test@zomake.com"
然后通過上一個命令輸入的郵箱來生成密鑰
ssh-keygen -t rsa -C "test@zomake.com"
如果不需要設置密鑰的密碼的話,直接三個回車。然后你就在命令行上看到生成了兩個文件:id_rsa和id_rsa.pub。
(如果不是第一次的話執行命令會提示overwrite,輸入y就行。)
然后我們把密鑰交給ssh-agent來管理,可以通過eval "$(ssh-agent -s)"看看是不是正常運行,是的話會輸出它的pid。
ssh-add ~/.ssh/id_rsa
用上面這個命令將剛剛生成的私鑰交給ssh-agent。路徑填你在終端上看到的。
登錄coding,點擊賬戶-SSH公鑰-添加。將之前生成的id_rsa.pub里的內容復制進去。
最后進到之前clone下來的代碼庫中修改.git文件夾下config中的url,改為遠端倉庫的SSH訪問地址,如git@git.coding.net:t-baby/test.git
這樣一來在服務器上git就無需輸入賬號密碼了。
準備update.sh
cd /vi git_update.sh
然后將下面的東西復制進去并保存:
#!/bin/bash cd /opt/jetty/webapps git remote update -p git checkout -f origin/master git submodule update --init service jetty restart
第二行和最后一行根據需要自行更換,因為我們的代碼是Java的,放在jetty中運行。將第二行的cd改成你自己的代碼所在目錄。而最后一行代碼是用來重啟jetty服務器的,你可以去掉或加上自己服務器的重啟代碼。
保存后給這個腳本文件777的權限。
準備githook.php
由于一些原因,為了方便我們使用了php作為GitHook回調的地址。
先裝好PHP環境并修改端口為8080,apache默認文件夾為/var/www(80已經被jetty占了,具體安裝方法見我另一篇文章)
在/var/www/中新建一個叫githook.php,然后放入以下代碼:
shell_exec('cd /var/www && php gitpull.php');
然后再在當前文件夾下建個gitpull.php
$pid = pcntl_fork(); if ($pid == -1){ } else if ($pid > 0){ $fs = fopen('./git_hook.log', 'a'); fwrite($fs, 'Request on ['.date("Y-m-d H:i:s").']'.PHP_EOL); $json = file_get_contents('php://input'); $data = json_decode($json, true); fwrite($fs, 'Data: '.print_r($data, true).PHP_EOL); fwrite($fs, '======================================================================='.PHP_EOL); $fs and fclose($fs); pcntl_wait($status); } else if ($pid == 0){ exec('sudo sh /git_update.sh &'); }
執行git_update.sh更新git倉庫。
為什么要這樣做呢。因為coding的webhook的等待時間是寫死的,要5秒內有反應,這就會導致包含一些需要時間的命令會讓webhook的地址驗證不成功,從而在push后不回調到地址上。
所以我們用了多進程來讓其中一個執行日志的記錄,另一個負責執行sh文件。
填入回調地址
緊接著我們在coding中打開部署用的代碼庫,左側點擊設置-WebHook。比如我們剛剛的是http://111.111.111.111:8080/githook.php。
(ps:直接填寫IP可以減少域名解析所耗費的時間)
給apache權限
聰明的朋友們測試的時候肯定發現了問題,exec里面的代碼并不執行怎么辦?其實很簡單是因為apache的權限不夠,只要給予權限就行。
我們可以先通過lsof -i:80看看apache的執行用戶是誰。
比如我這里是www-data用戶,然后執行visudo。
然后找到圖片上的位置修改成圖片上那樣,后面那行www-data是要自己添加的。接著保存。保存的話就是ctrl+x然后回車。
這樣就可以讓apache不需要密碼就可以用管理員權限執行了。
趕緊測試下看看是不是成功了!
如何部署代碼以及結論
現在只要你一更新倉庫的代碼,就會自動回調到githook.php從而讓服務器自動更新代碼。即使多幾臺服務器也是一樣的,最簡單的方法就是利用公有云服務的鏡像功能做成鏡像裝在集群中的其它機器,然后在coding的WebHook那里加上這些服務器的IP就行。
這應該是全網最完善的相關教程了吧。自己靠著百度到很多不完整的資料琢磨了一天然后寫下此教程。找教程。。。最后別太相信百度到的,血的教訓~。