自动化部署基础与shell脚本实现

关于自动化的基础知识:

1.1:当前代码部署的实现方式:

运维纯手工scp到web服务器
纯手工登录git服务器执行git pull或svn服务器执行svn update更新代码
通过xftp上传代码
开发打压缩包上传到服务器然后解压

缺点:
1.需要运维全程参与,占用大量的工作时间
2.上线时间比较慢
3.人为造成的失误较多,管理比较混乱
4.回滚复杂而且慢,还不及时

1.2:运行环境规划:
开发环境:开发者本地有自己的环境,然后运维需要设置开发环境的公用服务,例如开发数据库、redis、memcached等
测试环境:功能测试环境和性能测试环境
预生产环境:由生产环境集群中的某一个节点担任测试,此节点只做测试不对外提供服务
生产环境:直接对外提供服务的环境

为什么有预生产环境?
可能是生产环境预测试环境的数据库或数据库版本不一样导致语句出现问题
或者是生产环境调用的接口不一样,例如支付接口在测试环境无法调用

1.3:设计一套生产环境的代码自动化部署系统:

开发环境 --> 功能测试/性能测试 --> 预生产环境 --> 生产环境

1.4:总体规划流程:
一个服务的集群节点数量,是一次部署还是分次部署
一键回滚到上个版本
一键回滚到任意版本
代码保存在SVN还是Git
获取指定分支或master的指定版本号的代码,svn指定版本号,git指定tag标签,或直接拉取某个分支
配置文件差异化,即测试环境和生产环境的配置文件不一样,如IP不一样或主机名不一样或数据库连接不一样等等
代码仓库和实际的差异,即配置文件是否放在代码仓库中,如果保存在git则所有人都可以从配置文件看到数据库用户密码等信息,可以使用单独分支保存配置文件,或配置文件只在部署服务器的某个项目的目录,比如是config.example
如何更新代码,java tomcat需要重启
测试部署后的web页面是否可以正常访问是否是想要的页面
并行(saltstack)或并行(shell)的问题,涉及到分组部署重启服务
如何执行,shell执行还是web执行

1.5:总体规划如下:

获取代码(git pull拉取) --> 是否编译(java需要编译) --> 配置文件(统一和差异) --> 打包 --> scp到目标服务器(或者用saltstack) --> 将服务器移除集群 --> 解压代码包 --> 放置到目标目录(如webroot) --> scp差异文件 --> 重启服务(可选) --> 测试服务(访问web或者post请求) --> 将节点重新加入集群

二:实现代码自动化部署

2.1:通过shell脚本实现,shell脚本规划如下:

2.1.1:各web服务器添加一个uid相同的普通用户,而且所有的web服务都以此普通用户启动,默认情况下所有的wenb服务除了负载均衡之外都不能监听80端口,比如可以监听8008端口

2.1.2:部署服务器的用户登录其他服务器免密码登录,因此需要做秘钥认证,在各主机执行以下命令:

# useradd www -u 1010
# su – www
$ ssh-keygen
#将部署机www用户的公钥复制到各web服务器的 /home/www/.ssh/authorized_keys或执行ssh-copy-id www@192.168.3.13

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

2.1.3:测试部署服务器是否可以免秘钥用www用户登录各个web服务器

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"    # 脚本执行日志# code env 代码变量
CODE_DIR="/deploy/code/deploy"    # 代码目录
CONFIG_DIR="/deploy/config"    # 配置文件目录
TMP_DIR="/deploy/tmp"        # 临时目录
TAR_DIR="/deploy/tar"        # 打包目录
LOCK_FILE="/tmp/deploy.lock"    # 锁文件标示# 使用帮助函数
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"
}# 主函数
main(){    if [ -f $LOCK_FILE ];then    # 先判断锁文件在不在echo "Deploy is running" && exit 10;     # 如果有锁文件直接退出fi DEPLOY_METHOD=$1    # 避免出错误将脚本的第一个参数作为变量case $DEPLOY_METHOD indeploy)        # 如果第一个参数是deploy就执行以下操作shell_lock;    # 执行部署之前创建锁,如果同时有其他人执行则提示锁文件存在避免冲突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)    # 如果第一个参数是rollback就执行以下操作shell_lock;    # 回滚之前也是先创建锁文件rollback;    # 执行完成删除锁文件shell_unlock;;;*)    # 其他输入执行以下操作usage;esac
}
# 执行主函数并把第一个变量当参数
main $1

