后端结构:
公司后端采用了Kubernetes+OpenFaaS+Flask的架构。openfaas提供FaaS服务。每一个flask项目具体到一个function中,一个function部署在一个docker容器中,各function之间相互独立,保证每个后端在操作同一个工作项目时逻辑的独立性。
脚本应用场景:
部署脚本需求的必要性:
- openfaas的部署需要自动生成yml文件
- 实际部署阶段需要区分生产环境(dev开发,stage预发布,prod正式,test测试)
- yml的生成结果需要动态化,如后端每一个项目都不一样,一个项目相当于一个faas function,因此function_name每个人必然是不一样的。
代码实现:
里面一些比较重要的文件:
- template.yml:OpenFaaS Function部署的模板yml,需要手动修改,这里要通过脚本自动化这个流程
- $0:即当前要执行的脚本名称,可以是"deploy.sh"
- deploy.yml:修改模板得到的yml,用于OpenFaas的部署
- 变量env:控制部署的环境
具体的脚本解读请看代码注释。
// 具体名称已隐去
"deploy.sh"
#!/usr/bin/env bash
#function_basename=$(basename `pwd`)
function_basename="xx" # function name,即openfaas function的名称,项目名称
env=$1 # 需要部署的环境的名称,$1即为后面第一位输入的参数
option=$2 # 执行的操作,如deploy为部署
# 前几行定义了整个脚本的操作,如 sh deploy.sh dev deploy,表明这个操作可以自动化整个项目到dev开发环境的部署
# 分配faas_gateway(openfaas的具体路由)
# 在使用变量时,如果不修改操作,调用变量需要加${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 "..." ]; 意为检查引号内文件是否存在,如果存在执行步骤,不存在执行另一步骤
if [ -f "./template.yml" ];then
echo "template.yml exists."
else
# 重定向内容,cat << EOF ... EOF会将EOF开始和结束中间的内容作为输入
# 再通过">"将内容重定向到template.yml
# 这里的含义就是判断如果这个template模板不存在,创建一个
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
# 默认不使用,公司后端统一模板,配置了orm,dockerfile,flask配置等
# faas template pull 即拉git上的模板,业务相关,可忽略
# Dockerfile默认在template业务模板中有,但每个项目都可能定制化Dockerfile
# 这里操作就是如果自定义Dockerfile,放到指定文件夹中,并覆盖原模板的Dockerfile
# 放到指定目录的原因就是在git中你可以看到这个目录,提醒其他人Dockerfile是定制的
if [ -f "./function/extra/Dockerfile" ];then
cp -rf ./function/extra/Dockerfile ./template/python3-flask/
fi
# run.sh同理,此为业务中脚本,可忽略
if [ -f "./function/extra/run.sh" ];then
cp -rf ./function/extra/run.sh ./template/python3-flask/
fi
# commit_id为设计的Docker tag,采用当前时间动态获取
# 这种tag必然是不会重复的
commit_id=$(date "+%Y%m%d%H%M%S")
# new_version是当前要部署的版本
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起名,除了正式环境,其他都要带上环境变量名
# 如dev-function..../stage-function...
if [ "$env" != "prod" ];then
function_name=$env-$function_basename
fi
# 重要步骤,将template.yml模板指定内容替换
# template.yml的固定部分:faas_gateway,funtion_name,docker_name,version
# sed不重定向不会修改原yml的内容,用指定变量替换相应字符串位置
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
以上是一些自动化部署问题的小思考~
如果架构不同,也可以参考一下其中的动态修改,用于自己的项目中,尤其是时间代替tag等这样的做法,可以使你实现一行命令完成部署的要求。
网友评论