日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

运维与自动化系列③自动化部署基础与shell脚本实现

發(fā)布時(shí)間:2025/3/20 编程问答 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 运维与自动化系列③自动化部署基础与shell脚本实现 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

自動(dòng)化部署基礎(chǔ)與shell腳本實(shí)現(xiàn)

關(guān)于自動(dòng)化的基礎(chǔ)知識:

1.1:當(dāng)前代碼部署的實(shí)現(xiàn)方式:

運(yùn)維純手工scp到web服務(wù)器
純手工登錄git服務(wù)器執(zhí)行g(shù)it pull或svn服務(wù)器執(zhí)行svn update更新代碼
通過xftp上傳代碼
開發(fā)打壓縮包上傳到服務(wù)器然后解壓

缺點(diǎn):
1.需要運(yùn)維全程參與,占用大量的工作時(shí)間
2.上線時(shí)間比較慢
3.人為造成的失誤較多,管理比較混亂
4.回滾復(fù)雜而且慢,還不及時(shí)

1.2:運(yùn)行環(huán)境規(guī)劃:
開發(fā)環(huán)境:開發(fā)者本地有自己的環(huán)境,然后運(yùn)維需要設(shè)置開發(fā)環(huán)境的公用服務(wù),例如開發(fā)數(shù)據(jù)庫、redis、memcached等
測試環(huán)境:功能測試環(huán)境和性能測試環(huán)境
預(yù)生產(chǎn)環(huán)境:由生產(chǎn)環(huán)境集群中的某一個(gè)節(jié)點(diǎn)擔(dān)任測試,此節(jié)點(diǎn)只做測試不對外提供服務(wù)
生產(chǎn)環(huán)境:直接對外提供服務(wù)的環(huán)境

為什么有預(yù)生產(chǎn)環(huán)境?
可能是生產(chǎn)環(huán)境預(yù)測試環(huán)境的數(shù)據(jù)庫或數(shù)據(jù)庫版本不一樣導(dǎo)致語句出現(xiàn)問題
或者是生產(chǎn)環(huán)境調(diào)用的接口不一樣,例如支付接口在測試環(huán)境無法調(diào)用

1.3:設(shè)計(jì)一套生產(chǎn)環(huán)境的代碼自動(dòng)化部署系統(tǒng):

開發(fā)環(huán)境 --> 功能測試/性能測試 --> 預(yù)生產(chǎn)環(huán)境 --> 生產(chǎn)環(huán)境

1.4:總體規(guī)劃流程:
一個(gè)服務(wù)的集群節(jié)點(diǎn)數(shù)量,是一次部署還是分次部署
一鍵回滾到上個(gè)版本
一鍵回滾到任意版本
代碼保存在SVN還是Git
獲取指定分支或master的指定版本號的代碼,svn指定版本號,git指定tag標(biāo)簽,或直接拉取某個(gè)分支
配置文件差異化,即測試環(huán)境和生產(chǎn)環(huán)境的配置文件不一樣,如IP不一樣或主機(jī)名不一樣或數(shù)據(jù)庫連接不一樣等等
代碼倉庫和實(shí)際的差異,即配置文件是否放在代碼倉庫中,如果保存在git則所有人都可以從配置文件看到數(shù)據(jù)庫用戶密碼等信息,可以使用單獨(dú)分支保存配置文件,或配置文件只在部署服務(wù)器的某個(gè)項(xiàng)目的目錄,比如是config.example
如何更新代碼,java tomcat需要重啟
測試部署后的web頁面是否可以正常訪問是否是想要的頁面
并行(saltstack)或并行(shell)的問題,涉及到分組部署重啟服務(wù)
如何執(zhí)行,shell執(zhí)行還是web執(zhí)行

1.5:總體規(guī)劃如下:

獲取代碼(git pull拉取) --> 是否編譯(java需要編譯) --> 配置文件(統(tǒng)一和差異) --> 打包 --> scp到目標(biāo)服務(wù)器(或者用saltstack) --> 將服務(wù)器移除集群 --> 解壓代碼包 --> 放置到目標(biāo)目錄(如webroot) --> scp差異文件 --> 重啟服務(wù)(可選) --> 測試服務(wù)(訪問web或者post請求) --> 將節(jié)點(diǎn)重新加入集群

