一鍵實現自動化部署(灰度發佈)實踐

 

 

在過去幾年的DevOps的浪潮中,自動化、持續集成這兩個概念早已深刻人心(互聯網技術人)。比爾蓋茨先生曾經都說過:「任何技術在一個業務中使用的第一條規則就是,將自動化應用到一個高效的操做上將會放大高效。第二條就是自動化應用到一個低效操做上,則放大了低效率。」php

自動化部署也逐漸成爲各中小型企業追求的方向,那麼,今天民工哥就自動化部署的概述、自動化部署的工具、自動化部署的流程、自動化部署實踐等4個方面,與你們一同來討論、交流一下關於中小企業自動部署的問題。前端

 

一、自動化部署概述java

1.1 什麼是自動化部署linux

一句簡單的話歸納:部署的過程當中全部的操做所有自動化,無需人工手工干預。git

1.2 自動部署的好處web

傳統的部署方式以下:shell

  • 運維人員手工使用Scp、Xftp等方式來傳輸數據後端

  • 手工登陸服務器執行git pull 、svn update等命令進行更新代碼的操做centos

  • 開發人員手工編譯打包,而後經過內網傳輸給運維人員api

  • 運維人員經過rz上傳的方式上傳到目標服務器,而後,執行重命名原包、拷貝新包到目標目錄,再執行服務應用重啓命令完成整個部署過程

看似很是簡單,也不是很麻煩,可是一旦項目多,部署頻繁,這種狀況下就會大大下降工做效率。民工哥以前工做中就有這類體驗,公司的活動類項目高達100+,不少都是須要快速上線及下線、或者更新的,手工部署真的累。

傳統的部署方式有如下的缺點:

  • 整個過程都須要人員參與,佔用大量的時間,效率低下

  • 上線、更新、回滾速度慢

  • 存在必定的管理混亂,人爲誤操做的機率增大

因此,自動化部署的優點就經過這種對比顯現出來了!!

 

二、自動化部署的工具

有自動動部署的概念,就須要自動化部署的工具,今天來介紹下一些這方面的工具給你們,怎麼用?如何用?你們根據實際需求來定,一切不以需求來定的工具、流程、方法等都是耍流氓。

2.1 Jenkins 

Jenkins是一個開源軟件項目,是基於Java開發的一種持續集成工具,用於監控持續重複的工做,旨在提供一個開放易用的軟件平臺,使軟件的持續集成變成可能。Jenkins應該說是目前最好用的持續集成工具之一,它的插件很是多,安裝也很方便,功能至關的強大、靈活,最大的缺點就是學習成本較高。

2.2 ElectricFlow 
ElectricFlow 是一個發佈自動化工具,提供免費的社區版本,你能夠在VirtualBox上運行。ElecticFlow支持大量插件和基於Groovy的 DSL,CLI,APIs。
 
2.3 Microsoft Visual Studio
微軟DevOps產品的基礎之一是 Visual Studio。 Visual Studio容許用戶定義版本定義,自動化運行,跟蹤版本等等。
 
2.4 Octopus Deploy
Octopus Deploy建立目的是爲了.NET應用的自動化部署。你能夠在一臺服務器安裝或在Azure裏作成實例。
 
2.5 IBM UrbanCode
2013年被IBM公司收購,UrbanCode 自動化部署到本地或雲環境。
 
2.6 AWS CodeDeploy
Amazon的自動化部署工具CodeDeploy,有着使人印象深入的客戶名單、平臺與語言無關。
 
2.7 DeployBot
DeployBot 能夠連接任何Git存儲庫,而且容許手動或自動部署到多種環境。DeployBot提供大量集成,包括經過Slack部署的能力。
 
2.8 Shippable
Shippable 規定了它們本身的「DevOps支柱」和它們本身的CI平臺,運行依靠稱爲minions的基於Docker的容器。
 
2.9 TeamCity
TeamCity 是一個來自Jet Brains的CI服務器。TeamCity 有智能的配置功能和擁有官方Docker鏡像服務器和代理。
 