2.2.2:完成脚本:实现代码部署、测试、回滚等操作:

代码回滚设计:
正常回滚是回滚已经在web服务器部署过的版本,因此就不需要获取代码打包和部署的过程了

列出回滚版本
将模板服务器移除集群
执行回滚
重启和测试
将模板服务器加入集群

#!/bin/bash#Dir List 部署节点(即部署节点需要做的操作)
# 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# 需要在客户端节点做的操作
# 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 服务器节点
PRE_LIST="192.168.3.12"        # 预生产节点
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"# 日志日期和时间变量
LOG_DATE='date "+%Y-%m-%d"' # 如果执行的话后面执行的时间,此时间是不固定的,这是记录日志使用的时间
LOG_TIME='date "+%H-%M-%S"'# 代码打包时间变量
CDATE=$(date "+%Y-%m-%d") # 脚本一旦执行就会取一个固定时间赋值给变量,此时间是固定的
CTIME=$(date +"%H-%M-%S")# shell env 脚本位置等变量
SHELL_NAME="deploy.sh"    # 脚本名称
SHELL_DIR="/home/www/"  # 脚本路径
SHELL_LOG="${SHELL_DIR}/${SHELL_NAME}.log" # 脚本执行日志文件路径# code env 代码变量
PRO_NAME="web-demo"    # 项目名称的函数
CODE_DIR="/deploy/code/web-demo"    # 从版本管理系统更新的代码目录
CONFIG_DIR="/deploy/config/web-demo"    # 保存不同项目的配置文件,一个目录里面就是一个项目的一个配置文件或多个配置文件
TMP_DIR="/deploy/tmp"            # 临时目录
TAR_DIR="/deploy/tar"            # 打包目录
LOCK_FILE="/tmp/deploy.lock" # 锁文件路径usage(){ # 使用帮助函数echo $"Usage: $0 [ deploy | rollback [ list | version ]"
}writelog(){ # 写入日志的函数LOGINFO=$1 # 将参数作为日志输入echo "${CDATE} ${CTIME} : ${SEHLL_NAME} : ${LOGINFO}" >> ${SHELL_LOG}
}# 锁函数
shell_lock(){touch ${LOCK_FILE}
}# 解锁函数
shell_unlock(){rm -f ${LOCK_FILE}
}# 获取代码的函数
code_get(){echo "code_get"writelog code_getcd $CODE_DIR && echo "git pull" # 进入到代码目录更新代码,此处必须免密码更新,此目录仅用于代码更新不能放其他任何文件cp -rf ${CODE_DIR} ${TMP_DIR}/ # 临时保存代码并重命名,包名为时间+版本号,准备复制到web服务器API_VER="123"  # 版本号
}code_build(){ # 代码编译函数echo code_build
}code_config(){ # 配置文件函数writelog code_config/bin/cp -rf ${CONFIG_DIR}/base/* ${TMP_DIR}/"${PRO_NAME}" # 将配置文件放在本机保存配置文件的临时目录,用于暂时保存代码项目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(){    # 对代码打包函数writelog code_tarcd ${TMP_DIR} && tar czf ${PKG_NAME}.tar.gz ${PKG_NAME}writelog "${PKG_NAME}.tar.gz"
}code_scp(){ # 代码压缩包scp到客户端的函数writelog  "code_scp"for node in $PRE_LIST;do # 循环服务器节点列表scp ${TMP_DIR}/${PKG_NAME}.tar.gz $node:/opt/webroot/ # 将压缩后的代码包复制到web服务器的/opt/webrootdonefor node in $GROUP1_LIST;do # 循环服务器节点列表scp ${TMP_DIR}/${PKG_NAME}.tar.gz $node:/opt/webroot/ # 将压缩后的代码包复制到web服务器的/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服务器添加至前端负载echo cluster_node_add
}cluster_node_remove(){ # 将web服务器从集群移除函数(正在部署的时候应该不处理业务)writelog "cluster_node_remove"
}pre_deploy(){writelog "pre_deploy"for node in ${PRE_LIST};do # 循环预生产服务器节点列表cluster_node_remove  ${node} # 部署之前将节点从前端负载删除echo  "pre_deploy, cluster_node_remove ${node}"ssh ${node} "cd /opt/webroot && tar zxf ${PKG_NAME}.tar.gz" #分别到web服务器执行压缩包解压命令ssh ${node} "rm -f /webroot/web-demo && ln -s /opt/webroot/${PKG_NAME} /webroot/web-demo" # 整个自动化的核心,创建软连接done
}pre_test(){ # 预生产主机测试函数for node in ${PRE_LIST};do # 循环预生产主机列表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} # 测试成功之后调用添加函数把服务器添加至节点,writelog "pre,${node} add to cluster OK!" # 记录添加服务器到集群的日志else # 如果访问失败writelog "${node} test no OK" # 记录日志echo "${node} test not OK"shell_unlock # 调用删除锁文件函数break # 结束部署fidone}group1_deploy(){ # 代码解压部署函数writelog "group1_code_deploy"for node in ${GROUP1_LIST};do # 循环生产服务器节点列表cluster_node_remove $node  echo "group1, cluster_node_remove $node"ssh ${node} "cd /opt/webroot && tar zxf ${PKG_NAME}.tar.gz" # 分别到各web服务器节点执行压缩包解压命令ssh ${node} "rm -f /webroot/web-demo && ln -s /opt/webroot/${PKG_NAME} /webroot/web-demo" # 整个自动化的核心,创建软连接donescp ${CONFIG_DIR}/other/192.168.3.13.server.xml 192.168.3.13:/webroot/web-demo/server.xml  # 将差异项目的配置文件scp到此web服务器并以项目结尾
}    group1_test(){ # 生产主机测试函数for node in ${PRE_LIST};do # 循环生产主机列表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!" #记录将服务器 添加至集群的日志else #如果访问失败writelog "${node} test no OK" #记录日志echo "${node} test no OK"shell_unlock # 调用删除锁文件函数break # 结束部署fidone
}rollback_fun(){ for node in $ROLLBACK_LIST;do # 循环服务器节点列表# 注意一定要加"号,否则无法在远程执行命令ssh $node "rm -f /webroot/web-demo && ln -s /opt/webroot/$1 /webroot/web-demo" # 立即回滚到指定的版本,$1即指定的版本参数echo "${node} rollback success!"done
}rollback(){ # 代码回滚主函数if [ -z $1 ];thenshell_unlock # 删除锁文件echo "Please input rollback version" && exit 3;ficase $1 in # 把第二个参数做当自己的第一个参数 list)ls -l /opt/webroot/*.tar.gz;;*)rollback_fun $1esac}main(){if [ -f $LOCK_FILE ] ;then # 先判断锁文件在不在,如果有锁文件直接退出echo "Deploy is running" && exit 10fiDEPLOY_METHOD=$1 # 避免出错误将脚本的第一个参数作为变量ROLLBACK_VER=$2case $DEPLOY_METHOD indeploy) # 如果第一个参数是deploy就执行以下操作shell_lock; # 执行部署之前创建锁。如果同时有其他人执行则提示锁文件存在code_get; # 获取代码code_build; # 如果要编译执行编译函数code_config; # cp配置文件code_tar;    # 打包code_scp;    # scp到服务器pre_deploy;  # 预生产环境部署pre_test;    # 预生产环境测试group1_deploy; # 生产环境部署group1_test;   # 生产环境测试shell_unlock; # 执行完成后删除锁文件;;rollback) # 如果第一个参数是rollback就执行以下操作shell_lock; # 回滚之前也是先创建锁文件rollback $ROLLBACK_VER;shell_unlock; # 执行完成删除锁文件;;*)usage;esac
}
main $1 $2

