• jenkins 自动化部署实战


      jenkins 作为一个自动化的集成工具,已经是必不可少的了。它里面提供各种插件,以及完备的基础流程设施,为大家的自动化集成之路提供了很多的方便。所以,我们有必要完整的实践一回。以切身体会到它的好处!

    一、 操作步骤说明陈列

      1. 下载jenkins包,并安装;(两种方案,基于物理机和基于docker,视情况而定建议使用docker)

      2. 安装后,初始化jenkins,基本都是下一步下一步搞定,保持默认是比较稳妥的选择;

      3. 订立目标,需要完成什么的场景下的打包功能? git ?  subversion? 或者其他 ?

      4. 选择此场景需要的必要插件安装,并进行简单调试;

      5. 新建一个任务,尝试使用工具完成一次简单的打包操作;

      6. 完善一个任务,使其可以支持一些简单的参数定制,如分支的选择;

      7. 打包完成后,编写部署脚本,使其可以一键部署;

      8. 设置权限管理,使不同环境的包由不同级别的同学进行操作;

      9. 进行反复功能验证,及权限验证;

      10. 备注所有的操作流程,以便在进行下次重新安装时,能够随时搞定;

     二、具体实践操作

      简单的安装和初始化,咱们就不多说了,网上一大堆的信息,随便找一个就能搞定,不找也能搞定,请参考官网: https://wiki.jenkins.io/display/JENKINS/Use+Jenkins

    打包场景一: 如何打包 maven 管理的java项目 ?

      其实要打包这种项目比较简单,只要安装一个 maven integeration 的插件即可!如下:

      安装好后,新建一个 maven 任务即可!

      其实maven任务和其他任务不太一样的地方是,它会出现一个 pom.xml 的字样,其实就是自己去加载这个配置文件,然后自行调用 maven 进行打包。而如果想要更灵活,也是可以的,只需要使用 系统的命令进行自由构建即可!

      goal 里可写: clean install | package

       经过上面的操作后,你可能会发现,其实并不会打包成功,为什么呢?因为我们还没有安装 maven 的工具到系统上,或者说没有向 jenkins 解释 maven 在哪里,所以需要到全局工具配置一下!

      另外,如果你是需要打包 git 类的代码的话,一般只需要进行简单授权就可以了!

      到此,一个 简单的 maven java 项目打包就成功了!

    但是,其实,打包到这个程度,其实对我们的环境部署一点更多的意义都没有,所以我们需要更深的定制化!咱们稍后再说!

    先来说说,另一种项目的打包方式, h5 代码的打包。 更具体的讲,就是 基于 nodejs 的打包实现!

      首先,我们当然需要安装 node js 的插件了!

      同样,该插件安装好后,还要安装  nodejs 的软件!可以直接选择自动 安装 ! 注意要求的版本!

      安装好后,新建一个自由风格的任务!

      进入,把 node 的环境支持勾选上!然后定稿node 的打包命令!

      同样,git 相关的操作一样!

      至此,简单的 node 版本的代码打包功能也做好了。 

      同样,只是进行打包,无法定制化的东西,对我们毫无意义,所以,我们需要更高级的定制 jenkins !

      例外:如果有依赖一些私有的包,那么,你可以选择安装私服,或者用如下方式解决:

    # for local repository dependency...
    ln -sf /var/lib/jenkins/pkg-bak/testmodule/ $WORKSPACE/node_modules/testmodule
    npm install
    npm run prod

    三、 定制你的 jenkins 功能!

    场景一: 我需要为一个git 仓库的多个分支打包?

      这个,简单, jenkins 中一添加定制化参数的功能,只需要添加一个文本参数就可以 了!

      在 git 分支一栏,写入 $branch 替换即可!

       如此,一个简单的支持 git 多分支打包的功能就做好了!

    但是:每次都让我自己输入分支,好烦啊! 而且,我自己也不一定知道有什么样的分支,这可怎么办?

      借助 groovy 脚本,可以动态拉取 分支列表,进行显示了!

      简单来说就是,执行一些shell脚本 , 从 git 远端列举出分支,给到列表选项! groovy 脚本如下:

    def git_url = "https://github.com/yougewe/elastic-job-lite"
    def git_cmd = "/usr/local/git/bin/git ls-remote -h $git_url  | grep -oP '(?<=refs/heads/).*' "
    branch = ['bash', '-c', git_cmd].execute().text.readLines()

      好了,分支的选择,看起来我们已经解决得差不多了!

      但是,前端有个点,就是这分支的触发问题,其实我们可以更动态方式实现!

    场景二: 我需要支持多个仓库进行切换打包,当然这里的仓库将必然影响到上面分支列表的选择!

      可以使用 Active Choice 这个插件,可以让我们在需要的时候触发一次分支的选择,比如支持 分支快速过滤!达到数据联动的效果;

      然后,也可以使分支依赖于动态的仓库进行变更分支列表等等!总之, Active Choice 插件真是很方便发挥!

      最终的效果就是,我们可以选择,多仓库,动态列表多分支,进行打包!

          总之,通过这个联动支持,以及简单groovy知识,你可以有很大的发挥空间;

    场景三: 我需要将打好的包部署到指定服务器上?

          这是个关键的问题,就是我们打包来的包,应该处理的问题!

          这里有两个核心问题: 1. 我如何找到打包后的东西? 2. 如何将找到的东西部署到线上?

      如果不能很好的处理这些包,我们将很无奈!所以  shell 就出场了!

      jenkins 支持在打包后进行一些自定义的操作! 比如 上传包到另外的服务器,或者部署到另外的地方等等!总之,就是任你发挥!

          一般地说,查找打包后的东西,要依赖于你的代码实现,所以具体问题具体分析;当然了,你可以通过mvn等命令直接订制打包的各种配置,从而活动查找的麻烦;

          另外,对于部署到服务器,至少有两个解决方案:1. 直接通过scp等服务器拷贝技术,将包放到目标服务器即可; 2. 将包打包成可执行的安装包,上传yum源服务器,在使用端直接拉取镜像即可;

      比如如下的脚本 ,我们可以将它部署到我们指定服务器的 docker 容器中!

      参考脚本如下:

    echo "hello, build over ??? would you scp or deploy apps ??? work dir: $WORKSPACE , repository: $spec_repository;"
    # specify dev environment or product environment
    deploy_env_server="root@172.10.11.16"
    deploy_path_prefix="/opt/docker/webapps/test"
    docker_app_startup_script="/etc/init.d/startup restart";
    case "$spec_repository" in
        richCash)
            docker_container_name="test_container";
            docker_app_startup_script="/etc/init.d/startup restart";
            deploy_path_prefix="/opt/docker/webapps/";
            deploy_sub_path="$deploy_environment"
            case "$deploy_environment" in
                "test-p8081")
                    docker_container_name="test_p8081_container"
                    ;;
                    docker_container_name="test_p8083_container"
                    ;;
                *)
                    # default container
                    ;;
            esac
            deploy_path_prefix="/opt/docker/webapps/$deploy_sub_path";
            ;;
        test2-01)
            deploy_path_prefix="/opt/docker/webapps/test2-01";
            docker_container_name="test2_01_container";
            docker_app_startup_script="/etc/init.d/startup restart";
            ;;
        *)
            echo "not find special configures in $spec_repository, do the default thing";
        ;;
    esac
    # deploy script
    deploy_script_path="ssh $deploy_env_server "docker exec $docker_container_name bash -c '$docker_app_startup_script'"";
    
    pom_file="$WORKSPACE/pom.xml";
    pom_file_tmp="$pom_file.tmp";
    cd $WORKSPACE;
    cat $pom_file | awk '{if($0 ~ /<parent>/){parent_begin++; print "no dump parent"} else if(parent_begin > 0){ if($0 ~ /</parent>/){parent_begin = 0; print "match the parent end.";} else {print "hit parent dump"; }} else { print $0;}}' > $pom_file_tmp
    package_artifactId=`grep "<artifactId>" $pom_file_tmp | head -n 1 | sed -e 's/(s*<artifactId>|</artifactId>s*)//g'`;
    package_version=`grep "<version>" $pom_file_tmp | head -n 1 | sed -e 's/(s*<version>|</version>s*)//g'`;
    package_full_name="$package_artifactId-$package_version.jar"    # 定义为jar包写死
    package_full_path="$WORKSPACE/target/$package_full_name";
    echo "packaged file is: $package_full_name";
    scp $package_full_path $deploy_env_server:"$deploy_path_prefix/$package_full_name";
    # restart the server...
    eval $deploy_script_path;

      如上,是对 jar 包的部署方式,我们再来看下 h5 包的部署方式:

    echo "hello, build over ??? work dir: $WORKSPACE , repository: $spec_repository; branch: $branch ;"
    # specify dev environment or product environment
    deploy_env_server="root@172.11.1.12"
    docker_container_name="web_container";
    deploy_path_prefix="/opt/docker/webapps/";
    deploy_sub_path="$deploy_environment"
    deploy_path_prefix="$deploy_path_prefix""$deploy_sub_path"
    deploy_package_bak_path="/opt/docker/webapps/bak/"
    docker_app_startup_script="ls "
    case "$deploy_environment" in
        "web-p81")
            docker_container_name="web_81_container"
        ;;
        *)
            # default container
        ;;
    esac
    datetime=`date '+%Y%m%d%H%M'`;
    package_full_name="$spec_repository-$branch-$datetime.tar.gz"
    package_full_origin_path_prefix="/var/lib/jenkins/tmppackages/h5"
    package_full_origin_path="$package_full_origin_path_prefix/$package_full_name";
    deploy_package_bak_path="$deploy_package_bak_path""$package_full_name"
    # deploy script
    deploy_script_path="ssh $deploy_env_server "rm -rf $deploy_path_prefix/*; if [ ! -d $deploy_path_prefix ]; then mkdir -p $deploy_path_prefix; fi; tar -xzf $deploy_package_bak_path -C $deploy_path_prefix"";
    
    package_dist_origin_path="$WORKSPACE/dist";
    cd $package_dist_origin_path;
    tar -czf $package_full_origin_path -C $package_dist_origin_path .;
    echo "packaged file is: $package_full_origin_path";
    scp $package_full_origin_path $deploy_env_server:"$deploy_package_bak_path";
    # restart the server...
    eval $deploy_script_path;

      如上,h5 的打包方式,区别在于需要手动打包一为 gz 包,然后到目标机器进行解压缩即是安装!

      
      如上,就可以进行一键部署测试环境了!
      剩下的,就是自己自由发挥了!
      同理于 h5 的部署方式!

    四、重难点提示

           其实,准确来说,上面的操作都比较常规,因为都是最终的结果步骤展示!但是其实这其中有很多的坑,期望提示对你有帮助!

           1. 使用groovy 进行分支获取时, 需要对 git 命令进行免密授权操作,否则将永远拉不到分支;

           2. 使用scp, scp 这些命令调用远程,需要免密登录,否则授权失败;

           3. 使用 ssh xx@1.2.2.4 "ls ." 运行远程命令如同本地命令;

           4. 真正的部署脚本可以远程服务器上,也可以写在部署机器上;

           5. 出于安全考虑,默认情况下运行jenkins的用户都不是root,所以一般不要以为在terminal操作正常的命令,在jenkins上也能正常;

     五、jenkins带来的切实好处

           为什么一定要用jenkins?难道就因为其名声大燥吗?其实是是因为它真的能带来这些好处:

           1. 部署速度指数级提升,以前按照个人的操作速度,要10分钟左右的操作且要记忆多种复杂关联命令,现在可能只要2分钟一键搞定,爽不爽?

           2. 部署信息有迹可查,如果按照之前的部署,谁部署出了问题,完全不知道,但是jenkins上有操作记录,更易发现问题;

           3. 解决了系统兼容性问题引发的不适,之前各自部署来源不一致,可能导致各种难查问题,而用jenkins则保证完全一致;

           4. 拒绝不可靠错误代码的上线,借助于jenkins的单元测试功能,可以发现在一些简单代码的问题,避免之前的误操作上线;

           5. 因为收口部署方式,对于后续新的部署方案,有了更加有利的支持,比如想加入sonar代码扫描,只需修改下部署部署脚本即可;

    附:

      Q: jenkins 使用插件进行部署,调用运行shell脚本不成功?
        nohup 运行 java 程序,被关掉后无法重启。可能原因是 该进程尚未被挂到当前会话,就被kill或者退出。解决办法是加上适当延迟。

    # 该进程可能启动缓慢
    nohup java -jar a.jar &
    
    #sleep 延迟可以处理异步问题
    sleep 3
    echo " start over, new pid: $! !!!"

      Q: 有哪些方便的插件推荐?
      Publish On SSH & SSH Slaves, 方便进行远程部署。
      Rebuilder, 方便进行相同参数的部署重新执行, rebuild 即可,避免反复选择参数信息。
      Active Choice, 下拉框,可以触发脚本执行,方便进行动态响应,而不是全静态的参数。
      Timestamper, 可以获取时间参数,以便进行日志类记录;
      user build vars plugin, 获取各种系统变量;
      Workspace Cleanup Plugin, 空间清理插件,避免jenkins占用太多空间;

    一句话总结:有时知道问题比解决问题更重要!

  • 相关阅读:
    CSS学习笔记-盒子阴影及文字阴影
    CSS学习笔记-2D转换模块
    CSS学习笔记-过度模块-编写过渡效果
    CSS学习笔记-过渡模块
    Unity3D_Transform_位置、角度、缩放及其他
    微信小程序实现生成画报并且实现下载功能
    前端知识点
    vue导出excel表格用到的两个文件
    react 的高阶组件
    代理的配置
  • 原文地址:https://www.cnblogs.com/yougewe/p/10567850.html
Copyright © 2020-2023  润新知