-
Why?
為什麼要做自動化流程?
在開發過程中,我們在本地機器上做開發,完成一次功能疊代之後,如何釋出到遠端産品伺服器一直是個很頭疼的問題。最通常的做法就是使用(S)FTP把代碼(或者代碼壓縮包)覆寫到伺服器上。這樣的做法雖然“直截了當”,但是容易出錯,而且全程需要人為幹預。(筆者親曆過其他項目部門的負責人過來求助,說釋出時拷貝代碼到伺服器的過程中,伺服器突然當機沒有反應。)是以我們需要一種方式幫助我們完成代碼釋出的整個過程。有非常多的第三方工具幫助我們實作流程自動化的目的。
我們要完成的目标是:1,無人幹預;2,縮短釋出時間,減少釋出時期存在的風險;3,增加項目疊代效率。
-
What?
用什麼工具來做自動化流程?
git, github(gitlab)
-
When?
在什麼時機下建立自動化流程?
理論上是在第一次釋出項目到伺服器之前就需要做自動化流程。但是根據疊代開發的思想,我們在建立項目的時候就應該開始着手建立自動化流程。
-
How?
如何建立一個最小化的自動化流程?
我們通過三部實作開發部署流程自動化。
-
建立版本倉庫
筆者使用Gitlab建立一個名為DevOps的私有倉庫.
new gitlab repo
接着clone 遠端倉庫到本地開發機器.
如果你還沒有建立任何項目代碼檔案。此時可以使用指令:
git clone [email protected]:EdisonLeung/devops.git
cd devops
touch README.md
git add README.md
git commit -m "add README"
git push -u origin master
如果您已經開始了本地機器上的編碼工作,此時可以在項目目錄下使用指令:
git init
git remote add origin [email protected]:EdisonLeung/devops.git
git add .
git commit -m "Initial commit"
git push -u origin master
如果您不光在本地開始了編碼工作,同時在本地已經建立了git倉庫.此時可以在項目目錄下使用指令:
git remote rename origin old-origin
git remote add origin [email protected]:EdisonLeung/devops.git
git push -u origin --all
git push -u origin --tags
最後在伺服器clone我們的版本倉庫(記得添加伺服器SSH Key到Gitlab):
cd ~/www
git clone [email protected]:EdisonLeung/devops.git
clone完成:
[email protected]:~/www# git clone [email protected]:EdisonLeung/devops.git
Cloning into 'devops'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (3/3), done.
目前我們從項目開發到項目部署有三個動作要手動做:
a) 本地機器git push到遠端倉庫
b) 遠端伺服器git pull拉去遠端倉庫版本
c) 重新開機webserver服務
第二步我們就要将這三個動作自動化。
-
建立自動化部署腳本
建立deploy目錄,并建立兩個檔案,main.go和deploy.sh:
目錄結構
deploy.go
package main
import (
"io"
"log"
"net/http"
"os/exec"
)
func relaunching() {
cmd := exec.Command("sh", "./deploy.sh")
err := cmd.Start()
if err != nil {
log.Fatal(err)
}
err = cmd.Wait()
}
func restart(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "<h1>deploy server: restarting webserver...</h1>")
relaunching()
io.WriteString(w, "<h1>deploy server: webserver restarted!</h1>")
}
func main() {
http.HandleFunc("/", restart)
http.ListenAndServe(":5000", nil)
}
當伺服器5000端口被通路時,http.HandleFunc會建立路由調用restart函數relaunching函數,調用過程中在浏覽器輸出啟動過程.
最終relaunching函數調用指令行deploy.sh來重新開機webserver.
deploy.sh腳本内容如下:
#! /bin/sh
kill -9 $(pgrep webserver)
cd ~/www/devops
git pull [email protected]:EdisonLeung/devops.git
./webserver &
再建立一個main.go來啟動一個最小web頁面:
webserver main.go
代碼示例如下:
package main
import (
"io"
"net/http"
)
func index(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "<h1>This is Index Page!</h1>")
}
func main() {
http.HandleFunc("/", index)
http.ListenAndServe(":8080", nil)
}
注意:這裡的http監聽端口号要與deploy.go内的端口号差別開,不能是相同端口号,不然會有端口沖突造成服務不能啟動!
這時的代碼架構就完成了,下面我們來編譯釋出代碼:
因為我們在本地機器環境編譯代碼,是以對于異構系統來說,go語言為我們提供了相應的參數來針對不同的作業系統和架構進行代碼的編譯:
因為伺服器所采用的是linux amd64的系統,是以編譯指令的環境變量如下:
main.go編譯生成webserver
env GOOS=linux GOARCH=amd64 go build -o webserver
進入deploy目錄編譯生成deploy
env GOOS=linux GOARCH=amd64 go build
輸出的檔案如圖:
編輯結果
下面我們送出項目:
進入DevOps根目錄
git add .
git commit -m "basic automatic publishing feature."
git push origin master
送出結果:
Counting objects: 8, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (8/8), done.
Writing objects: 100% (8/8), 5.03 MiB | 1.21 MiB/s, done.
Total 8 (delta 1), reused 0 (delta 0)
To gitlab.com:EdisonLeung/devops.git
91e5396..c9c087f master -> master
接下來就要進入伺服器拉去最新版本代碼并釋出。
登入遠端伺服器拉取代碼:
[email protected]:~/www/devops# git pull
remote: Enumerating objects: 9, done.
remote: Counting objects: 100% (9/9), done.
remote: Compressing objects: 100% (8/8), done.
remote: Total 8 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (8/8), done.
From gitlab.com:EdisonLeung/devops
91e5396..c9c087f master -> origin/master
Updating 91e5396..c9c087f
Fast-forward
deploy/deploy | Bin 0 -> 6594124 bytes
deploy/deploy.go | 28 ++++++++++++++++++++++++++++
deploy/deploy.sh | 6 ++++++
main.go | 15 +++++++++++++++
webserver | Bin 0 -> 6498848 bytes
5 files changed, 49 insertions(+)
create mode 100755 deploy/deploy
create mode 100644 deploy/deploy.go
create mode 100644 deploy/deploy.sh
create mode 100644 main.go
create mode 100755 webserver
将deploy目錄拷貝至使用者根目錄:
cp -r ~/www/devops/deploy/* ~/
啟動webserver和deploy service:
cd ~
./www/devops/webserver &
./deploy &
打開浏覽器檢視結果顯示:
webserver result
deploy service result
兩個服務均啟動成功了!
注意1.兩個服務啟動前,先用以下指令檢視是否有相同服務正在運作,如果有,先将其kill掉:
$ps aux | grep webserver
$kill [pid]
注意2.使用chmod指令給服務程式和腳本提權:
chmod a+x webserver
-
自動擷取版本推送事件webhook
我們将部署觸發的位址添加到遠端版本倉庫的webhook中,如圖:
webhook
webhook添加完成:
webhook
下面我們驗證一下這個簡單的自動化流程的效果。
我們把顯示的文本改為"This is the Index Page2".
change code
然後編譯送出
編譯送出
檢視結果:
釋出疊代成功
文章中提到的做法僅僅是抛磚引玉,實作使用Golang是因為語言結構上簡短精悍,更容易了解流程,如果您使用其他語言,例如python,php等都可以用相同的方式實作。同時流程上僅關注自動化的過程,開發編譯的整個過程都在本地進行,服務端沒有提到任何反向代理的服務及運作環境、虛拟環境的配置,因為在虛拟化環境下這些做法會有很多變化,很多情況下完全沒有必要做,或者很少去做。更沒有必要像目前這樣自己去實作自動化流程。如果沒有虛拟化實作自動化流程的經驗,直接上手虛拟化,還沒有很深入了解的情況下,在虛拟化環境下做DevOps及微服務架構,會給自己帶來很大的困惑。具體這些将會在後續的文章中提到。