后端結(jié)構(gòu):
公司后端采用了Kubernetes+OpenFaaS+Flask的架構(gòu)。openfaas提供FaaS服務(wù)。每一個flask項目具體到一個function中,一個function部署在一個docker容器中,各function之間相互獨立,保證每個后端在操作同一個工作項目時邏輯的獨立性。
腳本應(yīng)用場景:
部署腳本需求的必要性:
- openfaas的部署需要自動生成yml文件
- 實際部署階段需要區(qū)分生產(chǎn)環(huán)境(dev開發(fā),stage預(yù)發(fā)布,prod正式,test測試)
- yml的生成結(jié)果需要動態(tài)化,如后端每一個項目都不一樣,一個項目相當(dāng)于一個faas function,因此function_name每個人必然是不一樣的。
代碼實現(xiàn):
里面一些比較重要的文件:
- template.yml:OpenFaaS Function部署的模板yml,需要手動修改,這里要通過腳本自動化這個流程
- $0:即當(dāng)前要執(zhí)行的腳本名稱,可以是"deploy.sh"
- deploy.yml:修改模板得到的yml,用于OpenFaas的部署
- 變量env:控制部署的環(huán)境
具體的腳本解讀請看代碼注釋。
// 具體名稱已隱去
"deploy.sh"
#!/usr/bin/env bash
#function_basename=$(basename `pwd`)
function_basename="xx" # function name,即openfaas function的名稱,項目名稱
env=$1 # 需要部署的環(huán)境的名稱,$1即為后面第一位輸入的參數(shù)
option=$2 # 執(zhí)行的操作,如deploy為部署
# 前幾行定義了整個腳本的操作,如 sh deploy.sh dev deploy,表明這個操作可以自動化整個項目到dev開發(fā)環(huán)境的部署
# 分配faas_gateway(openfaas的具體路由)
# 在使用變量時,如果不修改操作,調(diào)用變量需要加${env}
# 大括號的作用是隔離,如${A}B和$AB是完全不一樣的含義。
# 定義了-h/--help的含義,一個instructions,為操作全過程的介紹。
case ${env} in
dev|test)
faas_gateway="xx1"
faas_gateway_="xx2"
;;
prod|stage)
faas_gateway="xx3"
faas_gateway_="xx4"
;;
*|-h|--help)
echo "$0:usage: [ test ] | [ prod ] | [ dev ] | [ stage ] \n"
echo "Env:"
echo "\ttest Testing Env"
echo "\tprod Prod Env"
echo "\tdev Dev Env"
echo "\tstage Stage Env\n"
echo "Available Commands:"
echo "\tbuild Builds OpenFaaS function containers"
echo "\tdeploy Deploy OpenFaaS functions"
echo "Examples:"
echo "\tsh deploy.sh test [ build | deploy ]"
echo "\tsh deploy.sh prod [ build | deploy ]"
echo "\tsh deploy.sh dev [ build | deploy ]"
echo "\tsh deploy.sh stage [ build | deploy ]\n"
echo "Use \"sh $0 -h\" for more information about a command."
exit 1
;;
esac
# if [ -f "..." ]; 意為檢查引號內(nèi)文件是否存在,如果存在執(zhí)行步驟,不存在執(zhí)行另一步驟
if [ -f "./template.yml" ];then
echo "template.yml exists."
else
# 重定向內(nèi)容,cat << EOF ... EOF會將EOF開始和結(jié)束中間的內(nèi)容作為輸入
# 再通過">"將內(nèi)容重定向到template.yml
# 這里的含義就是判斷如果這個template模板不存在,創(chuàng)建一個
cat > template.yml <<EOF
provider:
name: faas
gateway: faas_gateway
functions:
function_name:
lang: xx
handler: ./function
image: xx.cn/xx/docker_name:version
EOF
fi
#faas template pull git@xx.cn/xx/xx.git --overwrite
# 默認(rèn)不使用,公司后端統(tǒng)一模板,配置了orm,dockerfile,flask配置等
# faas template pull 即拉git上的模板,業(yè)務(wù)相關(guān),可忽略
# Dockerfile默認(rèn)在template業(yè)務(wù)模板中有,但每個項目都可能定制化Dockerfile
# 這里操作就是如果自定義Dockerfile,放到指定文件夾中,并覆蓋原模板的Dockerfile
# 放到指定目錄的原因就是在git中你可以看到這個目錄,提醒其他人Dockerfile是定制的
if [ -f "./function/extra/Dockerfile" ];then
cp -rf ./function/extra/Dockerfile ./template/python3-flask/
fi
# run.sh同理,此為業(yè)務(wù)中腳本,可忽略
if [ -f "./function/extra/run.sh" ];then
cp -rf ./function/extra/run.sh ./template/python3-flask/
fi
# commit_id為設(shè)計的Docker tag,采用當(dāng)前時間動態(tài)獲取
# 這種tag必然是不會重復(fù)的
commit_id=$(date "+%Y%m%d%H%M%S")
# new_version是當(dāng)前要部署的版本
new_version=$commit_id
echo version: $new_version-$env
# docker name即name:tag中的name,部署到私有hub上的鏡像name
docker_name=$function_basename
function_name=$function_basename
# 為openfaas的項目function起名,除了正式環(huán)境,其他都要帶上環(huán)境變量名
# 如dev-function..../stage-function...
if [ "$env" != "prod" ];then
function_name=$env-$function_basename
fi
# 重要步驟,將template.yml模板指定內(nèi)容替換
# template.yml的固定部分:faas_gateway,funtion_name,docker_name,version
# sed不重定向不會修改原yml的內(nèi)容,用指定變量替換相應(yīng)字符串位置
sed -e "s/version/$new_version/g;s/function_name/$function_name/g;s/faas_gateway/$faas_gateway_/g;s/docker_name/$docker_name/g" template.yml > deploy.yml
# faas cli 操作 u/p登錄
faas-cli login -g $faas_gateway -u xx --password 'xx'
# option如果是build,用Dockerfile去build,但并不deploy
if [ "$option" = "build" ];then
function_name=$env-$function_name
fi
faas-cli build -f deploy.yml --build-arg FLASK_ENV=$env
faas-cli push -f deploy.yml
echo "Version:$new_version"
if [ "$option" = "deploy" ];then
faas-cli deploy -f deploy.yml
echo '======deploy success======'
echo [function]: $function_name
echo [version ]: $new_version
echo [image ]: xx.cn/xx/$docker_name:$new_version
echo '=========================='
echo ' '
else
echo '======build success======'
echo [function]: $function_name
echo [version ]: $new_version
echo [image ]: xx.cn/xx/$docker_name:$new_version
echo '========================='
echo ' '
fi
# build完后,項目代碼中刪除build目錄,本地并不需要
rm -rf ./build
以上是一些自動化部署問題的小思考~
如果架構(gòu)不同,也可以參考一下其中的動態(tài)修改,用于自己的項目中,尤其是時間代替tag等這樣的做法,可以使你實現(xiàn)一行命令完成部署的要求。