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


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

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

 

1、自動化部署概述

1.1 什么是自動化部署

一句簡單的話概括:部署的過程中所有的操作全部自動化,無需人工手工干預。

1.2 自動部署的好處

傳統的部署方式如下:

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

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

  • 開發人員手工編譯打包,然后通過內網傳輸給運維人員

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

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

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

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

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

  • 存在一定的管理混亂,人為誤操作的機率增大

所以,自動化部署的優勢就通過這種對比顯現出來了!!

 

2、自動化部署的工具

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

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是面向罐裝的解決方案用例,目前還不夠靈活。

 

3、自動化部署的流程

大概的流程步驟如下:

  • 獲取代碼

  • 編譯打包

  • 移除目標服務器

  • 解壓文件到目標目錄

  • 拷貝差異化文件

  • 重啟服務

  • 測試

  • 重新加入集群

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

 

 

如果在測試時出現問題,則需要回滾到上一次穩定版本。

一般可以將需要回滾的版本先列出來,然后將現有的軟鏈接文件刪除,重新將上一個版本的源文件生成一個軟鏈接至目標目錄,然后重新啟動服務,進行自動化測試,最終加入集群。

 

4、自動化部署實踐

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

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

 

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

腳本使用環境:

1、操作系統:centos 6.5 64位

2、代碼使用gitlab進行管理

3、代碼每次上線通過tag控制

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

5、WEB container使用tomcat實現

6、項目構建使用maven

使用腳本注意事項:
1、 發布機器需要能夠解析web服務器主機名,並且配置ssh通信
2、 變量中的目錄以及用戶等信息需要自己創建,腳本沒有做判斷自己創建。我這里web服務器是使用ansible進行部署的,相關目錄和用戶都會自動創建。
3、代碼的部署使用tag,但是代碼的更新使用軟連接來控制,回滾則切換到上一個軟連接
4、由於java是編譯型語言,我們使用maven來進行編譯,所以需要安裝maven環境。
5、關於環境配置文件:配置文件為自己手動維護,每次都是刪除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代碼自動發布

腳本適應環境:

1、操作系統:centos 6.5 64位

2、代碼使用gitlab進行管理

3、代碼每次上線和回滾通過tag控制

補充:如果需要在你的企業使用我的這種部署方式,還需要有相應環境規范以及git分支管理規范。

使用腳本注意事項:
1、 發布機器需要能夠解析web服務器主機名,並且配置ssh通信
2、 變量中的目錄以及用戶等信息需要自己創建,腳本沒有做判斷自己創建。我這里web服務器是使用ansible進行部署的,相關目錄和用戶都會自動創建。
3、代碼的部署使用tag,回滾原則為回滾到上個tag版本,所以部署腳本本身沒有備份代碼。
4、如果需要過濾一些臨時目錄或者日志目錄,可以在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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM