前提知识:maven,gitlab,sonarqube,Docker,Harbor,java微服务,Jenkins,Nginx
基本流程
项目代码上传到gitlab
创建代码仓库
后端代码提交
加入版本控制:
git:
提交:
点击commit:
添加远程仓库:
推送到远程仓库:
前端代码提交
先安装TortoiseGit软件
创建本地仓库:
push:
代码提交成功:
从Gitlab拉取项目源码
jenkins创建流水线项目:
设置流水线:
生成checkout语法:
参数化构建:
项目创建jenkinsfile并提交:
def git_auth = "ee475541-cfd3-42a8-b8eb-4e8f9ac5c5b7"
def git_url = "http://192.168.1.50:82/root/tensquare_back.git"
node {
stage('拉取代码') {
checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
}
}
部署:
查看项目代码:
ll /var/lib/jenkins/workspace/tensquare_back
拉取代码完毕
SonarQube代码审查
添加Choice Parameter
每个子模块添加sonar-project.properties到根目录
# must be unique in a given SonarQube instance
sonar.projectKey=tensquare_eureka_server
# this is the name and version displayed in the SonarQube UI. Was mandatory prior to SonarQube 6.1.
sonar.projectName=tensquare_eureka_server
sonar.projectVersion=1.0
# Path is relative to the sonar-project.properties file. Replace "" by "/" on Windows.
# This property is optional if sonar.modules is set.
sonar.sources=.
sonar.exclusions=**/test/**,**/target/**
sonar.java.binaries=.
sonar.java.source=1.8
sonar.java.target=1.8
#sonar.java.libraries=**/target/classes/**
# Encoding of the source code. Default is default system encoding
sonar.sourceEncoding=UTF-8
jenkeinsfile添加一个stage 代码审查,注意这里的sonar-scanner和sonarqube不是瞎写的,是根据jenkins配置有关
def git_auth = "ee475541-cfd3-42a8-b8eb-4e8f9ac5c5b7"
def git_url = "http://192.168.1.50:82/root/tensquare_back.git"
node {
stage('拉取代码') {
checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
}
stage('代码审查') {
//引入全局工具配置中的sonarqube-scanner名
def scannerHome = tool 'sonar-scanner'
//引入系统配置中Sonarqube server的名
withSonarQubeEnv('sonarqube'){
sh """
cd ${project_name}
${scannerHome}/bin/sonar-scanner
"""
}
}
}
这里我们就可以通过选择指定的项目来审查项目了:
编译打包微服务
先编译,安装公共子工程
添加一个stage
stage('编译,安装公共子工程') {
sh "mvn -f tensquare_common clean install"
}
Jenkinsfile中再添加一个stage,这样就可以打包指定微服务了。
stage('编译,打包微服务工程') {
sh "mvn -f ${project_name} clean install"
}
我这里打包注册中心微服务:
有可能打包子工程失败:因为本地环境缺少父工程依赖
我们先手动install父工程
再把本地仓库中的父工程依赖移动到服务器对应目录下,再重新打包就好了。
使用Dockerfile编译、生成镜像
利用dockerfile-maven-plugin插件构建docker镜像
每个微服务项目的pom.xml加入该插件
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<version>1.3.6</version>
<configuration>
<repository>${project.artifactId}</repository>
<buildArgs>
<JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
</buildArgs>
</configuration>
</plugin>
每个微服务项目根目录下面建立Dockerfile文件
#FROM java:8
FROM openjdk:8-jdk-alpine
# 传入的参数
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
EXPOSE 10020
ENTRYPOINT ["java","-jar","/app.jar"]
注意每个项目开放端口不一样,注意修改。
修改jenkinsfile:
stage('编译,打包微服务工程') {
sh "mvn -f ${project_name} clean install dockerfile:build"
}
打包结果:
查看本地镜像:
docker images
镜像构建成功
上传镜像到Harbor仓库
添加harbor凭证:(我这里账号记错了,harbor默认账号是admin,后面我改回来了)
拿到凭证id:
生成流水线代码片段:
修改Jenkinsfile:
def git_auth = "ee475541-cfd3-42a8-b8eb-4e8f9ac5c5b7"
def git_url = "http://192.168.1.50:82/root/tensquare_back.git"
def tag = "latest"
//harbor的url
def harbor_url = "192.168.1.52:85"
def harbor_project = "tensquare"
//harbor凭证id
def harbor_auth = "25ca1748-2a03-4acb-a828-863fe805165c"
node {
stage('拉取代码') {
checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
}
stage('代码审查') {
//引入全局工具配置中的sonarqube-scanner名
def scannerHome = tool 'sonar-scanner'
//引入系统配置中Sonarqube server的名
withSonarQubeEnv('sonarqube'){
sh """
cd ${project_name}
${scannerHome}/bin/sonar-scanner
"""
}
}
stage('编译,安装公共子工程') {
sh "mvn -f tensquare_common clean install"
}
stage('编译,打包微服务工程, 上传镜像') {
sh "mvn -f ${project_name} clean install dockerfile:build"
def imageName = "${project_name}:${tag}"
//镜像打上标签
sh "docker tag ${imageName} ${harbor_url}/${harbor_project}/${imageName}"
//推送到Harbor
withCredentials([usernamePassword(credentialsId: "${harbor_auth}", passwordVariable: 'password', usernameVariable: 'username')]) {
//登陆到harbor
sh "docker login -u ${username} -p ${password} ${harbor_url}"
//镜像上传
sh "docker push ${harbor_url}/${harbor_project}/${imageName}"
echo "镜像推送到harbor成功"
}
}
}
部署结果:
查看harbor仓库:
拉取镜像和发布应用
把192.168.1.51的公钥发送给192.168.1.73(这里图里面是53服务器,是因为我后来改了ip地址)
#在192.168.1.51执行
ssh-copy-id 192.168.1.73
jenkins安装publish over ssh插件,可以远程发送shell命令,安装完该插件后,配置Publish over SSH
点击测试
jenkins添加输入端口选项:
在流水线语法出生成流水线片段:要选择sshPublisher
jenkinsfile配置:
def git_auth = "ee475541-cfd3-42a8-b8eb-4e8f9ac5c5b7"
def git_url = "http://192.168.1.50:82/root/tensquare_back.git"
def tag = "latest"
//harbor的url
def harbor_url = "192.168.1.52:85"
def harbor_project = "tensquare"
//harbor凭证id
def harbor_auth = "25ca1748-2a03-4acb-a828-863fe805165c"
node {
stage('拉取代码') {
checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
}
stage('代码审查') {
//引入全局工具配置中的sonarqube-scanner名
def scannerHome = tool 'sonar-scanner'
//引入系统配置中Sonarqube server的名
withSonarQubeEnv('sonarqube'){
sh """
cd ${project_name}
${scannerHome}/bin/sonar-scanner
"""
}
}
stage('编译,安装公共子工程') {
sh "mvn -f tensquare_common clean install"
}
stage('编译,打包微服务工程, 上传镜像') {
def imageName = "${project_name}:${tag}"
//打包、构建镜像
sh "mvn -f ${project_name} clean install dockerfile:build"
//镜像打上标签
sh "docker tag ${imageName} ${harbor_url}/${harbor_project}/${imageName}"
//推送到Harbor
withCredentials([usernamePassword(credentialsId: "${harbor_auth}", passwordVariable: 'password', usernameVariable: 'username')]) {
//登陆到harbor
sh "docker login -u ${username} -p ${password} ${harbor_url}"
//镜像上传
sh "docker push ${harbor_url}/${harbor_project}/${imageName}"
echo "镜像推送到harbor成功"
}
sh "docker rmi ${harbor_url}/${harbor_project}/${imageName}"
sh "docker rmi ${imageName}"
sshPublisher(publishers: [sshPublisherDesc(configName: 'master_server', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "/opt/jenkins_shell/deploy.sh $harbor_url $harbor_project $project_name $tag $port", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
}
}
192.168.1.73服务器上:
mkdir /opt/jenkins_shell
vi deploy.sh
chmod 755 deploy.sh
脚本内容如下:
#! /bin/sh
#接收外部参数
harbor_url=$1
harbor_project_name=$2
project_name=$3
tag=$4
port=$5
imageName=$harbor_url/$harbor_project_name/$project_name:$tag
echo "$imageName"
#查询容器是否存在,存在则删除
containerId=`docker ps -a | grep -w ${project_name}:${tag} | awk '{print $1}'`
if [ "$containerId" != "" ] ; then
#停掉容器
docker stop $containerId
#删除容器
docker rm $containerId
echo "成功删除容器"
fi
#查询镜像是否存在,存在则删除
imageId=`docker images | grep -w $project_name | awk '{print $3}'`
if [ "$imageId" != "" ] ; then
#删除镜像
docker rmi -f $imageId
echo "成功删除镜像"
fi
# 登录Harbor
docker login -u admin -p Harbor12345 $harbor_url
# 下载镜像
docker pull $imageName
# 启动容器
docker run -di -p $port:$port $imageName
echo "容器启动成功"
部署eureka:
部署成功后,访问eureka主页成功
#依次手动部署完所有的服务后
docker images
部署前端静态网站
192.168.1.73服务器,安装nginx:
yum install -y epel-release
yum install -y nginx
修改nginx默认端口为9090
vi /etc/nginx/nginx.conf
关闭selinux:
#临时更改
setenforce 0
#永久更改
vi /etc/selinux/config
SELINUX=disabled
启动nginx:
systemctl enable nginx
systemctl start nginx
访问9090,安装成功
jenkins安装nodejs插件后,在全局插件配置nodejs
创建前端项目流水线(tensquare_front),参数化项目
pipeline script:
def git_auth = "ee475541-cfd3-42a8-b8eb-4e8f9ac5c5b7"
def git_url = "http://192.168.1.50:82/root/tensquare_front.git"
node {
stage('拉取代码'){
checkout([$class: 'GitSCM', branches: [[name: '*/${branch}']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
}
stage('打包,部署网站'){
nodejs('nodejs12') {
sh '''
npm install
npm run build
'''
}
sshPublisher(publishers: [sshPublisherDesc(configName: 'master_server', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '/usr/share/nginx/html', remoteDirectorySDF: false, removePrefix: 'dist', sourceFiles: 'dist/**')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
}
}
第一次部署,会有点慢,最后部署成功!