3.通过刚才编写的shell脚本将html官网页面部署到nginx中

①将代码上传到部署节点的/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

部署节点执行以下操作:

# 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; # 实际生产环境中需要填写域名location / {alias /webroot/web-demo/; # 这个web-demo目录不需要创建,有软链接指向/webroot/web-demo目录index index.html;}
}

创建相关目录并修改权限

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

③执行脚本
测试部署:

[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!

转载于:https://www.cnblogs.com/reblue520/p/7110213.html

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

  1. linux cc脚本,Linux运维知识之Linux简单处理CC攻击shell脚本

    本文主要向大家介绍了Linux运维知识之Linux简单处理CC攻击shell脚本,通过具体的内容向大家展现,希望对大家学习Linux运维知识有所帮助. 第一个脚本是通过查找日志中访问次数过多的ip,并 ...

  2. 【Python自动化运维】Python环境安装及基础语法

    [Python自动化运维]Python环境安装及基础语法 1. Python环境安装 2. Python基础语法 1. Python环境安装   pyenv官方安装手册:https://github. ...

  3. 运维转型之路—手工运维到无人值守的自动化运维,从根本实现降本增效

    运维伴随信息技术的发展而生,经历了从手工管理到工具化运维,发展至平台化运维,最终实现自动化.智能化运维的四个阶段. 图一:运维发展阶段及特点 在信息化发展初期,业务流量不大,服务器数量相对较少,系统复 ...

  4. 运维技能定级标准第4篇——关于运维工程师岗位的自动化运维与运维开发技能级别设计

    运维工程师岗位工作技能的评定类别(5)和(6) 5.自动化运维技术 级别0,什么都不懂 级别1,了解ansible.saltstack.puppet等主流的自动化运维管理技术工具,掌握公司主要使用的一 ...

  5. python executemany执行延迟_运维架构师-Python 自动化运维开发-031

    *运维架构师-Python 自动化运维开发-031 十九.Python3 操作数据库 1.Python3 操作 MySQL 1.基本介绍 Python3 操作 MySQL 数据库 可以使用的模块是 p ...

  6. python 自动运维架构师_运维架构师-Python 自动化运维开发-031

    *运维架构师-Python 自动化运维开发-031 十九.Python3 操作数据库 1.Python3 操作 MySQL 1.基本介绍Python3 操作 MySQL 数据库 可以使用的模块是 py ...

  7. 自动化运维(使用api自动化管理f5设备)

    自动化运维(使用api自动化管理f5设备) 前言 F5 的API接口 关于认证 利用python实现自动化巡检 成果 附录(f5 api reference) 前言 利用F5设备自带的API,通过py ...

  8. python cs架构 运维_运维架构师-Python 自动化运维开发-005

    *运维架构师-Python 自动化运维开发-005 四.Ipython 交互式解释器 1.Ipython 简介 IPython外加一个文本编辑器 Windows系统下是IPython加notepad+ ...

  9. python运维开发培训_运维架构师-Python 自动化运维开发-014

    运维架构师-Python 自动化运维开发-014 九.标准数据类型 1.为什么编程语言中要有类型 类型有以下几个重要角色:对机器而言,类型描述了内存中的电荷是怎么解释的. 对编译器或者解释器而言,类型 ...

最新文章

  1. 对python3中pathlib库的Path类的使用详解
  2. 装上螺旋桨,加州理工让只能行走的双足机器人「上了天」,还玩起了障碍滑板、走绳索...
  3. 深度学习在单图像超分辨率上的应用:SRCNN、Perceptual loss、SRResNet
  4. 命令模式——HeadFirst设计模式学习笔记
  5. QT的QHistoryState类的使用
  6. myabtis 数字+逗号 传参问题 $和#
  7. Python gensim库word2vec 基本用法
  8. HDU2012 素数判定
  9. 壹动官网上线新增产品【等保】
  10. 高级PHP应用程序漏洞审核技术
  11. 通过Memcached来实现对Tomcat集群中Session的共享策略
  12. Java与jar之间的区别
  13. OSChina 周二乱弹 ——人在职场飘,哪能不跳槽
  14. CRM八面体:客户关系管理成功案例2 Yorkshire Water
  15. 【校园网环境下知网研学下载文献出现“下载文献 当前IP没有获取权限或服务器异常”处理办法】
  16. markdown从VSCode中导出为PDF时字体格式问题
  17. springboot+vue+elementui社区公益志愿者服务网站java
  18. 网易校招编程题目之牛牛分苹果
  19. 宽带响应超时服务器无应答,宽带服务器无应答怎么办
  20. Cocos Creator 开发实战——篮球物理游戏

热门文章

  1. 用顺序栈实现十进制向二进制转化
  2. python图像插值
  3. 闭包(匿名函数) php
  4. JFreeChart使用
  5. html里调用css的语句
  6. 卖软件源码、解决技术难题、做生意,都需要讲个基本原则【No Money No Code】
  7. 为ASP.NET MVC扩展异步Action功能(下)
  8. musical.ly体验-这款国产外销的APP凭什么登上美国榜首?
  9. 征集活动 | PMCAFF八周年,十万产品经理送祝福
  10. 不服来战!这才是产品汪与程序猿撕逼的正确方式