使用git的post-receive實現自動部署
這事斷斷續續折騰我大概兩週時間,這就把我經歷的事分享給大家。
為了實現在本地提交這個blog專案能不用手動到線上更新而努力著,剛開始在找解決辦法時以為就那麼簡單,結果卻折騰在docker、linux許可權和如何寫shell的幾個關鍵知識裡面。
流程
這裡先簡單介紹一下部署流程:
本地--[推送程式碼]-->git伺服器--[觸發]-->`post-receive`鉤子--[拉取程式碼]-->部署目錄
目前情況
以下是我目前的情況:
- git服務和網站服務在同一個伺服器上
- 專案不存在構建,只把生成的內容放到固定分支
- git服務用的是gogs
- 用ssh方式拉取程式碼
處理辦法
好了,具體怎麼做?
post-receive
然後把下面程式碼新增進去:
#!/bin/bash while read oldrev newrev refname do branch=$(git rev-parse --symbolic --abbrev-ref $refname) if [ "gh-pages" == "$branch" ]; then # 在這新增你需要做的部署行為 fi done
接下來得說說關鍵部分的部署程式碼,根據我目前的情況,在部署程式碼之前需要做兩件事情:
移除GIT_DIR
環境變數
這裡由於GIT_DIR
預設為’.’,會導致訪問地址不對並給出下面提示:
“fatal: Not a git repository: ‘.’”
處理辦法:
unset GIT_DIR
生成金鑰
為滿足使用ssh方式拉取程式碼就會需要金鑰,我gogs是跑在docker容器下,第一步先進入容器然後生成金鑰:
ssh-keygen -t rsa -C "your name or email"
如何生成金鑰這裡就不詳細說明,各位到網上自查攻略吧!
再來到gogs的[倉庫設定]->[管理部署金鑰]->[新增部署金鑰]把公鑰新增進去就能用了。
自定義ssh請求
為滿足ssh指定載入特定金鑰,需要在git執行前自定義ssh的操作:
GIT_SSH_COMMAND="ssh -i /git/.ssh/id_rsa" git fetch
GIT_SSH_COMMAND
只適用於 git version 大於 2.6 的版本
執行後會出現一堆提示而且不會執行git的具體操作:
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! Someone could be eavesdropping on you right now (man-in-the-middle attack)! It is also possible that the RSA host key has just been changed. The fingerprint for the RSA key sent by the remote host is 50:e6:cb:58:bc:b7:a3:f6:e8:8f:46:a7:c1:5f:c2:df. Please contact your system administrator. Add correct host key in /git/.ssh/known_hosts to get rid of this message. Offending key in /git/.ssh/known_hosts:7 RSA host key for 192.168.0.4 has changed and you have requested strict checking. Host key verification failed.
傳送ssh請求會詢問是否把相關資訊記錄至known_hosts
,但是由於是指令碼處理所以並沒得到處理,最後會給出上面的提示。
解決辦法有三種:
- 刪除提示資訊中,對應的行數,例如上例,需要刪除/git/.ssh/known_hosts檔案的第7行。
- 刪除整份/git/.ssh/known_hosts檔案。
上面兩種並不能從根本解決問題,這裡推薦在ssh命令後新增下面兩個引數的第三種解決辦法:
-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null
GIT_SSH_COMMAND="ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i /git/.ssh/id_rsa" git fetch
寫成這樣就能帶上給定的ssh金鑰,到這裡基本把需要解決的問題都解決了,下面給上完整程式碼:
#!/bin/bash while read oldrev newrev refname do branch=$(git rev-parse --symbolic --abbrev-ref $refname) if [ "gh-pages" == "$branch" ]; then printf "branch:$branch\n" PROJECT_ROOT=/www PROJECT_PATH="$PROJECT_ROOT/[目錄地址]" REPO_PATH="[git地址]" REPO_BRANCH="$branch" # GIT_DIR預設為'.',會導致訪問地址不對,故需要移除GIT_DIR環境變數 # > https://alfred-long.iteye.com/blog/1836347 unset GIT_DIR # `-o StrictHostKeyChecking=no` 不檢查公鑰 # `-o UserKnownHostsFile=/dev/null` 不更新known_hosts # `-i /git/.ssh/uxfeel` 指定金鑰 # > https://www.cnblogs.com/zhengah/p/4959682.html GIT_SSH_COMMAND="ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i /git/.ssh/uxfeel" export GIT_SSH_COMMAND if [ ! -d "$PROJECT_PATH" ]; then printf "git clone -b$REPO_BRANCH$REPO_PATH\n" cd "$PROJECT_ROOT" git clone -b "$REPO_BRANCH" "$REPO_PATH" printf "git clone finish.\n\n" else cd "$PROJECT_PATH" printf "git fetch \n" git fetch printf "git fetch finish.\n\n" printf "git pull \n" git pull printf "git pull finish." fi fi done
這裡說幾點需要注意的:
- 外部部署環境的目錄權限盡量和容器裡面生成目錄的許可權保持一致(能解決大部分的許可權問題)
- 搞清楚shell當前的許可權所屬再寫shell(少走彎路,特別是你不太清醒的時候)
-
應用只全域性的變數一定要
export
,export
,export
(重要的事情說三次,這個害我花了不少時間)
如果你的環境沒那麼複雜是真的不用考慮那麼多,自己擼起可能會比我少走很多彎路,希望大家處理許可權的時候記住:linux許可權規則還是linux的許可權規則,不要給docker給迷惑了!