目录

Jenkins - 开源 CI&CD 软件

Jenkins 是一款开源 CI&CD 软件,用于自动化各种任务,包括构建、测试和部署软件。

Jenkins 支持各种运行方式,可通过系统包、Docker 或者通过一个独立的 Java 程序。

  • 持续集成 (Continuous Integration)
  • 持续部署 (Continuous Deployment)

安装 Jenkins

建议使用的 Docker 映像是 jenkinsci/blueocean。该镜像捆绑了所有Blue Ocean插件和功能。这意味着你不需要单独安装Blue Ocean插件。

1
2
3
4
5
6
7
8
9
docker run \
  -u root --name jenkins-tutorials \
  --rm \
  -d \
  -p 8080:8080 \
  -p 50000:50000 \
  -v jenkins-data:/var/jenkins_home \
  -v /var/run/docker.sock:/var/run/docker.sock \
  jenkinsci/blueocean

jenkins-data 卷也可以 docker volume create 命令创建: docker volume create jenkins-data 代替映射 /var/jenkins_home 目录转换为Docker卷,还 可以将此目录映射到计算机本地文件系统上的目录。

浏览 Jenkins Web 服务,并等待 解锁 Jenkins 页面出现。

1
2
3
docker logs -f jenkins-tutorials
docker exec -it jenkins-tutorials bash
cat /var/jenkins_home/secrets/initialAdminPassword

Blue Ocean 主题插件

Blue Ocean 重新思考Jenkins的用户体验,从头开始设计Jenkins Pipeline, 但仍然与自由式作业兼容,Blue Ocean减少了混乱而且进一步明确了团队中每个成员 Blue Ocean 的主要特性包括:

  • 持续交付(CD)Pipeline的 复杂可视化 ,可以让您快速直观地理解管道状态。
  • Pipeline 编辑器 - 引导用户通过直观的、可视化的过程来创建Pipeline,从而使Pipeline的创建变得平易近人。
  • 个性化 以适应团队中每个成员不同角色的需求。
  • 在需要干预和/或出现问题时 精确定位 。 Blue Ocean 展示 Pipeline中需要关注的地方, 简化异常处理,提高生产力
  • 本地集成分支和合并请求, 在与GitHub 和 Bitbucket中的其他人协作编码时实现最大程度的开发人员生产力。

系统管理»管理插件»可选插件 过滤 Blue Ocean 勾选 直接安装

流水线 Pipeline

Jenkins 流水线 (或简单的带有大写"P"的"Pipeline") 是一套插件,它支持实现和集成 continuous delivery pipelines 到Jenkins。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!groovy
pipeline {
    agent any
    tools { 
        maven 'm3' 
        jdk 'jdk8' 
    }
    stages {
        stage ('Initialize') {
            steps {
                sh '''
                    echo "PATH = ${PATH}"
                    echo "M2_HOME = ${M2_HOME}"
                ''' 
            }
        }

        stage ('Build') {
            steps {
                echo 'This is a minimal pipeline.'
                checkout([$class: 'GitSCM', branches: [[name: '*/TD_sit']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: '63b8184b-a84c-4beb-9ccd-1267f7f32c5e', url: 'http://dev.ixdigit.com/bo/Trade_socket.git']]])
                sh 'mvn versions:set -DgenerateBackupPoms=false -DnewVersion=1.0.0-SIT-SNAPSHOT'
                sh 'mvn --update-snapshots clean deploy -B -e -U -Dmaven.test.skip=true -DreleaseEnv=SIT'
            }
        }
    }
}

流水线开发工具

配置

系统设置

Git plugin

user.name user.email

Gitlab

Gitlab host URL Credentals GitLab API token

全局工具配置

Git

Path to Git executable git

Maven

Maven name m3

MAVEN_HOME /opt/maven

Maven

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
mkdir /opt/maven
cd /opt/maven
wget http://mirrors.tuna.tsinghua.edu.cn/apache/maven/maven-3/3.5.3/binaries/apache-maven-3.5.3-bin.tar.gz
tar -xvf apache-maven-3.5.3-bin.tar.gz

vi /etc/profile
export MAVEN_HOME=/opt/maven/apache-maven-3.5.3
export MAVEN_HOME
export PATH=${PATH}:${MAVEN_HOME}/bin

source /etc/profile
mvn -v
# 更改 maven 用户配置 与全局配置 ${MAVEN_HOME}/conf/settings.xml 共同作用,用户配置优先
vi ~/.m2/settings.xml

SSH 免密登陆

1
2
3
4
5
# 生成公私密钥 直接回车  
ssh-keygen -t rsa
# ssh-keygen -t rsa -C "iwys@qq.com"
# 本机将公钥传输到远程机器
scp -r /root/.ssh/id_rsa.pub 192.168.31.147:/root/.ssh/authorized_keys

JDK8

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# Ubuntu jdk 8
sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get install oracle-java8-installer
# 设置默认JDK
sudo apt install oracle-java8-set-default

# vim ~/.bashrc
vi /etc/profile
export JAVA_HOME=/usr/lib/jvm/java-8-oracle
export JRE_HOME=${JAVA_HOME}/jre   
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib   
export PATH=${JAVA_HOME}/bin:$PATH
source /etc/profile
env
# /usr/lib/jvm/java-8-oracle
java -version

Gitlab

建立jenkins 专用账号

登陆 Gitlab Profile Settings

Account Private Token

SSH Keys

maven integration plugin //该插件安装了,才能创建maven项目。

