通过shell脚本实现代码自动化部署
通过shell脚本实现代码自动化部署
一、传统部署方式及优缺点
1.传统部署方式
(1)纯手工scp
(2)纯手工登录git pull、svn update
(3)纯手工xftp往上拉
(4)开发给打一个压缩包,rz上去;解压
2.缺点
(1)全程运维参与,占用大量时间
(2)上线速度慢
(3)人为失误多,管理混乱
(4)回滚慢,不及时
二、环境规划
1、开发环境--开发者本地有自己的环境。
运维需要设置的开发环境,大家共用的服务。
2、测试环境:功能测试环境和性能测试环境。
3、预生产环境:生产环境集群中的某一个节点。
4、生产环境:直接对用户提供服务的环境。
测试环境与生产环境的数据库不一致时,可能会导致测试的功能不全面,在测试环境测无问题,放在线上可能出现问题
三、需求分析
一、功能需求需求
一个集群有十个节点
1.实现 一键部署10个节点
2.一键回滚到任意版本
3.一键回滚到上个版本
二、部署需求
部署:
1.代码在哪里:svn、git
2.获取什么版本代码?
svn/git:直接拉去某个分支
svn:指定版本号
git:指定tag
3.差异解决:
(1)各个节点直接差异:配置文件未必一致(crontab.xml)。预生产节点。
(2)代码仓库和实际的差异。配置文件是否放在代码仓库中。
4.如何更新
更新时需要考虑是否重启。例如java代码,需要考虑重启tomcat。重启过程中,用户就不能访问了。
5.测试
部署多个节点,某个节点由于配置问题导致部署不成功。如何测试。
6.串行和并行
部署多个节点,串行部署还是并行部署,视具体业务需求决定。
7.如何执行
1.shell脚本,直接执行
2.web界面
三、部署流程
1.获取代码(直接拉取)----》 2.编译(可选)----》 3.配置文件放进去----》 4.打包 ----》
5.SCP到目标服务器----》 6.将目标服务器移除集群----》 7.解压 ----》 8.放置到webroot ----》
9.SCP差异文件 ----》 10.重启(可选) ----》 11.测试 ----》 12.加入集群
四、代码实现
1、设置无交互访问
通过ssh-keygen将部署机的公钥发送给应用服务器。
注意,这里通常是用普通用户登陆部署机,生成公钥后,再把公钥发给应用服务器
ssh-keygen -t rsa
切换到.ssh目录下
[www@linux-node1 ~/.ssh]$ ll
total 16
-rwx------ 1 www www 397 Jul 31 22:45 authorized_keys
-rwx------ 1 www www 1679 Jul 31 22:44 id_rsa
-rwx------ 1 www www 397 Jul 31 22:44 id_rsa.pub
将id_rsa.pub中的内容复制粘贴到应用服务器的www用户的.ssh目录下,
文件名称为authorized_keys
[www@linux-node2 .ssh]$ cat authorized_keys
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCqT3VwY9Wo7tKsXa4Ce1zXGLT/Iygy30tDBKnV4HW4g5BdUS48urTvYljL9cwJ/HWvoqbtJ5mc7PMmhDMOAjIh1CRZtGxKEkQFB/Xp5cLeAsE7iH+WfkNqavFHD75+YuM2mbNBvisDXO+/pJ/QfbmYwWJ6CW6uLpQKpitdJwrLpQDJGQv5H3aV0kHKZdoA+twdXm0LmQcWWJt7zruPq19CAXG5b93KTdgyt/1x4BfcT5/+PCaEd9suYwEneI2Io8CX9oTAe3MRyRPtlN0szT89qP/q+Q4sktVjc1nkxHhdP2mahqeiBLUGULfkgUBtEjaGAFSWb+ejFV0fRDHk6bSJ www@linux-node1
注意,修改authorized_keys的权限
chmod 600 authorized_keys
另外,将.ssh目录的权限设置成700
chmod 700 .ssh
2、详细代码
#!/bin/bash #Node List PRE_LIST="192.168.56.11" GROUP1_LIST="192.168.56.12" ROLLBACK_LIST="192.168.56.11 192.168.56.12" #Date/Time Variable 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="/deploy1.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=$ echo "${CDATE}${CTIME}: ${SHELL_NAME}: ${LOGINFO} " >> ${SHELL_LOG} } shell_lock(){ touch ${LOCK_FILE} } shell_unlock(){ rm -f ${LOCK_FILE} } code_get(){ writelog "code_get"; cd $CODE_DIR && echo "git pull"; cp -r ${CODE_DIR} ${TMP_DIR}/ API_VER="" } code_build(){ echo code_build } code_config(){ writelog "code_config" /bin/cp -r ${CONFIG_DIR}/base/* ${TMP_DIR}/"${PRO_NAME}" PKG_NAME="${PRO_NAME}"_"$API_VER"_"${CDATE}-${CTIME}" cd ${TMP_DIR} && mv ${PRO_NAME} ${PKG_NAME} } code_tar(){ writelog "code_tar" cd ${TMP_DIR} && tar czf ${PKG_NAME}.tar.gz $PKG_NAME writelog "${PKG_NAME}.tar.gz" } code_scp(){ writelog "code_scp" for node in $PRE_LIST;do scp ${TMP_DIR}/${PKG_NAME}.tar.gz $node:/opt/webroot done for node in $GROUP1_LIST;do scp ${TMP_DIR}/${PKG_NAME}.tar.gz $node:/opt/webroot done } cluster_node_remove(){ writelog "cluster_node_remove" } pre_deploy(){ writelog "remove from cluster" ssh $PRE_LIST "cd /opt/webroot && tar zxf ${PKG_NAME}.tar.gz" ssh $PRE_LIST "rm -rf /webroot/web-demo && ln -s /opt/webroot/${PKG_NAME} /webroot/web-demo" } url_test(){ URL=$1 curl -s --head $URL|grep "200 OK" if [ $? -ne 0 ];then shell_unlock; writelog "test error" && exit; fi } pre_test(){ url_test "http://${PRE_LIST}/index.html" echo "add to cluster" } group1_deploy(){ writelog "remove from cluster" for node in $GROUP1_LIST;do ssh $node "cd /opt/webroot && tar zxf ${PKG_NAME}.tar.gz" ssh $node "rm -rf /webroot/web-demo && ln -s /opt/webroot/${PKG_NAME} /webroot/web-demo" done scp ${CONFIG_DIR}/other/192.168.56.12.crontab.xml 192.168.56.12:/webroot/web-demo/crontab.xml } group1_test(){ url_test "http://192.168.56.12/index.html" echo "add to cluster" } rollback_fun(){ for node in $ROLLBACK_LIST;do ssh $node "rm -rf /webroot/web-demo && ln -s /opt/webroot/$1 /webroot/web-demo" done } rollback(){ if [ -z $1 ];then shell_unlock; echo "please input rollback version" && exit; fi case $1 in list) ls -l /opt/webroot/*.tar.gz ;; *) rollback_fun $1 esac } main(){ if [ -f $LOCK_FILE ];then echo "Deploy is running" && exit; fi DEPLOY_METHON=$1 ROLLBACK_VER=$2 case $DEPLOY_METHON in deploy) shell_lock; code_get; code_build; code_config; code_tar; code_scp; pre_deploy; pre_test; group1_deploy; group1_test; shell_unlock; ;; rollback) shell_lock; rollback $ROLLBACK_VER; shell_unlock; ;; *) usage; esac } main $1 $2
测试方式
[www@linux-node1 ~]$ curl --head http://192.168.56.11/index.html
HTTP/1.1 200 OK
Date: Mon, 01 Aug 2016 09:42:23 GMT
Server: Apache/2.4.6 (CentOS) OpenSSL/1.0.1e-fips PHP/5.4.16 mod_wsgi/3.4 Python/2.7.5
Last-Modified: Mon, 01 Aug 2016 09:39:52 GMT
ETag: "17-538ff61ca0a00"
Accept-Ranges: bytes
Content-Length: 23
Content-Type: text/html; charset=UTF-8
[www@linux-node1 ~]$ curl -s --head http://192.168.56.11/index.html|grep "200 OK"
HTTP/1.1 200 OK
上面脚本远程执行命令或者拷贝 是使用ssh/scp完成的。当服务器稍多的时候,效率并不高。
我在生产环境中是使用 ansible 替代的,个人感觉对于这个脚本来说,就是个并行、串行的区别。
进一步的发展,还可以开发一些WEB界面去结合这个脚本,做到WEB化自动部署,当然也可以使用开源的jenkis。
3、回滚
1.列出回滚版本
2.目标服务器移除集群
3.执行回滚
4.重启和测试
5.加入集群
===========
如果是遇到重大bug
1.列出回滚版本
2.执行回滚(重启)
==========
非常紧急
1.直接回滚到上个版本(重启)
自动化部署的核心是创建软链接,同样在回滚的时候也能实现秒级回滚。
但是在生产环境中,使用软连接可能会造成WEB打开页面空白,这点需要注意。
通过shell脚本实现代码自动化部署的更多相关文章
- 持续集成之⑤:jenkins结合脚本实现代码自动化部署及一键回滚至上一版本
持续集成之⑤:jenkins结合脚本实现代码自动化部署及一键回滚至上一版本 一:本文通过jenkins调用shell脚本的的方式完成从Git服务器获取代码.打包.部署到web服务器.将web服务器从负 ...
- jenkins结合脚本实现代码自动化部署及一键回滚至上一版本
持续集成之⑤:jenkins结合脚本实现代码自动化部署及一键回滚至上一版本 一:本文通过jenkins调用shell脚本的的方式完成从Git服务器获取代码.打包.部署到web服务器.将web服务器从负 ...
- AWS DevOps – 配合Jenkins和CodeDeploy实现代码自动化部署
AWS DevOps – 配合Jenkins和CodeDeploy实现代码自动化部署 Amazon ElastiCache 连接至 Redis 节点 通过 AWS Command Line Inter ...
- Jar包一键重启的Shell脚本及新服务器部署的一些经验
原文首发于博客园,作者:后青春期的Keats:地址:https://www.cnblogs.com/keatsCoder/ 转载请注明,谢谢! 前言 最近公司为客户重新部署了一套新环境,由我来完成了基 ...
- 采用shell脚本统计代码的行数
刚毕业那会儿有一次去台湾公司面试,我问多行代码怎么写.我从来没有想过这个问题,粗略计算,.惊叹:大概几十万行不行. 最近整理资料,看着eclipse左边全面上市,我觉得这个东西.代码共同拥有的行倒底总 ...
- mac链接linux终端,shell脚本发布代码
项目的业务需求:从mac端直接连上linux服务终端,并发布相关的代码 一.使用ssh链接上linux服务端 1.cd ~/.ssh 2.vi config,按照下面的内容配置config文件,然后: ...
- 【git】之使用shell脚本提交代码
为减少提交步骤,防止提交错误,使用Shell脚本进行git提交不失一件好事 #!/bin/sh # @author Hubal # @Email Hubal@123.com # @createBy - ...
- 利用shell脚本[带注释的]部署单节点多实例es集群(docker版)
文章目录 目录结构 install_docker_es.sh elasticsearch.yml.template 没事写写shell[我自己都不信,如果不是因为工作需要,我才不要写shell],努力 ...
- 使用开源my-deploy工具实现开发环境的代码自动化部署
@编者按: 由于公司内部存在的开发系统:内网开发--外网预发布--外网生产环境,程序员频繁的更新代码造成运维人员大量时间被占用,于是有了使用该开源工具的部署测试环节.在这里感谢该开源工具的作者,也希望 ...
随机推荐
- hdu5564--Clarke and digits(数位dp+矩阵快速幂)
Clarke and digits 问题描述 克拉克是一名人格分裂患者.某一天,克拉克变成了一个研究人员,在研究数字. 他想知道在所有长度在[l,r]之间的能被7整除且相邻数位之和不为k的正整数有多少 ...
- 问题-RZ安装后报错“RzBorder.pas”
错误象现:[Error] RzBorder.pas(1429): Number of elements differs from declaration [Fatal Error] RzEdit.pa ...
- [HAOI2012] 容易题
有一个数列A已知对于所有的A[i]都是1~n的自然数,并且知道对于一些A[i]不能取哪些值,我们定义一个数列的积为该数列所有元素的乘积,要求你求出所有可能的数列的积的和 mod 1000000007的 ...
- MySQL 统计信息
200 ? "200px" : this.width)!important;} --> 介绍 数据库维护统计信息的目的主要是为了优化器进行更好的执行优化,首先统计信息是建立在 ...
- React-Native首次运行提示-ReferenceError-Can-t-find-variable-fbBatchedBridge
React Native运行报错ReferenceError: Can't find variable: _fbBatchedBridge' React Native目前貌似要火的样子,作为移动开发人 ...
- HDU2001java
import java.util.*;import java.text.DecimalFormat;class Main{public static void main(String args[]){ ...
- socket.io中emit和on的用法【转】
socket.emit('action');表示发送了一个action命令,命令是字符串的,在另一端接收时,可以这么写: socket.on('action',function(){...});soc ...
- (转)十分钟搞定CSS选择器
原文地址:http://www.cnblogs.com/dolphinX/p/3347713.html 在最近的web开发中是不是就会用到一些选择器,发现很多尤其是CSS3新增的不太熟悉,在此总结一下 ...
- HDU-1018(简单数学)
Big Number Problem Description In many applications very large integers numbers are required. Some o ...
- 移动端布局Demo展示图文
上两张图自勉一下(来自刘墉先生的文章,最近看他的作品):然后移动端该愈来愈受到重视,未来的市场我不知道,不过我知道手机的功能越来越强大是不争的事实!移动端布局的积累也需要从现在做起! 需求一:实现下图 ...