二:實(shí)現(xiàn)代碼自動(dòng)化部署

2.1:通過shell腳本實(shí)現(xiàn),shell腳本規(guī)劃如下:

2.1.1:各web服務(wù)器添加一個(gè)uid相同的普通用戶,而且所有的web服務(wù)都以此普通用戶啟動(dòng),默認(rèn)情況下所有的wenb服務(wù)除了負(fù)載均衡之外都不能監(jiān)聽80端口,比如可以監(jiān)聽8008端口

2.1.2:部署服務(wù)器的用戶登錄其他服務(wù)器免密碼登錄,因此需要做秘鑰認(rèn)證,在各主機(jī)執(zhí)行以下命令:

# useradd www -u 1010
# su – www
$ ssh-keygen
#將部署機(jī)www用戶的公鑰復(fù)制到各web服務(wù)器的 /home/www/.ssh/authorized_keys或執(zhí)行ssh-copy-id www@192.168.3.13

$ chmod 600 /home/www/.ssh/authorized_keys

2.1.3:測試部署服務(wù)器是否可以免秘鑰用www用戶登錄各個(gè)web服務(wù)器

2.2:編寫shell腳本:
2.2.1:完成框架編寫:

#!/bin/bash#shell env SHELL_NAME="deploy.sh" SHELL_DIR="/home/www/" # 腳本路徑 SHELL_LOG="${SHELL_DIR}/${SHELL_NAME}.log" # 腳本執(zhí)行日志# code env 代碼變量 CODE_DIR="/deploy/code/deploy" # 代碼目錄 CONFIG_DIR="/deploy/config" # 配置文件目錄 TMP_DIR="/deploy/tmp" # 臨時(shí)目錄 TAR_DIR="/deploy/tar" # 打包目錄 LOCK_FILE="/tmp/deploy.lock" # 鎖文件標(biāo)示# 使用幫助函數(shù) usage(){ echo $"Usage: $0 [ deploy | rollback ]" }shell_lock(){touch ${LOCK_FILE} }shell_unlock(){rm -f ${LOCK_FILE} }code_get(){echo "code_get"sleep 60 }code_build(){echo "code_build" }code_config(){echo "code_config" }code_tar(){echo "code_tar" }code_scp(){echo "code_scp" }cluster_node_remove(){echo "cluster_node_remove" }code_deploy(){echo "code_deploy" }config_diff(){echo "config_diff" }code_test(){echo "code_test" }cluster_node_in(){echo "cluste_node_in" }rollback(){echo "rollback" }# 主函數(shù) main(){ if [ -f $LOCK_FILE ];then # 先判斷鎖文件在不在echo "Deploy is running" && exit 10; # 如果有鎖文件直接退出fi DEPLOY_METHOD=$1 # 避免出錯(cuò)誤將腳本的第一個(gè)參數(shù)作為變量case $DEPLOY_METHOD indeploy) # 如果第一個(gè)參數(shù)是deploy就執(zhí)行以下操作shell_lock; # 執(zhí)行部署之前創(chuàng)建鎖,如果同時(shí)有其他人執(zhí)行則提示鎖文件存在避免沖突code_get;code_build;code_config;code_tar;code_scp;cluster_node_remove;code_deploy;config_diff;code_test;cluster_node_in;shell_unlock;;;rollback) # 如果第一個(gè)參數(shù)是rollback就執(zhí)行以下操作shell_lock; # 回滾之前也是先創(chuàng)建鎖文件rollback; # 執(zhí)行完成刪除鎖文件shell_unlock;;;*) # 其他輸入執(zhí)行以下操作usage;esac } # 執(zhí)行主函數(shù)并把第一個(gè)變量當(dāng)參數(shù) main $1

?

2.2.2:完成腳本:實(shí)現(xiàn)代碼部署、測試、回滾等操作:

代碼回滾設(shè)計(jì):
正常回滾是回滾已經(jīng)在web服務(wù)器部署過的版本,因此就不需要獲取代碼打包和部署的過程了

列出回滾版本
將模板服務(wù)器移除集群
執(zhí)行回滾
重啟和測試
將模板服務(wù)器加入集群

#!/bin/bash#Dir List 部署節(jié)點(diǎn)(即部署節(jié)點(diǎn)需要做的操作) # mkdir -p /deploy/code/web-demo # mkdir -p /deploy/config/web-demo/base # mkdir -p /deploy/config/web-demo/other # mkdir /deploy/tmp # mkdir /deploy/tar# chown -R www.www /deploy # chown -R www.www /webroot # chown -R www.www /opt/webroot/ # chown -R www.www /webroot# 需要在客戶端節(jié)點(diǎn)做的操作 # mkdir /opt/webroot # mkdir /webroot # chown -R www.www /webroot # chown -R www.www /opt/webroot/ # chown -R www.www /webroot # [www@ ~]$ touch /webroot/web-dem# Node List 服務(wù)器節(jié)點(diǎn) PRE_LIST="192.168.3.12" # 預(yù)生產(chǎn)節(jié)點(diǎn) GROUP1_LIST="192.168.3.12 192.168.3.13" GROUP2_LIST="192.168.3.13" ROLLBACK_LIST="192.168.3.12 192.168.3.13"# 日志日期和時(shí)間變量 LOG_DATE='date "+%Y-%m-%d"' # 如果執(zhí)行的話后面執(zhí)行的時(shí)間,此時(shí)間是不固定的,這是記錄日志使用的時(shí)間 LOG_TIME='date "+%H-%M-%S"'# 代碼打包時(shí)間變量 CDATE=$(date "+%Y-%m-%d") # 腳本一旦執(zhí)行就會(huì)取一個(gè)固定時(shí)間賦值給變量,此時(shí)間是固定的 CTIME=$(date +"%H-%M-%S")# shell env 腳本位置等變量 SHELL_NAME="deploy.sh" # 腳本名稱 SHELL_DIR="/home/www/" # 腳本路徑 SHELL_LOG="${SHELL_DIR}/${SHELL_NAME}.log" # 腳本執(zhí)行日志文件路徑# code env 代碼變量 PRO_NAME="web-demo" # 項(xiàng)目名稱的函數(shù) CODE_DIR="/deploy/code/web-demo" # 從版本管理系統(tǒng)更新的代碼目錄 CONFIG_DIR="/deploy/config/web-demo" # 保存不同項(xiàng)目的配置文件,一個(gè)目錄里面就是一個(gè)項(xiàng)目的一個(gè)配置文件或多個(gè)配置文件 TMP_DIR="/deploy/tmp" # 臨時(shí)目錄 TAR_DIR="/deploy/tar" # 打包目錄 LOCK_FILE="/tmp/deploy.lock" # 鎖文件路徑usage(){ # 使用幫助函數(shù)echo $"Usage: $0 [ deploy | rollback [ list | version ]" }writelog(){ # 寫入日志的函數(shù)LOGINFO=$1 # 將參數(shù)作為日志輸入echo "${CDATE} ${CTIME} : ${SEHLL_NAME} : ${LOGINFO}" >> ${SHELL_LOG} }# 鎖函數(shù) shell_lock(){touch ${LOCK_FILE} }# 解鎖函數(shù) shell_unlock(){rm -f ${LOCK_FILE} }# 獲取代碼的函數(shù) code_get(){echo "code_get"writelog code_getcd $CODE_DIR && echo "git pull" # 進(jìn)入到代碼目錄更新代碼,此處必須免密碼更新,此目錄僅用于代碼更新不能放其他任何文件cp -rf ${CODE_DIR} ${TMP_DIR}/ # 臨時(shí)保存代碼并重命名,包名為時(shí)間+版本號,準(zhǔn)備復(fù)制到web服務(wù)器API_VER="123" # 版本號 }code_build(){ # 代碼編譯函數(shù)echo code_build }code_config(){ # 配置文件函數(shù)writelog code_config/bin/cp -rf ${CONFIG_DIR}/base/* ${TMP_DIR}/"${PRO_NAME}" # 將配置文件放在本機(jī)保存配置文件的臨時(shí)目錄,用于暫時(shí)保存代碼項(xiàng)目PKG_NAME="${PRO_NAME}"_"$API_VER"_"${CDATE}-${CTIME}" # 定義代碼目錄名稱cd ${TMP_DIR} && mv ${PRO_NAME} ${PKG_NAME} # 重命名代碼文件為web-demo_123-20170629-11-19-10格式}code_tar(){ # 對代碼打包函數(shù)writelog code_tarcd ${TMP_DIR} && tar czf ${PKG_NAME}.tar.gz ${PKG_NAME}writelog "${PKG_NAME}.tar.gz" }code_scp(){ # 代碼壓縮包scp到客戶端的函數(shù)writelog "code_scp"for node in $PRE_LIST;do # 循環(huán)服務(wù)器節(jié)點(diǎn)列表scp ${TMP_DIR}/${PKG_NAME}.tar.gz $node:/opt/webroot/ # 將壓縮后的代碼包復(fù)制到web服務(wù)器的/opt/webrootdonefor node in $GROUP1_LIST;do # 循環(huán)服務(wù)器節(jié)點(diǎn)列表scp ${TMP_DIR}/${PKG_NAME}.tar.gz $node:/opt/webroot/ # 將壓縮后的代碼包復(fù)制到web服務(wù)器的/opt/webrootdone }url_test(){URL=$1curl -s --head $URL |grep '200 OK'if [ $? -ne 0 ];thenshell_unlock;writelog "test error" && exit;fi }cluster_node_add(){ #將web服務(wù)器添加至前端負(fù)載echo cluster_node_add }cluster_node_remove(){ # 將web服務(wù)器從集群移除函數(shù)(正在部署的時(shí)候應(yīng)該不處理業(yè)務(wù))writelog "cluster_node_remove" }pre_deploy(){writelog "pre_deploy"for node in ${PRE_LIST};do # 循環(huán)預(yù)生產(chǎn)服務(wù)器節(jié)點(diǎn)列表cluster_node_remove ${node} # 部署之前將節(jié)點(diǎn)從前端負(fù)載刪除echo "pre_deploy, cluster_node_remove ${node}"ssh ${node} "cd /opt/webroot && tar zxf ${PKG_NAME}.tar.gz" #分別到web服務(wù)器執(zhí)行壓縮包解壓命令ssh ${node} "rm -f /webroot/web-demo && ln -s /opt/webroot/${PKG_NAME} /webroot/web-demo" # 整個(gè)自動(dòng)化的核心,創(chuàng)建軟連接done }pre_test(){ # 預(yù)生產(chǎn)主機(jī)測試函數(shù)for node in ${PRE_LIST};do # 循環(huán)預(yù)生產(chǎn)主機(jī)列表curl -s --head http://${node}:9999/index.html | grep "200 OK" # 測試web界面訪問if [ $? -eq 0 ];then # 如果訪問成功writelog " ${node} Web Test OK!" # 記錄日志echo " ${node} Web Test OK!"cluster_node_add ${node} # 測試成功之后調(diào)用添加函數(shù)把服務(wù)器添加至節(jié)點(diǎn),writelog "pre,${node} add to cluster OK!" # 記錄添加服務(wù)器到集群的日志else # 如果訪問失敗writelog "${node} test no OK" # 記錄日志echo "${node} test not OK"shell_unlock # 調(diào)用刪除鎖文件函數(shù)break # 結(jié)束部署fidone}group1_deploy(){ # 代碼解壓部署函數(shù)writelog "group1_code_deploy"for node in ${GROUP1_LIST};do # 循環(huán)生產(chǎn)服務(wù)器節(jié)點(diǎn)列表cluster_node_remove $node echo "group1, cluster_node_remove $node"ssh ${node} "cd /opt/webroot && tar zxf ${PKG_NAME}.tar.gz" # 分別到各web服務(wù)器節(jié)點(diǎn)執(zhí)行壓縮包解壓命令ssh ${node} "rm -f /webroot/web-demo && ln -s /opt/webroot/${PKG_NAME} /webroot/web-demo" # 整個(gè)自動(dòng)化的核心,創(chuàng)建軟連接donescp ${CONFIG_DIR}/other/192.168.3.13.server.xml 192.168.3.13:/webroot/web-demo/server.xml # 將差異項(xiàng)目的配置文件scp到此web服務(wù)器并以項(xiàng)目結(jié)尾 } group1_test(){ # 生產(chǎn)主機(jī)測試函數(shù)for node in ${PRE_LIST};do # 循環(huán)生產(chǎn)主機(jī)列表curl -s --head http://${node}:9999/index.html | grep "200 OK" #測試web界面訪問if [ $? -eq 0 ];then #如果訪問成功writelog " ${node} Web Test OK!" #記錄日志echo "group1_test,${node} Web Test OK!"cluster_node_addwritelog " ${node} add to cluster OK!" #記錄將服務(wù)器 添加至集群的日志else #如果訪問失敗writelog "${node} test no OK" #記錄日志echo "${node} test no OK"shell_unlock # 調(diào)用刪除鎖文件函數(shù)break # 結(jié)束部署fidone }rollback_fun(){ for node in $ROLLBACK_LIST;do # 循環(huán)服務(wù)器節(jié)點(diǎn)列表# 注意一定要加"號,否則無法在遠(yuǎn)程執(zhí)行命令ssh $node "rm -f /webroot/web-demo && ln -s /opt/webroot/$1 /webroot/web-demo" # 立即回滾到指定的版本,$1即指定的版本參數(shù)echo "${node} rollback success!"done }rollback(){ # 代碼回滾主函數(shù)if [ -z $1 ];thenshell_unlock # 刪除鎖文件echo "Please input rollback version" && exit 3;ficase $1 in # 把第二個(gè)參數(shù)做當(dāng)自己的第一個(gè)參數(shù) list)ls -l /opt/webroot/*.tar.gz;;*)rollback_fun $1esac}main(){if [ -f $LOCK_FILE ] ;then # 先判斷鎖文件在不在,如果有鎖文件直接退出echo "Deploy is running" && exit 10fiDEPLOY_METHOD=$1 # 避免出錯(cuò)誤將腳本的第一個(gè)參數(shù)作為變量ROLLBACK_VER=$2case $DEPLOY_METHOD indeploy) # 如果第一個(gè)參數(shù)是deploy就執(zhí)行以下操作shell_lock; # 執(zhí)行部署之前創(chuàng)建鎖。如果同時(shí)有其他人執(zhí)行則提示鎖文件存在code_get; # 獲取代碼code_build; # 如果要編譯執(zhí)行編譯函數(shù)code_config; # cp配置文件code_tar; # 打包c(diǎn)ode_scp; # scp到服務(wù)器pre_deploy; # 預(yù)生產(chǎn)環(huán)境部署pre_test; # 預(yù)生產(chǎn)環(huán)境測試group1_deploy; # 生產(chǎn)環(huán)境部署group1_test; # 生產(chǎn)環(huán)境測試shell_unlock; # 執(zhí)行完成后刪除鎖文件;;rollback) # 如果第一個(gè)參數(shù)是rollback就執(zhí)行以下操作shell_lock; # 回滾之前也是先創(chuàng)建鎖文件rollback $ROLLBACK_VER;shell_unlock; # 執(zhí)行完成刪除鎖文件;;*)usage;esac } main $1 $2

?

3.通過剛才編寫的shell腳本將html官網(wǎng)頁面部署到nginx中

①將代碼上傳到部署節(jié)點(diǎn)的/deploy/code/web-demo目錄中

[www@master web-demo]$ pwd /deploy/code/web-demo [www@master web-demo]$ ll total 20 drwxr-xr-x 6 www www 4096 Jun 6 13:46 assets -rw-r--r-- 1 www www 1150 Jun 6 17:59 favicon.ico drwxr-xr-x 2 www www 4096 Jun 6 15:32 images -rw-r--r-- 1 www www 4323 Jun 6 16:19 index.html

?

部署節(jié)點(diǎn)執(zhí)行以下操作:

# mkdir -p /deploy/code/web-demo # mkdir -p /deploy/config/web-demo/base # mkdir -p /deploy/config/web-demo/other # mkdir /deploy/tmp # mkdir /deploy/tar# chown -R www.www /deploy # chown -R www.www /webroot # chown -R www.www /opt/webroot/

?

②需要在客戶端做的操作
# 安裝nginx
# yum install -y nginx

編輯nginx

vim /etc/nginx/conf.d/cloudeye.confserver {listen 9999;server_name 192.168.3.13; # 實(shí)際生產(chǎn)環(huán)境中需要填寫域名location / {alias /webroot/web-demo/; # 這個(gè)web-demo目錄不需要?jiǎng)?chuàng)建,有軟鏈接指向/webroot/web-demo目錄index index.html;} }

?

創(chuàng)建相關(guān)目錄并修改權(quán)限

mkdir /opt/webroot mkdir /webroot chown -R www.www /webroot chown -R www.www /opt/webroot/ [www@ ~]$ touch /webroot/web-demo

?

③執(zhí)行腳本
測試部署:

[www@master ~]$ ./deploy.sh deploy code_get git pull code_build web-demo_123_2017-06-26-12-18-09.tar.gz 100% 1214KB 1.2MB/s 00:00 web-demo_123_2017-06-26-12-18-09.tar.gz 100% 1214KB 1.2MB/s 00:00 web-demo_123_2017-06-26-12-18-09.tar.gz 100% 1214KB 1.2MB/s 00:00 pre_deploy, cluster_node_remove 192.168.3.12 HTTP/1.1 200 OK 192.168.3.12 Web Test OK! cluster_node_add group1, cluster_node_remove 192.168.3.12 group1, cluster_node_remove 192.168.3.13 /deploy/config/web-demo/other/192.168.3.13.server.xml: No such file or directory HTTP/1.1 200 OK group1_test,192.168.3.12 Web Test OK! cluster_node_add

?

訪問客戶端,可以看到能夠正常訪問,說明部署成功
http://192.168.3.13:9999

修改代碼,測試回滾效果

[www@master ~]$ vim /deploy/code/web-demo/index.html [www@master ~]$ ./deploy.sh deploy code_get git pull code_build web-demo_123_2017-06-26-12-18-57.tar.gz 100% 1214KB 1.2MB/s 00:00 web-demo_123_2017-06-26-12-18-57.tar.gz 100% 1214KB 1.2MB/s 00:00 web-demo_123_2017-06-26-12-18-57.tar.gz 100% 1214KB 1.2MB/s 00:00 pre_deploy, cluster_node_remove 192.168.3.12 HTTP/1.1 200 OK 192.168.3.12 Web Test OK! cluster_node_add group1, cluster_node_remove 192.168.3.12 group1, cluster_node_remove 192.168.3.13 /deploy/config/web-demo/other/192.168.3.13.server.xml: No such file or directory HTTP/1.1 200 OK group1_test,192.168.3.12 Web Test OK! cluster_node_add[www@master ~]$ ./deploy.sh rollback list -rw-rw-r-- 1 www www 1243347 Jun 26 11:36 /opt/webroot/web-demo_123_2017-06-26-11-36-44.tar.gz -rw-rw-r-- 1 www www 1243347 Jun 26 11:39 /opt/webroot/web-demo_123_2017-06-26-11-39-02.tar.gz -rw-rw-r-- 1 www www 1243351 Jun 26 12:04 /opt/webroot/web-demo_123_2017-06-26-12-04-19.tar.gz -rw-rw-r-- 1 www www 1243347 Jun 26 12:16 /opt/webroot/web-demo_123_2017-06-26-12-16-49.tar.gz -rw-rw-r-- 1 www www 1243347 Jun 26 12:18 /opt/webroot/web-demo_123_2017-06-26-12-18-09.tar.gz -rw-rw-r-- 1 www www 1243369 Jun 26 12:18 /opt/webroot/web-demo_123_2017-06-26-12-18-57.tar.gz

?修改部署成功頁面

測試回滾,頁面再次回到修改前,說明回滾成功

[www@master ~]$ ./deploy.sh rollback web-demo_123_2017-06-26-12-18-09 192.168.3.12 rollback success! 192.168.3.13 rollback success!

?

轉(zhuǎn)載于:https://www.cnblogs.com/reblue520/p/7110213.html

總結(jié)

以上是生活随笔為你收集整理的运维与自动化系列③自动化部署基础与shell脚本实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。