2.10 Bamboo
Bamboo Server 是CI,由來自在Atlassian的人們提供,他們是Jira和Confluence的製造者。Bamboo公佈「integrations that matter」並提供一個「small teams」包,捐贈給 Room to Read慈善事業。
 
2.11 Codar
Codar 是一個HP的持續部署解決方案。部署使用Jenkins觸發。
 
2.12 CircleCI
CircleCI 是一個CI解決方案,強調靈活性、可靠性和速度。CircleCI提供從資源到建立到部署的解決方案,而且支持大量的語言和應用。
 
2.13 Gradle
Gradle 是一個被一些業內最有名的例如LinkedIn, Netflix, 和Adobe所使用的建立工具。Gradle使用Groovy建立腳本,按慣例構建框架,並認爲構建工具同時做爲Apache的Ant的通用工具。
 
2.14 Automic
Automic 試圖應用DevOps原理給一些後端應用,容許他們從已經在過去幾年裏許多前端、基於web的應用相同的實踐上受益。
 
2.15 Distelli
Distelli 專門在任何地方部署Kubernetes集羣,除了能夠在任何雲或物理服務器上使用。根據TechCrunch這篇文章,Distelli 在2015年12月得到了280萬美圓的資金,是由前AWS員工Rahul Singh創立的。
 
2.16 XL Deploy
XL Deploy 是一個來自XebiaLabs的應用發佈自動化工具,支持大量插件和環境,使用無代理架構。
 
2.17 Codeship
Codeship是服務器託管CI解決方案,經過原生Docker支持定製。
 
2.18 GoCD
一個CD服務器,強調可視化工做流,GoCD 是一個開源項目,由ThoughtWorks公司贊助開發。
 
2.19 Capistrano
Capistrano 是一個開源部署工具,使用Ruby開發。Capistrano 文檔具備腳本語言和「理智的,富有表現力的API。」
 
2.20 Travis CI
Travis CI 能夠同步到你的GitHub帳戶,容許自動化測試和部署。Travis CI是一個免費的開源項目。
 
2.21 BuildBot 
BuildBot 是一個開源的基於Python的持續集框架,自稱爲「內含有電池的框架」。BuildBot是面向罐裝的解決方案用例,目前還不夠靈活。

 

三、自動化部署的流程

大概的流程步驟以下:

    • 獲取代碼

    • 編譯打包

    • 移除目標服務器

    • 解壓文件到目標目錄

    • 拷貝差別化文件

    • 重啓服務

    • 測試

    • 從新加入集羣

    • 繼續下一個節點或一組節點

 

 

若是在測試時出現問題,則須要回滾到上一次穩定版本。

通常能夠將須要回滾的版本先列出來,而後將現有的軟連接文件刪除,從新將上一個版本的源文件生成一個軟連接至目標目錄,而後從新啓動服務,進行自動化測試,最終加入集羣。

 

四、自動化部署實踐

說完了一堆的理論東東,接下來就是須要實踐操做了,我以前也寫過一個自動化的腳本,以下圖:

 

 

這裏列舉兩個實例,這兩個實例是由網友西門飛冰投稿提供,具體的實例以下:

 

4.1 使用shell腳本實現java灰度發佈

腳本使用環境:

一、操做系統:centos 6.5 64位

二、代碼使用gitlab進行管理

三、代碼每次上線經過tag控制

四、前端使用haproxy實現負載均衡,使用haproxy socat實現RS的平滑上下線

五、WEB container使用tomcat實現

六、項目構建使用maven

使用腳本注意事項:
一、 發佈機器須要可以解析web服務器主機名,而且配置ssh通訊
二、 變量中的目錄以及用戶等信息須要本身建立,腳本沒有作判斷本身建立。我這裏web服務器是使用ansible進行部署的,相關目錄和用戶都會自動建立。
三、代碼的部署使用tag,可是代碼的更新使用軟鏈接來控制,回滾則切換到上一個軟鏈接
四、因爲java是編譯型語言,咱們使用maven來進行編譯,因此須要安裝maven環境。
五、關於環境配置文件:配置文件爲本身手動維護,每次都是刪除git倉庫拉取下來的配置文件,把對應環境的代碼文件複製進編譯目錄進行編譯。