git plugin //从远程拉取代码

deploy to container plugin //发布

publish over ssh ssh远程登录

配置插件

Blue Ocean

Maven Integration

Git plugin

GitLab

系统设置->Gitlab

Connection name gitlab

GitLab host URL http://dev.ixdigit.com

如果报500错误 可能是 API-Level 需要指定

Credentials -> Add -> Jenkins

Kind GitLab API token

写入 API token 点击 Add

登陆 GitLab Profiel Settings-> Account-> Private token LrvCsd1rBjcRRdv5ng19

Gitlab Hook

打开一个Jenkins Job的配置,在“构建触发器”区中选择 “Build when a change is pushed to GitLab. GitLab CI Service URL:”

GitLab webhook URL: http://172.27.2.49:8088/project/Goldoffice_trade_api

这个url 是给gitlab 用

高级选项中生成“Secret token”

登陆GitLab 选择对应的Project “Settings”–》“Integrations”

填入 URL 与 Sercret Token

Deploy to container

Email Extension Plugin

Publish Over SSH

远程部署 jar

Execute shell

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15

cd /opt/projectname/  #进入项目jar包存放目录

#得到进程ID pid,kill该进程
pid=`cat /opt/projectname/pid`  #得到该目录下 pid文件中的进程id
if [ -n "$pid" ]
then
    echo "kill -9 的pid:" $pid
    kill -9 $pid    #kill该进程
fi

#执行jar,并将进程挂起,保存进程ID到 pid文件
echo "Execute shell Finish"

BUILD_ID=DONTKILLME nohup java -jar /opt/projectname/jenkins_jar.jar  & echo "$!" > pid   #执行项目jar包,将进程挂起,然后将进程id写入当前目录下的pid文件中

Global Tool Configuration 系统设置

  • JDK
  • Git
  • Maven
  • Docker

Jenkinsfile

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
pipeline {
    agent any
    stages {
        stage('Checkout') {
            steps {
                echo 'Checkout'
                checkout([$class: 'GitSCM', branches: [[name: '*/master']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: '500378f5-a6e4-4255-984e-61537fe0e455', url: 'git@gitlab.aniu.so:aniu-yunwei/game-of-life.git']]])
            }
        }        
        stage('Build') {
            steps {
                echo 'Building'
                sh 'mvn clean install' # 可以用自己的 mvn clean deploy + 参数替代
            }
        }
        stage('Test') {
            steps {
                echo 'Testing'
                sh 'mvn clean verify sonar:sonar' # 此处可以使用mvn test替代,笔者这步是检测代码的质量同步到自己的代码质量检测平台。
            }
        }
        stage('Deploy') {
            steps {
                echo 'Deploying'
                sh 'mvn clean deploy'  # 此处调用脚本或者ansiblesaltstak,部署到远程
            }
        }
    }
}

运行 jar 发布到远程服务器

Post Steps

Run only if build succeeds

增加 Execute shell script on remote host using ssh

SSH site root@192.168.10.1:22

Command

1
2
3
export JAVA_HOME=/usr/local/jdk/jdk1.8.0_144
/opt/projectname/service.sh stop
rm -rf /opt/projectname/*

增加 Execute shell

1
2
scp -r ${WORKSPASE}/target/spring-ynthm.war  root@192.168.10.1:/opt/projectname
scp -r ${WORKSPASE}/service.sh  root@192.168.10.1:/opt/projectname

增加 Execute shell script on remote host using ssh

SSH site root@192.168.10.1:22

Command

1
2
export JAVA_HOME=/usr/local/jdk/jdk1.8.0_144
/opt/projectname/service.sh start

service.sh

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#!/bin/sh    
    
## java env    
export JAVA_HOME=/usr/local/jdk/jdk1.8.0_144    
export JRE_HOME=$JAVA_HOME/jre    
    
## service name    
APP_NAME=account    
    
SERVICE_DIR=/usr/local/dubbo-server/$APP_NAME    
SERVICE_NAME=medcare-dubbo-$APP_NAME    
JAR_NAME=$SERVICE_NAME\.jar    
PID=$SERVICE_NAME\.pid    
    
cd $SERVICE_DIR    
    
case "$1" in    
    
    start)    
        nohup $JRE_HOME/bin/java -Xms256m -Xmx512m -jar $JAR_NAME >/dev/null 2>&1 &    
        echo $! > $SERVICE_DIR/$PID    
        echo "=== start $SERVICE_NAME"    
        ;;    
    
    stop)    
        kill `cat $SERVICE_DIR/$PID`    
        rm -rf $SERVICE_DIR/$PID    
        echo "=== stop $SERVICE_NAME"    
    
        sleep 5    
        ##    
        ## edu-service-aa.jar    
        ## edu-service-aa-bb.jar    
        P_ID=`ps -ef | grep -w "$SERVICE_NAME" | grep -v "grep" | awk '{print $2}'`    
        if [ "$P_ID" == "" ]; then    
            echo "=== $SERVICE_NAME process not exists or stop success"    
        else    
            echo "=== $SERVICE_NAME process pid is:$P_ID"    
            echo "=== begin kill $SERVICE_NAME process, pid is:$P_ID"    
            kill -9 $P_ID    
        fi    
        ;;    
    
    restart)    
        $0 stop    
        sleep 2    
        $0 start    
        echo "=== restart $SERVICE_NAME"    
        ;;    
    
    *)    
        ## restart    
        $0 stop    
        sleep 2    
        $0 start    
        ;;    
    
esac    
exit 0  

附录