通过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脚本实现代码自动化部署的更多相关文章

  1. 持续集成之⑤:jenkins结合脚本实现代码自动化部署及一键回滚至上一版本

    持续集成之⑤:jenkins结合脚本实现代码自动化部署及一键回滚至上一版本 一:本文通过jenkins调用shell脚本的的方式完成从Git服务器获取代码.打包.部署到web服务器.将web服务器从负 ...

  2. jenkins结合脚本实现代码自动化部署及一键回滚至上一版本

    持续集成之⑤:jenkins结合脚本实现代码自动化部署及一键回滚至上一版本 一:本文通过jenkins调用shell脚本的的方式完成从Git服务器获取代码.打包.部署到web服务器.将web服务器从负 ...

  3. AWS DevOps – 配合Jenkins和CodeDeploy实现代码自动化部署

    AWS DevOps – 配合Jenkins和CodeDeploy实现代码自动化部署 Amazon ElastiCache 连接至 Redis 节点 通过 AWS Command Line Inter ...

  4. Jar包一键重启的Shell脚本及新服务器部署的一些经验

    原文首发于博客园,作者:后青春期的Keats:地址:https://www.cnblogs.com/keatsCoder/ 转载请注明,谢谢! 前言 最近公司为客户重新部署了一套新环境,由我来完成了基 ...

  5. 采用shell脚本统计代码的行数

    刚毕业那会儿有一次去台湾公司面试,我问多行代码怎么写.我从来没有想过这个问题,粗略计算,.惊叹:大概几十万行不行. 最近整理资料,看着eclipse左边全面上市,我觉得这个东西.代码共同拥有的行倒底总 ...

  6. mac链接linux终端,shell脚本发布代码

    项目的业务需求:从mac端直接连上linux服务终端,并发布相关的代码 一.使用ssh链接上linux服务端 1.cd ~/.ssh 2.vi config,按照下面的内容配置config文件,然后: ...

  7. 【git】之使用shell脚本提交代码

    为减少提交步骤,防止提交错误,使用Shell脚本进行git提交不失一件好事 #!/bin/sh # @author Hubal # @Email Hubal@123.com # @createBy - ...

  8. 利用shell脚本[带注释的]部署单节点多实例es集群(docker版)

    文章目录 目录结构 install_docker_es.sh elasticsearch.yml.template 没事写写shell[我自己都不信,如果不是因为工作需要,我才不要写shell],努力 ...

  9. 使用开源my-deploy工具实现开发环境的代码自动化部署

    @编者按: 由于公司内部存在的开发系统:内网开发--外网预发布--外网生产环境,程序员频繁的更新代码造成运维人员大量时间被占用,于是有了使用该开源工具的部署测试环节.在这里感谢该开源工具的作者,也希望 ...

随机推荐

  1. NDK编译路径问题

    有点偷懒,在一个使用了jni工程里面稍微修改一下,编译另外一个jni工程. 代码写完后,Android.mk等文件也写好,但是ndk-build的时候提示Android NDK:Your APP_BU ...

  2. 10个强大的Apache开源模块

    1.单点登录模块 LemonLDAP LemonLdap可以很棒地实现Apache的SSO功能,并且可以处理超过 20 万的用户请求.LemonLdap支持Java, PHP, .Net, Perl, ...

  3. 微信开发第8章 通过accesstoken将长连接转换为短链接

    业务场景:开发的过程中经常会有一些很长的链接,这个时候如果生成二维码,会导致扫码的过程中识别比较慢,如果存入数据库,会导致数据库的字段长度要设定的很长才行,所以把长连接转换为短链接就越来越重要了. 接 ...

  4. 聊聊LAA(LARGE ADDRESS AWARE)

    博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:聊聊LAA(LARGE ADDRESS AWARE).

  5. IOS开发之tableview只选中一行

    场景:一个弹出层,包含一个Tableview,每一行为一个选择条件,且只能选择一个.选中后文体有颜色变化,后面还会有对勾.选择另一个后,前一个恢复成普通状态. 示例代码: -(void)tableVi ...

  6. Error In Work

    ReferenceError: BAD_REQUEST is not defined MyBatis配置错误,比如$!conflict.id,写成conflict.$!id

  7. listbox icon

    . 实现过程 . . . 图 . 备注 . .关键点 . 相关链接 相关链接    相关链接 相关链接    相关链接. . 来自为知笔记(Wiz) 附件列表

  8. java缓存算法【转】

    http://my.oschina.net/u/866190/blog/188712 提到缓存,不得不提就是缓存算法(淘汰算法),常见算法有LRU.LFU和FIFO等算法,每种算法各有各的优势和缺点及 ...

  9. git 设置

    系统乱码 项目中的编码统一设置为UTF-8编码. 设置系统的语言设置为 zh_UTF-8,把 export LANG=zh_CN.UTF-8 保存到~/.profile文件里. $ env|grep ...

  10. 大区间素数筛选 POJ2689

    题意: 给一个区间[L,U],(1<=L< U<=2,147,483,647),U-L<=1000000,求出[L,U]内距离近期和距离最远的素数对. 因为L,U都小于2^32 ...