1. 工具介紹
git:版本控制,一般都是托管到代碼倉庫的。如 github、coding、gitlab (本文以 coding 為例)
jenkins:持續集成工具之一,也是最常用的工具,主要工作就是將代碼從git倉庫pull下來,通過maven打包,在部署到服務器上
maven:java 項目管理構建自動化工具,主要是將 java 源代碼打包成 jar 程序
ansible:批量部署程序所使用的工具。
下面介紹的部署過程使用到了以上 4 個工具。
主機介紹:

實現思路:

2. 持續集成實例
2.1 首先將源代碼托管到 git 倉庫,具體操作自行百度,例如:coding倉庫。

我這里是一個私有倉庫,請自行創建倉庫。
2.2 安裝 jenkins 和 maven 工具
這里最好將 jenkins 配置文件修改如下:
[root@192.168.118.17 ~]#vim /etc/sysconfig/jenkins ... JENKINS_USER="root" ...
修改為 root 這樣可以直接使用 root用戶打包,不用在其他用戶家目錄下構建依賴包
本次構建使用了 jenkins 的 pipeline 功能,這里需要安裝一些插件:
系統管理 -> 插件管理 -> 可選插件 搜索一下插件進行安裝:
Blue Ocean
插件安裝完成后,重啟下服務:
[root@192.168.118.17 ~]#systemctl restart jenkins
安裝 git 和 maven
安裝git
[root@192.168.118.17 ~]#yum install git -y
安裝 maven
下載地址:http://maven.apache.org/download.cgi [root@192.168.118.17 /usr/local/src]#tar xf apache-maven-3.1.1-bin.tar.gz -C /usr/local/ [root@192.168.118.17 /usr/local/src]#cd /usr/local/ [root@192.168.118.17 /usr/local]#ln -vs /usr/local/apache-maven-3.1.1/ /usr/local/maven ‘/usr/local/maven’ -> ‘/usr/local/apache-maven-3.1.1/’ [root@192.168.118.17 /usr/local]#ln -vs /usr/local/maven/bin/mvn /usr/bin/ ‘/usr/bin/mvn’ -> ‘/usr/local/maven/bin/mvn’
安裝好兩個工具后,首先通過 git 將源代碼克隆下來,通過 maven 進行測試。
[root@192.168.118.17 ~]#git clone https://git.dev.tencent.com/hukey/winstar-common-api.git [root@192.168.118.17 ~]#cd winstar-common-api/ [root@192.168.118.17 ~/winstar-common-api]#mvn clean package -Dmaven.test.skip=true
第一次通過 mvn 打包時間會長一點。

