一、Jenkins的安装
1、首先在服务器安装好Docker
安装Docker参考:https://blog.51cto.com/u_15410237/6066776
2、在Docker中运行Jenkins
docker run -u root -d -p 8080:8080 -p 50000:50000 -v jenkins-data:/var/jenkins_home -v /etc/localtime:/etc/localtime:ro -v /var/run/docker.sock:/var/run/docker.sock --restart=always jenkinsci/blueocean
-v jenkins-data:/var/jenkins_home:
jenkins的家目录以匿名卷的方式挂载到宿主机-v /etc/localtime:/etc/localtime:ro:
宿主机和容器的时间显示一致-v /var/run/docker.sock:/var/run/docker.sock:
宿主机的/var/run/docker.sock被映射到了容器内,有以下两个作用: 1、在容器内只要向/var/run/docker.sock发送http请求就能和Docker Daemon通信了 2、如果容器内有docker文件,那么在容器内执行docker ps、docker port这些命令,和在宿主机上执行的效果是一样的,因为容器内和宿主机上的docker文件虽然不同,但是他们的请求发往的是同一个Docker Daemon--restart=always:
开机时启动
3、访问jenkins界面
当首次访问新的Jenkins实例时,系统会要求使用自动生成的密码
访问地址:http://localhost:8080 localhost为服务地址
查看容器日志:
docker logs 容器ID
- 安装推荐的插件
先退出一下,再登录进去,会避免很多小bug
二、Jenkins实战
准备一个git项目进行测试
1、在IDEA创建一个项目
2、在IDEA安装gitee插件
3、在gitee创建仓库
注册并登录:https://gitee.com/
4、创建本地git仓库(如果没有装gitee插件)
项目交给git管理
出现commit表示设置git管理成功
git提交时忽略的文件设置
5、推送代码
设置提交代码和拉取代码的地址,地址从步骤3获取
6、开发项目基本功能,并在项目中创建一个Jenkinsfile文件
在jenkins里面创建一个项目
在项目里面创建一个Jenkinsfile文件
Jenkins的基础语法框架如下
//流水线有两种形式:声明式、脚本式
//声明式
pipeline{
//全部的CICD流程都需要在这里定义
//任何一个代理可用就可以执行流水线
agent any
//定义一些环境信息
//定义流水线的加工流程
stages {
//流水线的所有阶段
//根据git地址拉取代码
//1、编译代码
stage('编译') {
steps {
echo "编译"
}
}
//2、测试代码
stage('测试') {
steps {
//
echo "测试"
}
}
//3、打包代码
stage('打包') {
steps {
//
echo "打包"
}
}
//4、部署代码
stage('部署') {
steps {
//
echo "部署"
}
}
}
}
提交代码后,我们来到Jenkins
选择Blue Ocean后选择自己的项目,选择运行后即可构建,出现绿色的则表示构建成功
此时,提交代码后还需要手动构建,我们期望的效果是: 远程的github代码提交了,jenkins流水线自动触发构建。
配置构建触发器
Jenkins配置一个新用户
配置gitee中的webhoots的URL URL组成
http://新创建的用户名:新用户生成的token@服务ip:jenkins端口号/项目构建触发器中提示的地址
配置完成后保存,回到jenkinns后,我们已经发现项目被重新构建,此时,已经可以实现IDEA向git提交代码后,jenkins就开始构建。
7、Jenkins的工作流程
我们准备一个web项目来打包,Jenkins文件如下
//流水线有两种形式:声明式、脚本式
//声明式
pipeline{
//全部的CICD流程都需要在这里定义
//任何一个代理可用就可以执行流水线
agent any
//定义一些环境信息
//定义流水线的加工流程
stages {
//流水线的所有阶段
//根据git地址拉取代码
//1、编译代码
stage('编译') {
//执行docker命令的前提是Jenkins安装docker、docker pipeline插件
//Jenkins原本不支持maven命令,加上自定义代理基础镜像,才可以支持maven命令
agent{
docker 'maven:3-alpine'
}
steps {
//可以定义要做的所有事情
//查看当前目录,在干什么
sh 'pwd && ls -alh'
sh 'printenv'
//检测maven命令是否可以执行
sh 'mvn -version'
//跳过单元测试打包。-Dmaven.test.skip=true:跳过单元测试
//运行mvn clean package时默认是从maven*仓库下载
sh 'mvn clean package -Dmaven.test.skip=true'
}
}
//2、生成镜像
stage('生成镜像') {
steps {
//
echo "生成镜像"
//检测docker命令是否可以正常运行
sh 'docker version'
sh 'pwd && ls -alh'
}
}
//4、部署代码
stage('部署') {
steps {
//
echo "部署"
}
}
}
}
自动部署后,我们发现下载Maven依赖是从maven*仓库下载的,下载速度非常慢
我们把平常配置的setting.xml文件挂载到宿主机,工作原理图如下
- 首先,我们进到找到Jenkins的家目录,进到家目录下面 :docker inspect 容器ID ,查询到挂载在宿主机的Jenkins家目录为:/var/lib/docker/volumes/jenkins-data/_data
- 然后在家目录下创建appconfig目录,来放所有jenkins构建时需要的配置文件,由于在此处,我们需要的是maven的配置文件,我们再在appconfig目录下创建一个maven目录,把setting.xml文件放到此目录下,配置阿里云加速器
<?xml version="1.0" encoding="UTF-8"?>
<settings
xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
<!-- localRepository
| The path to the local repository maven will use to store artifacts.
|
| Default: ${user.home}/.m2/repository
<localRepository>H:\Devsoft\apache-maven-3.6.1\repository</localRepository>
用户目录下的.m2是所有jar包的地方; maven容器内jar包的位置
-->
<localRepository>/root/.m2</localRepository>
<pluginGroups></pluginGroups>
<proxies></proxies>
<servers></servers>
<mirrors>
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
</mirrors>
<profiles>
<profile>
<id>jdk-1.8</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>1.8</jdk>
</activation>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
</properties>
</profile>
</profiles>
</settings>
- 在Jenkinsfile文件中用-s指定要用的settings.xml文件
打包
Jenkinsfile
//流水线有两种形式:声明式、脚本式
//声明式
pipeline{
//全部的CICD流程都需要在这里定义
//任何一个代理可用就可以执行流水线
agent any
//定义一些环境信息
//定义流水线的加工流程
stages {
//流水线的所有阶段
//根据git地址拉取代码
//1、编译代码
stage('编译') {
//执行docker命令的前提是Jenkins安装docker、docker pipeline插件
//Jenkins原本不支持maven命令,加上自定义代理基础镜像,才可以支持maven命令
agent{
docker 'maven:3-eclipse-temurin-8-alpine'
}
steps {
//可以定义要做的所有事情
//查看当前目录,在干什么
sh 'pwd && ls -alh'
sh 'printenv'
//检测maven命令是否可以执行
sh 'mvn -version'
//跳过单元测试打包。-Dmaven.test.skip=true:跳过单元测试
//运行mvn clean package时默认是从maven*仓库下载
//-s /var/jenkins_home :指定settings.xml文件的位置, /var/jenkins_home/appconfig/maven/settings.xml 是容器里面的路径,在指定的settings.xml文件中配置阿里云加速下载
sh 'mvn clean package -s "/var/jenkins_home/appconfig/maven/settings.xml" -Dmaven.test.skip=true '
}
}
//2、生成镜像
stage('生成镜像') {
steps {
//
echo "生成镜像"
//检测docker命令是否可以正常运行
sh 'docker version'
sh 'pwd && ls -alh'
}
}
//4、部署代码
stage('部署') {
steps {
//
echo "部署"
}
}
}
}
- 此时还存在一个问题,就是每次构建都会重新下载maven依赖,我们在代理里面加一个maven的映射仓库,映射到宿主机
Jenkinsfile
//流水线有两种形式:声明式、脚本式
//声明式
pipeline{
//全部的CICD流程都需要在这里定义
//任何一个代理可用就可以执行流水线
agent any
//定义一些环境信息
//定义流水线的加工流程
stages {
//流水线的所有阶段
//根据git地址拉取代码
//1、编译代码
stage('编译') {
//执行docker命令的前提是Jenkins安装docker、docker pipeline插件
//Jenkins原本不支持maven命令,加上自定义代理基础镜像,才可以支持maven命令
agent{
//用完就会杀掉
docker
{
image 'maven:3-eclipse-temurin-8-alpine'
//将maven容器的仓库挂载到宿主机,避免每次下载
args '-v /var/jenkins_home/appconfig/maven/.m2:/root/.m2'
}
}
steps {
//可以定义要做的所有事情
//查看当前目录,在干什么
sh 'pwd && ls -alh'
sh 'printenv'
//检测maven命令是否可以执行
sh 'mvn -version'
//跳过单元测试打包。-Dmaven.test.skip=true:跳过单元测试
//运行mvn clean package时默认是从maven*仓库下载
//-s /var/jenkins_home :指定settings.xml文件的位置, /var/jenkins_home/appconfig/maven/settings.xml 是容器里面的路径
sh 'mvn clean package -s "/var/jenkins_home/appconfig/maven/settings.xml" -Dmaven.test.skip=true '
}
}
//2、生成镜像
stage('生成镜像') {
steps {
//
echo "生成镜像"
//检测docker命令是否可以正常运行
sh 'docker version'
sh 'pwd && ls -alh'
}
}
//4、部署代码
stage('部署') {
steps {
//
echo "部署"
}
}
}
}
构建一次后,在此构建,已经没有了下载maven依赖的动作
构建镜像
- 临时容器导致的问题
- 1、第一次检出代码的目录:
/var/jenkins_home/workspace/java-devops-demo
- 2、使用代理agent时,会运行一个临时的maven容器,临时的容器会被放到一个临时的目录:
/var/jenkins_home/workspace/java-devops-demo@2
,默认就是workspace的内容 - 3、在临时容器里面,运行的
sh 'mvn clean package -s "/var/jenkins_home/appconfig/maven/settings.xml" -Dmaven.test.skip=true '
命令会在临时目录进行工作/var/jenkins_home/workspace/java-devops-demo@2
- 4、此时package的工作目录是:
/var/jenkins_home/workspace/java-devops-demo@2
,所以在临时目录生成了jar包 - 5、每一个stage的开始,工作目录都会回到workspace目录,所以生成镜像阶段又回到了
/var/jenkins_home/workspace/java-devops-demo
目录,这个目录没有jar包,所以需要在打包前先把目录切换到workspace目录 - 6、生成镜像阶段需要在项目的根目录下放一个Dockerfile文件
- 1、第一次检出代码的目录:
FROM openjdk:8-jre-alpine
LABEL maintainer="lori@qq.com"
COPY target/*.jar /app.jar
#设置时区
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone && touch /app.jar
ENV JAVA_OPTS=""
ENV PARAMS=""
ENTRYPOINT [ "sh", "-c", "java -Djava.security.egd=file:/dev/./urandom $JAVA_OPTS -jar /app.jar $PARAMS" ]
Jenkinsfile
//流水线有两种形式:声明式、脚本式
//声明式
pipeline{
//全部的CICD流程都需要在这里定义
//任何一个代理可用就可以执行流水线
agent any
//定义一些环境信息
environment{
WS = "${WORKSPACE}"
}
//定义流水线的加工流程
stages {
stage('检查') {
steps {
//查看当前目录
sh 'pwd && ls -alh'
}
}
//流水线的所有阶段
//根据git地址拉取代码
//1、编译代码
stage('编译') {
//执行docker命令的前提是Jenkins安装docker、docker pipeline插件
//Jenkins原本不支持maven命令,加上自定义代理基础镜像,才可以支持maven命令
agent{
//用完就会杀掉
docker
{
image 'maven:3-eclipse-temurin-8-alpine'
//将maven容器的仓库挂载到宿主机,避免每次下载
args '-v /var/jenkins_home/appconfig/maven/.m2:/root/.m2'
}
}
steps {
//可以定义要做的所有事情
//查看当前目录,在干什么
sh 'pwd && ls -alh'
sh 'printenv'
//检测maven命令是否可以执行
sh 'mvn -version'
//跳过单元测试打包。-Dmaven.test.skip=true:跳过单元测试
//运行mvn clean package时默认是从maven*仓库下载
//在sh 'printenv'命令下,我们可以看到workspace的目录是一个默认的环境变量,所以我们可以取到以后切换目录:${WORKSPACE},但是我们发现cd以后还是临时的目录,没有切换过来,此时,我们需要设置一个全局的环境变量,WS = "${WORKSPACE}"
//-s /var/jenkins_home :指定settings.xml文件的位置, /var/jenkins_home/appconfig/maven/settings.xml 是容器里面的路径
sh 'cd ${WS} && mvn clean package -s "/var/jenkins_home/appconfig/maven/settings.xml" -Dmaven.test.skip=true '
}
}
//2、生成镜像
stage('生成镜像') {
steps {
//
echo "生成镜像"
//检测docker命令是否可以正常运行
sh 'docker version'
sh 'pwd && ls -alh'
sh 'docker build -t java-devops-demo .'
}
}
//4、部署代码
stage('部署') {
steps {
//
echo "部署"
}
}
}
}
部署
- 在部署环节里加docker run命令启动服务容器
Jenkinsfile
//流水线有两种形式:声明式、脚本式
//声明式
pipeline{
//全部的CICD流程都需要在这里定义
//任何一个代理可用就可以执行流水线
agent any
//定义一些环境信息
environment{
WS = "${WORKSPACE}"
}
//定义流水线的加工流程
stages {
stage('检查') {
steps {
//查看当前目录
sh 'pwd && ls -alh'
}
}
//流水线的所有阶段
//根据git地址拉取代码
//1、编译代码
stage('编译') {
//执行docker命令的前提是Jenkins安装docker、docker pipeline插件
//Jenkins原本不支持maven命令,加上自定义代理基础镜像,才可以支持maven命令
agent{
//用完就会杀掉
docker
{
image 'maven:3-eclipse-temurin-8-alpine'
//将maven容器的仓库挂载到宿主机,避免每次下载
args '-v /var/jenkins_home/appconfig/maven/.m2:/root/.m2'
}
}
steps {
//可以定义要做的所有事情
//查看当前目录,在干什么
sh 'pwd && ls -alh'
sh 'printenv'
//检测maven命令是否可以执行
sh 'mvn -version'
//跳过单元测试打包。-Dmaven.test.skip=true:跳过单元测试
//运行mvn clean package时默认是从maven*仓库下载
//在sh 'printenv'命令下,我们可以看到workspace的目录是一个默认的环境变量,所以我们可以取到以后切换目录:${WORKSPACE},但是我们发现cd以后还是临时的目录,没有切换过来,此时,我们需要设置一个全局的环境变量,WS = "${WORKSPACE}"
//-s /var/jenkins_home :指定settings.xml文件的位置, /var/jenkins_home/appconfig/maven/settings.xml 是容器里面的路径
sh 'cd ${WS} && mvn clean package -s "/var/jenkins_home/appconfig/maven/settings.xml" -Dmaven.test.skip=true '
}
}
//2、生成镜像
stage('生成镜像') {
steps {
//
echo "生成镜像"
//检测docker命令是否可以正常运行
sh 'docker version'
sh 'pwd && ls -alh'
sh 'docker build -t java-devops-demo .'
}
}
//4、部署代码
stage('部署') {
steps {
//
echo "部署"
sh 'docker rm -f java-devops-demo-dev'
sh 'docker run -d -p 8888:8080 --name java-devops-demo-dev java-devops-demo'
}
}
}
}
8、Jenkins部署完成后发送邮件通知
- 发送用邮件流程
- 首先在Jenkins的系统管理->系统配置里配置邮件相关信息,配置来源信息如下,在QQ邮箱中获取(我们以QQ邮箱为例)
- 登录QQ邮箱在设置里配置POP3,如果是开启状态,先点关闭,再开启,然后发送短信后会得到一个授权码
- 根据QQ邮箱中【如何使用 Foxmail 等软件收发邮件?】手册操作获取SMTP服务器和端口号
- 我们在Jenkinsfile配置发送邮件内容,内容可以去jenkins的流水线语法里去生成 加到我们的Jenkinsfile文件里
//流水线有两种形式:声明式、脚本式
//声明式
pipeline{
//全部的cicd流程都需要在这里定义
//任何一个代理可用就可以执行流水线
agent any
//定义一些环境信息
environment{
ws = "${workspace}"
}
//定义流水线的加工流程
stages {
stage('检查') {
steps {
//查看当前目录
sh 'pwd && ls -alh'
}
}
//流水线的所有阶段
//根据git地址拉取代码
//1、编译代码
stage('编译') {
//执行docker命令的前提是jenkins安装docker、docker pipeline插件
//jenkins原本不支持maven命令,加上自定义代理基础镜像,才可以支持maven命令
agent{
//用完就会杀掉
docker
{
image 'maven:3-eclipse-temurin-8-alpine'
//将maven容器的仓库挂载到宿主机,避免每次下载
args '-v /var/jenkins_home/appconfig/maven/.m2:/root/.m2'
}
}
steps {
//可以定义要做的所有事情
//查看当前目录,在干什么
sh 'pwd && ls -alh'
sh 'printenv'
//检测maven命令是否可以执行
sh 'mvn -version'
//跳过单元测试打包。-dmaven.test.skip=true:跳过单元测试
//运行mvn clean package时默认是从maven*仓库下载
//在sh 'printenv'命令下,我们可以看到workspace的目录是一个默认的环境变量,所以我们可以取到以后切换目录:${workspace},但是我们发现cd以后还是临时的目录,没有切换过来,此时,我们需要设置一个全局的环境变量,ws = "${workspace}"
//-s /var/jenkins_home :指定settings.xml文件的位置, /var/jenkins_home/appconfig/maven/settings.xml 是容器里面的路径
sh 'cd ${ws} && mvn clean package -s "/var/jenkins_home/appconfig/maven/settings.xml" -Dmaven.test.skip=true '
}
}
//2、生成镜像
stage('生成镜像') {
steps {
//
echo "生成镜像"
//检测docker命令是否可以正常运行
sh 'docker version'
sh 'pwd && ls -alh'
sh 'docker build -t java-devops-demo .'
}
}
//3、部署代码
stage('部署') {
steps {
//
echo "部署"
sh 'docker rm -f java-devops-demo-dev'
sh 'docker run -d -p 8888:8080 --name java-devops-demo-dev java-devops-demo'
}
}
//3、构建报告发送
stage('报告发送') {
steps {
emailext body: '项目构建成功', subject: '流水线项目构建情况', to: '1129979425@qq.com'
}
}
}
}