腳本代碼大概的步驟以下:

#!/bin/bash

# 設置時間變量
CTIME=$(date "+%Y-%m-%d-%H-%M")
# 項目名稱,建議和gitlab倉庫名稱一致
project=
# 本地代碼目錄(gitlab拉取代碼後存放目錄)
CODE_DIR=/data/gitlab/"$project"
# 臨時代碼目錄,用來修改配置文件和編譯打包代碼
TMP_DIR=/data/tmp/"$project"
# 用來存放war包
WAR_DIR=/data/war/"$project"
# 對應環境配置文件
deploy_conf=/data/conf/pro/"$project"/*
# 代碼中的配置文件路徑
local_conf=$TMP_DIR/src/main/resources/config
# 遠程主機名稱
REMOTE_HOST="tomcat-01 tomcat-02"
# 遠程主機代碼目錄
REMOTE_CODE_DIR=/data/webapps/"$project"
# 遠程主機用戶
REMOTE_USER=root
# 遠程主機war包存放目錄
REMOTE_WAR_DIR=/data/war/
# 代碼臨時目錄
CODE_TMP=/data/code_tmp/
# 上線日誌
DEPKOY_LOG=/data/log/pro_log.log

# 腳本使用幫助
usage(){
echo $"Usage: $0 [deploy tag | rollback_list | rollback_pro ver]"
}

# 拉取代碼
git_pro(){
if [ $# -lt 1 ];then
echo "請傳入tag"
exit 1
fi
tag=$1
cd $CODE_DIR && git checkout master && git pull && git checkout $1
if [ $? != 0 ];then
echo "拉取代碼失敗"
exit 10
fi
cd $CODE_DIR && git pull 2>/dev/null >/dev/null
# 推送代碼到臨時目錄
rsync -avz --delete $CODE_DIR/ $TMP_DIR/ 2>/dev/null >/dev/null
}

# 設置代碼的配置文件
config_pro(){
echo "設置代碼配置文件"
rm -f $local_conf/config.properties
.........
}

# 打包代碼
tar_pro(){
echo "本地打包代碼"
cd $TMP_DIR && /usr/local/maven/bin/mvn clean compile war:war && cp target/"$project".war "$WAR_DIR"/"$project"_"$tag"_"$CTIME".war
}

# 推送war包到遠端服務器
rsync_pro(){
echo "推送war包到遠端服務器"
for host in $REMOTE_HOST;do
scp "$WAR_DIR"/"$project"_"$tag"_"$CTIME".war $REMOTE_USER@$host:$REMOTE_WAR_DIR
done
}

# 解壓代碼包
solution_pro(){
echo "解壓代碼包"
for host in $REMOTE_HOST;do
ssh $REMOTE_USER@$host "unzip "$REMOTE_WAR_DIR""$project"_"$tag"_"$CTIME".war -d "$CODE_TMP""$project"_"$tag"_"$CTIME"" 2>/dev/null >/dev/null
done
}

# api測試
test_pro(){
# 運行api測試腳本,若是api測試有問題,則退出部署
if [ $? != 0 ];then
echo "API測試存在問題,退出部署"
exit 10
fi
}


# 部署代碼
deploy_pro(){
echo "部署代碼"
...................
sleep 3
# 執行api測試
test_pro
ssh haproxy "echo "enable server $project/$host" | /usr/bin/socat /var/lib/haproxy/stats stdio"
done
}
# 列出能夠回滾的版本
rollback_list(){
echo "------------可回滾版本-------------"
ssh $REMOTE_USER@$REMOTE_HOST "ls -r "$CODE_TMP" | grep -o $project.*"
}

# 回滾代碼
rollback_pro(){
   echo "回滾中"
   for host in $REMOTE_HOST;do
   .............................
   sleep 3
   ssh haproxy "echo "enable server $project/$host" | /usr/bin/socat /var/lib/haproxy/stats stdio"
   done
}

# 記錄日誌
record_log(){
   echo "$CTIME 主機:$REMOTE_HOST 項目:$project tag:$1" >> $DEPKOY_LOG
}

# 代碼執行選項設置
main(){
   case $1 in
    deploy)
    git_pro $2;
    config_pro;
    tar_pro;
    rsync_pro;
    solution_pro;
    deploy_pro;
    record_log $2;
    ;;
    rollback_list)
    rollback_list;
    ;;
    rollback_pro)
    rollback_pro $2;
    record_log;
    ;;
    *)
    usage;
    esac
}
main $1 $2

 

4.2 使用shell實現php代碼自動發佈

腳本適應環境:

一、操做系統:centos 6.5 64位

二、代碼使用gitlab進行管理

三、代碼每次上線和回滾經過tag控制

補充:若是須要在你的企業使用個人這種部署方式,還須要有相應環境規範以及git分支管理規範。

使用腳本注意事項:
一、 發佈機器須要可以解析web服務器主機名,而且配置ssh通訊
二、 變量中的目錄以及用戶等信息須要本身建立,腳本沒有作判斷本身建立。我這裏web服務器是使用ansible進行部署的,相關目錄和用戶都會自動建立。
三、代碼的部署使用tag,回滾原則爲回滾到上個tag版本,因此部署腳本自己沒有備份代碼。
四、若是須要過濾一些臨時目錄或者日誌目錄,能夠在rsync推送代碼的時候使用–exclude選項進行過濾,示例腳本中過濾了.git目錄和config.php文件是不會部署的。

#!/bin/bash

# 設置時間相關變量
CTIME=$(date "+%Y-%m-%d-%H-%M")
# 項目名稱,建議和gitlab倉庫名稱一致
project=test
# 本地代碼目錄(gitlab拉取代碼後存放目錄)
CODE_DIR=/data/gitlab/pro/$project/
# 遠程主機
REMOTE_HOST="LNMP-01.fblinux.com LNMP-02.fblinux.com"
# 遠程主機代碼目錄
REMOTE_DIR=/data/www/fblinux/
# 遠程主機用戶
REMOTE_USER=root
# 遠程主機代碼執行用戶
CODE_USER=php
# 上線日誌
DEPKOY_LOG=/data/log/pro_log.log

#腳本使用幫助
usage(){
echo $"Usage: $0 [deploy tag]"
}

#拉取代碼
git_pro(){
if [ $# -lt 1 ];then
echo "請傳入tag"
exit 1
fi
echo "拉取代碼"
cd $CODE_DIR && git checkout master && git pull && git checkout $1
if [ $? != 0 ];then
echo "拉取代碼失敗"
exit 10
fi
cd $CODE_DIR && git pull
}

#推送代碼服務器
rsync_pro(){
for host in $REMOTE_HOST;do
echo "推送代碼到服務器$host"
rsync -rPv -P --delete --exclude="config.php" --exclude=".git" $CODE_DIR -e 'ssh -p 22' $REMOTE_USER@$host:$REMOTE_DIR
if [ $? != 0 ];then
echo "推送代碼失敗"
exit 10
fi
echo "代碼受權"
ssh $REMOTE_USER@$host "chown -R $CODE_USER $REMOTE_DIR"
if [ $? != 0 ];then
echo "代碼受權失敗"
exit 10
fi
done
}

#記錄日誌
record_log(){
echo "$CTIME 主機:$REMOTE_HOST 項目:$project tag:$1" >> $DEPKOY_LOG
}

main(){
case $1 in
deploy)
git_pro $2;
rsync_pro;
record_log $2;
;;
*)
usage;
esac
}
main $1 $2

以上就是兩個實際的生產部署實例的配置環境、注意事項及代碼等講解。讀者若是須要上述兩個實例的完整代碼請在 民工哥技術之路 公衆號後臺回覆 「自動化部署」來獲取腳本完整代碼的下載地址。

參考資料以下:

https://dzone.com/articles/21-automated-deployment-tools-you-should-know 

http://www.fblinux.com/?p=489    

http://www.fblinux.com/?p=476

相關文章
相關標籤/搜索