出現如上信息,則打包完成。
2.3 通過 ansible 將程序推送到需要部署的節點
接下來的思路:
通過 ansible 將 xxx.jar 文件推送到需要部署的服務器上,啟動起來。
安裝 ansible 並配置:
[root@192.168.118.17 ~]#yum install ansible -y
(1)將 ansible 主機連接 程序部署主機設置為免密碼登錄
[root@192.168.118.17 ~]#ssh-keygen -t rsa -P '' [root@192.168.118.17 ~]#ssh-copy-id root@192.168.118.19 [root@192.168.118.17 ~]#ssh-copy-id root@192.168.118.20
(2)配置 ansible 組
[root@192.168.118.17 ~]#vim /etc/ansible/hosts ... [common-api] 192.168.118.19:22 ansible_ssh_user=root adrser=/app/node-1/ 192.168.118.20:22 ansible_ssh_user=root adrser=/app/node-1/ ...
格式:
ip:port ansible_ssh_user=用戶名 adrser=設置一個變量,這里設置的變量為一個程序部署目錄,這兩台主機目錄必須存在。
(3)測試 ansible 無密碼驗證
[root@192.168.118.17 ~]#ansible common-api -m ping
192.168.118.20 | SUCCESS => {
"changed": false,
"ping": "pong"
}
192.168.118.19 | SUCCESS => {
"changed": false,
"ping": "pong"
}
(4)通過 ansible 為兩台程序節點部署環境
創建啟動程序目錄:
[root@192.168.118.17 ~]#ansible common-api -m file -a "path=/app/node-1 state=directory"
192.168.118.19 | SUCCESS => {
"changed": true,
"gid": 0,
"group": "root",
"mode": "0755",
"owner": "root",
"path": "/app/node-1",
"size": 6,
"state": "directory",
"uid": 0
}
192.168.118.20 | SUCCESS => {
"changed": true,
"gid": 0,
"group": "root",
"mode": "0755",
"owner": "root",
"path": "/app/node-1",
"size": 6,
"state": "directory",
"uid": 0
}
為兩台程序節點安裝jdk
# 將jdk拷貝到遠程主機,並解壓到 /usr/local/ 目錄 [root@192.168.118.17 ~]#ansible common-api -m unarchive -a "src=/usr/local/src/jdk-8u77-linux-x64.tar.gz dest=/usr/local/" # 創建軟鏈接文件 [root@192.168.118.17 ~]#ansible common-api -m file -a "path=/usr/bin/java src=/usr/local/jdk1.8.0_77/bin/java state=link" [root@192.168.118.17 ~]#ansible common-api -m file -a "path=/usr/bin/javac src=/usr/local/jdk1.8.0_77/bin/javac state=link"
(5)首先將 jar 包推送到兩台服務器上,是為了編寫啟動腳本比較方便。
[root@192.168.118.17 ~]#ansible common-api -m copy -a "src=/root/winstar-common-api/target/winstar-common-api-1.0.0-SNAPSHOT.jar dest={{adrser}}"
(6)編寫程序啟動腳本
[root@192.168.118.19 /app/node-1]#vim service.sh
#!/bin/bash
cd /app/node-1
start(){
if [ -f `ls *.jar` ];then
APP=$(ls *.jar)
nohup java -jar $APP &
else
echo "Error: no app!"
fi
}
stop(){
pkill -9 java
}
update(){
if [ ! -d backup ];then
mkdir -p backup
fi
mv -f *.jar backup
rm -rf nohup.out
}
case $1 in
start)
start
;;
stop)
stop
;;
update)
stop
update
;;
*)
echo "Usage: $0 [start | stop | update]"
esac
編寫了一個比較簡單的腳本,這個腳本只是用來測試使用,如果生產環境使用,還有許多地方需要進行改善。
將這個腳本放在兩個程序節點 /app/node-1/目錄下。
(7)通過 ansible 測試程序能否正常啟動成功
第一步,將程序從控制節點拷貝到程序節點:
# 安裝 net-tools 包,主要用到 netstat 命令
[root@192.168.118.17 ~]#ansible common-api -m yum -a "name=net-tools state=present"
# 查看目前在工作的端口信息
[root@192.168.118.17 ~]#ansible common-api -a "netstat -ntplu"
192.168.118.19 | SUCCESS | rc=0 >>
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 891/sshd
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 1454/master
tcp6 0 0 :::22 :::* LISTEN 891/sshd
tcp6 0 0 ::1:25 :::* LISTEN 1454/master
192.168.118.20 | SUCCESS | rc=0 >>
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 882/sshd
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 1369/master
tcp6 0 0 :::22 :::* LISTEN 882/sshd
tcp6 0 0 ::1:25 :::* LISTEN 1369/master
# 將應用程序拷貝到程序節點
[root@192.168.118.17 ~]#ansible common-api -m copy -a "src=/root/winstar-common-api/target/winstar-common-api-1.0.0-SNAPSHOT.jar dest={{adrser}}"
第二步,啟動程序,查看程序端口
# 啟動應用程序
[root@192.168.118.17 ~]#ansible common-api -a "sh {{adrser}}/service.sh start"
# 啟動完畢間隔一段時間,查看應用程序端口是否啟動完成
[root@192.168.118.17 ~]#ansible common-api -a "netstat -ntplu"
192.168.118.19 | SUCCESS | rc=0 >>
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 891/sshd
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 1454/master
tcp6 0 0 :::3090 :::* LISTEN 3447/java
tcp6 0 0 :::3091 :::* LISTEN 3447/java
tcp6 0 0 :::22 :::* LISTEN 891/sshd
tcp6 0 0 ::1:25 :::* LISTEN 1454/master
192.168.118.20 | SUCCESS | rc=0 >>
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 882/sshd
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 1369/master
tcp6 0 0 :::3090 :::* LISTEN 3200/java
tcp6 0 0 :::3091 :::* LISTEN 3200/java
tcp6 0 0 :::22 :::* LISTEN 882/sshd
tcp6 0 0 ::1:25 :::* LISTEN 1369/master
應用端口:3090,管理端口:3091 說明啟動成功。
至於 stop 和 update 可以自行測試,必須要保證腳本的可用性,因為后面會用到。
2.4 配置 jenkins pipeline流水線
登錄 jenkins -> 新建任務


應用並保存,這樣 jenkins 配置已經完成。要使用 jenkins 的 pipeline 功能,要需要在 git 倉庫里新增幾個配置文件。
2.5 在 git 倉庫配置 pipeline 文件
登錄到倉庫頁面

Jenkinsfile 文件內容如下:
pipeline{
agent any
stages {
stage('Build') {
steps{
sh 'mvn clean package -Dmaven.test.skip=true'
echo 'Build success.'
}
}
stage('Test') {
steps{
sh 'mvn test'
}
post {
always {
junit 'target/surefire-reports/*.xml'
}
}
}
stage('Deliver') {
steps {
sh 'sh ./jenkins/scripts/deliver.sh'
}
}
}
}
代碼內容很簡單,分為三段:
1. 打包
2. 測試
3. 發布
重點關注下 第三個 發布是通過出一個腳本來實現的。因此這個目錄和腳本必須也放置到 git 倉庫。 將 jenkins pipeline 配置文件和腳本放置到 git倉庫,這樣更易於維護,而且對 jenkins 的使用會更加靈活。

注意腳本放置的目錄,腳本內容如下:
#!/bin/bash
# Author: hukey
# date: 2019-07-16 17:23:20
#
function status(){
ansible common-api -a "netstat -ntplu"
}
function update(){
if [ ! -f target/*.jar ];then
echo '[Error]:java.jar not exist, update failed.'
exit 1
fi
JAR=$(ls target/*.jar)
ansible 'common-api' -m shell -a '{{adrser}}/service.sh update'
ansible 'common-api' -m copy -a "src=$JAR dest={{adrser}}"
}
function start(){
ansible 'common-api' -m shell -a '{{adrser}}/service.sh start'
}
update
sleep 3
start
上面的腳本,必須和 app-node 中的腳本對應着來看,簡要說下:
首先 執行 update 操作,將 app-node 上的應用程序停止並備份到backup目錄,將本地的 jar 程序拷貝到 app-node 節點;
再次 通過 start 將 app-node 上的程序啟動起來。
這樣一個持續性的流水線工作就完成了。
3. 持續集成測試

點擊構建,然后查看后台日志輸出信息:


當返回 SUCCESS 說明構建成功了。也可以通過 Blue Ocean 查看


到這里, 采用 jenkins 構建 java 項目持續集成已經完畢,這里采用的是手動觸發構建,如果需要自動構建可以通過 webHook 來實現。
