【架构思考】Jenkins自动化部署升级版
背景
在上一篇我们讲了,如何通过 Bamboo 实现自动化部署,流程如下:

其中,前面几个环节都是成熟的商业产品,最后一环是自己造的轮子(简单的 shell 脚本)。
对于中小型团队,这个方案已经足够适用了。
但是对于大型团队,或者需要更高程度的自动化,还可以进一步加强。
架构
经过考量,我们决定将架构升级如下:

这里加强的点是:
- 整体更加自动化,一键就能把 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 配置
- 首先,需要配置 pipiline script 从哪里读,可以是一个静态的文件,也可以专门建一个 git repository,从 SCM 读取。
- 其次,需要配置 credentials ,可以是 SSH key,也可以是 username / passowrd 。这些在 Jenkinsfile 中可以直接引用。
- 最后,可以配置一些其它参数。(可选)
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

浙公网安备 33010602011771号