一鍵實現自動化部署(灰度釋出)實踐

民工哥技術之路發表於2019-08-27

在過去幾年的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、自動化部署的流程

大概的流程步驟如下:

  • 獲取程式碼
  • 編譯打包
  • 移除目標伺服器
  • 解壓檔案到目標目錄
  • 拷貝差異化檔案
  • 重啟服務
  • 測試
  • 重新加入叢集
  • 繼續下一個節點或一組節點

clipboard.png

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

一般可以將需要回滾的版本先列出來,然後將現有的軟連結檔案刪除,重新將上一個版本的原始檔生成一個軟連結至目標目錄,然後重新啟動服務,進行自動化測試,最終加入叢集。

4、自動化部署實踐

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

clipboard.png

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

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...
http://www.fblinux.com/?p=489
http://www.fblinux.com/?p=476

在 民工哥技術之路 微信公眾號對話方塊回覆關鍵字:1024 可以獲取一份最新整理的技術乾貨。

clipboard.png

相關文章