【架构思考】Jenkins自动化部署升级版

背景

上一篇我们讲了,如何通过 Bamboo 实现自动化部署,流程如下:

1

其中,前面几个环节都是成熟的商业产品,最后一环是自己造的轮子(简单的 shell 脚本)。

对于中小型团队,这个方案已经足够适用了。
但是对于大型团队,或者需要更高程度的自动化,还可以进一步加强。

架构

经过考量,我们决定将架构升级如下:

2

这里加强的点是:

  • 整体更加自动化,一键就能把 application 部署并运行起来。(以前还需要自己手动再启动一遍)
  • 更强大的部署功能,支持集群机器的部署。(以前是自己手动登录到每个 server 跑一遍 shell 脚本来部署)
  • 支持非常多的开箱即用的扩展功能。(比如多个具有依赖关系的 components ,可以方便快捷地指定顺序)
  • 集成启停与监控模块,实现一站式管理。(以前这块没有,是手动操作的)

技术栈

  • Jenkins
    • 由 CD Foundation 管理的 open source 项目,是一个自动化部署工具。
    • 提供 Pipeline 功能,是所有操作的发起点。
    • 链接: https://www.jenkins.io/
  • Ansible
    • 由 Redhat 开发管理,是一个 automation and orchestration tool 。
    • 可以用来串联其它组件和工具。
    • 链接: https://www.ansible.com/
  • EOS + LPS
    • 这一块用的是公司自己开发的工具。来作为 Application Manager 。主要功能是:启停,监控。

Jenkins 配置

  1. 首先,需要配置 pipiline script 从哪里读,可以是一个静态的文件,也可以专门建一个 git repository,从 SCM 读取。
  2. 其次,需要配置 credentials ,可以是 SSH key,也可以是 username / passowrd 。这些在 Jenkinsfile 中可以直接引用。
  3. 最后,可以配置一些其它参数。(可选)

Deploy Script 配置

Jenkinsfile: 定义 pipeline 需要干些啥,一个简单的例子(pipeline 1)如下:使用 maven plugin 进行 deploy

pipeline { 
    agent any 
    options {
        skipStagesAfterUnstable()
    }
    stages {
        stage('Build') { 
            steps { 
                sh 'make' 
            }
        }
        stage('Test'){
            steps {
                sh 'make check'
                junit 'reports/**/*.xml' 
            }
        }
        stage('Deploy') {
            steps {
                sh 'make publish'
		/* sh("mvn clean package install deploy") */
            }
        }
    }
}

另外一个的例子(pipeline 2)如下:

  • 为一些变量赋值初始化
  • import lib
  • call ansible playbooks
  • 发送 email 通知 deploy 信息
#!groovy
import groovy.transform.Field

@Field def mailRecipients = "XXX@XXX"
@Field def env = ['stg', 'uat']
@Field def ssh_credentialId = "SSH_DEV_KEY"

pipeline {

    agent { label 'linux' }

    parameters{
        // git
        gitParameter(name: 'TAG', type: 'PT_BRANCH_TAG', defaultValue: 'origin/master')
        // execute goal
        choice(choices: ["Deploy"],
                description: 'Choose your execution profile',
                name: 'profile')
        // target
        choice(description: 'Select Deploy Target Environment', name: 'environment', choices: env)
    }

    // set up env var
    environment{
        ANSIBLE_FORCE_COLOR="yes"
    }

    // import lib
    libraries {
        lib("devops@master")
    }

    // checkout from git
    // checkout scm

    stages {
        stage('Deploy') {
            steps {
                ansiColor('xterm') {
                    script{

                        // define ansible path
                        ansible.galaxy("src/main/scripts/ansible/")

                        try {
                            // get the deployment file
                            def execution_file = "deploy.yml"

                            // send out start notification
                            notifyBuild('STARTED', params.environment)

                            // parse credentials
                            withCredentials([
                                    sshUserPrivateKey(credentialsId: ssh_credentialId,  keyFileVariable: 'keyfile', usernameVariable: 'ssh_user')
                            ]) {
                                // do some actual jobs
                                sh(script: """${tool 'Ansible 2'}/ansible-playbook  -i src/main/scripts/ansible/hosts/${params.environment}.yml  \
                                        -u=$ssh_user --private-key=$keyfile  \
                                        src/main/scripts/ansible/$execution_file -v \
                                        """)
                            }
                            notifyBuild('SUCCESSFUL', params.environment)
                        } catch (e) {
                            notifyBuild('FAILED', params.environment)
                            throw e
                        }
                    }
                }
            }
        }
    }
}

// send email notification
def notifyBuild(String buildStatus, String stage_env) {
	...
}

deploy.yml: 定义了 ansible playbook 需要做的事情,下例中,使用 eos2 进行部署,当然,也可以使用 shell 脚本或者其它 ansible 支持的模块。

---
 - hosts: all
   tasks:
    - name: deploy package
      eos2:
	item: "{{version}}"
        hostnames: "{{deploy_host}}"
        mode: install
        control_state: 'ON'

hosts/dev.yml: 这一部分是 properties file 。

--- 
all:
  hosts:
    XXX
  vars:
    ansible_user: XXX
    deploy_host: XXX
    version: XXX
    java_path: /usr/bin/java
posted @ 2021-02-15 21:30  MaxStack  阅读(27)  评论(0)    收藏  举报