第10章 Jenkins部署.md 24 KB

1、部署Springboot应用

1.1 Windows部署项目

执行运行前准备工作:

  • 确保被依赖jar在本地Maven仓库中存在
  • 确保启动服务是可执行jar包,有springbootMaven打包插件

如果Nacos配置文件中存在中文运行命令中需要设置编码

java -Dfile.encoding=UTF-8 -jar service-album.jar --server.port=8181

1.2 Centos部署项目

在宿主机上安装JDK(配置环境变量)

  1. 将课后资料中的jdk-17_linux-x64_bin.rpm上传到jenkins所在服务器

  2. 安装 jdk 17

    >    sudo yum -y install ./jdk-17_linux-x64_bin.rpm
    >    ```
    >
    > 3. 验证
    >
    >    ```shell
    >    java -version
    >    ```
    
    守护进程方式启动Java进程:
    
    

    shell

nohup java -jar app.jar & tail -f xx.log -n 100


查询java进程得到进程ID

shell 方式一:利用jdk自带命令jps查询本地所有java进程 jps 方式二:利用centos提供命令 ps aux|grep java


杀掉java进程

shell kill -9 pid


### 1.3 Docker开启远程访问

将构建的镜像自动上传到服务器。需要开放 Docker 的端口,让我们在本地能连接上服务器的 Docker,这样,才能上传构建的镜像给 Docker。在部署环境服务器修改Docker 的服务文件

sh vim /usr/lib/systemd/system/docker.service


修改前 ExecStart 

> 默认的配置如下
> ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

修改后 ExecStart 

shell ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock


【**注意**】2375 端口是 Docker 默认的端口,可以换成其他未被使用过的端口。

重启 Docker

shell systemctl daemon-reload systemctl restart docker


### 1.4 Docker-maven插件打包镜像

准备工作:

shell 1.将课后资料中JDKDocker镜像压缩tar包上传到服务器 2.通过命令解压jdk镜像到本地 docker load -i jdk17.tar


1. 在Maven项目根目录下创建Dockerfile文件

     ![image-20240530151356448](assets/image-20240530151356448.png)

2. Dockerfile文件内容如下:

shell #目的:将当前项目制作为docker镜像 # 基础镜像 本地不存在镜像就会自动下载镜像 FROM openjdk:17-jdk-alpine # 作者 MAINTAINER atguigu # 执行shell命令:在镜像中创建文件夹 用于存放jar包 RUN mkdir -p /workspace/java/demo # 复制jar包到镜像中 COPY target/app.jar /workspace/java/demo/app.jar # 启动jar包执行命令 ENTRYPOINT ["java", "-jar", "/workspace/java/demo/app.jar"] # 设置环境变量 CMD ["--spring.profiles.active=dev"] # 暴露端口 EXPOSE 8080


3. pom.xml导入插件

xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"

        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.atguigu.docker</groupId>
   <artifactId>springboot_docker_docker</artifactId>
   <version>1.0</version>

   <properties>
       <maven.compiler.source>17</maven.compiler.source>
       <maven.compiler.target>17</maven.compiler.target>
       <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
   </properties>

   <parent>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-parent</artifactId>
       <version>3.0.5</version>
       <!-- 版本对应: https://start.spring.io/actuator/info -->
   </parent>


   <dependencies>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-web</artifactId>
       </dependency>
       <dependency>
           <groupId>org.projectlombok</groupId>
           <artifactId>lombok</artifactId>
       </dependency>
   </dependencies>

   <build>
       <finalName>app</finalName>
       <plugins>
           <plugin>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-maven-plugin</artifactId>
           </plugin>
           <plugin>
               <groupId>com.spotify</groupId>
               <artifactId>docker-maven-plugin</artifactId>
               <version>1.2.2</version>
               <executions>
                   <!-- Maven打包后,然后对该包执行 docker build 构建成镜像-->
                   <execution>
                       <id>build-image</id>
                       <phase>package</phase>
                       <goals>
                           <goal>build</goal>
                       </goals>
                   </execution>
               </executions>
               <!-- 配置构建的镜像信息 -->
               <configuration>
                   <!-- 指定远程 DockerAPI地址 -->
                   <dockerHost>http://192.168.200.10:2375</dockerHost>
                   <!-- 构建的镜像名称以及版本号 -->
                   <imageName>${project.artifactId}</imageName>
                   <imageTags>
                       <!--<imageTag>latest</imageTag>-->
                       <imageName>${project.version}</imageName>
                   </imageTags>
                   <!-- Dockerfile的位置;${project.basedir}是项目的根路径-->
                   <dockerDirectory>${project.basedir}</dockerDirectory>
               </configuration>
           </plugin>
       </plugins>
   </build>


4. 在Maven窗口中执行package打包

     ![image-20240530151643391](assets/image-20240530151643391.png)

5. 查看服务器镜像列表

   ![image-20240530155524979](assets/image-20240530155524979.png)

6. 基于镜像进行产生容器

sh docker run -d --name=myapp -p 8080:8080 springboot_docker:1.0


## 2、CI持续集成/CD持续交付

CI/CD被称为持续集成和持续部署

### 2.1 devops概述

在最开始的编程工作者,开发人员就是运维人员。随着软件开发复杂度不断增加,技术团队角色逐渐 增多(如开发工程师、运维工程师、测试工程师等),这种情况就导致组织里充斥着「部门墙」,大家 都自行其事,形成了一种天然壁垒。在非DevOps开发运维中,开发员创建代码,在他们自己的系统上对其进行测试,通过QA【质量保证部门】运行并将其推送到运行维护操作中。由于运维(Ops)团队无法承受对其系统进行**频繁更改**,因此新代

码通常并不兼容。因此运维将代码发回给开发员而他们又必须又得从头开发,然后循环往复给两个团队带来了相互隔离的现象,为此,没有太多关于是什么原因导致代码不兼容的交流而带来各司其职不负责任的结果。

DevOps专注于消除开发与运维团队之间的这种隔阂,从而在不影响质量的情况下促进更快的交付。 DevOps消除了将开发和运维团队限制在孤岛中的情况。DevOps也是一种开发哲学**理念**,它使整个团队和组织的工作变得更轻松。DevOps还需要协作才能成功而不仅是开发和运维,QA和安全团队通常也需要将自己集成到其中,以实现快速交付完美的软件产品。

打通整个链路:开发工具集、运维工具集、监控工具集、项目进度工具集

![image-20230226214239449](assets/image-20230226214239449.png) 



DevOps元素周期表

https://devops.phodal.com/home

### 2.2 CI/CD简介

CI/CD是DevOps把理论变为现实的核心有效方法与方案。

**CI**(Continuous Integration):CI(持续集成)是一种实践,开发员定期将代码推送到共享存储库,通常一天几次。每次“推送”都会自动验证,并在没有任何错误的情况下与主分支集成。定期集成允许在早期测试和调试小批量代码,这样就不会在开发生命周期的后期阶段出现重大问题。

![image-20230226213054231](assets/image-20230226213054231.png)  

- 部署以前的所有步骤:
- 把我们写的功能,持续的集成到整个系统,方便联调、测试;
- 最多部署到测试环境

**CD**(Continuous Delivery 和 Continuous Deployment):CD(持续交付、持续部署)可确保代码始终准备好交付或部署,其中包括所有更改——新功能、错误修复、配置更改等。通过CI实现推送代码、测试代码并将其自动合并到主分支。无论一天内集成多少次代码,即使数量是数千也可轻松实现。此处的目的是始终拥有已通过必要测试的可部署、无错误的产品。

![image-20230226213618681](assets/image-20230226213618681.png) 

- 交付:产品交付给客户使用
- 交付的N种方式
  - 部署(Deploy):把产品部署到服务器;  `CD(Continuous Deployment): 持续部署`
  - 下载(Download):
  - 增量更新(Update):
  - 推送升级(OTA):
  - 服务升级(Service):
  - 合同更新:
  - 虚拟产品:

### 2.3 完整CI/CD流程

完整的CI/CD流程如下所示:

![image-20230226205253234](assets/image-20230226205253234.png) 

并且整个CI/CD的过程完全可以实现自动化,开发人员只需要将代码推送到远程仓库,后期的所有阶段都可以靠自动化完成。

1、`需求管理、项目管理`:jira、禅道...

- 开发人员每天去`领任务`
- 项目经理每天去`发任务`
- 产品经理每天去`分析需求`
- 测试人员每天去`提bug`
- ...

2、`IDE`: Eclipse、Idea、VSCode...

- 开发功能

3、`代码仓库`: svn、github、Gitee(私有化git仓库-gitlab)

- 每天开发功能、提交、推送、合并

4、`构建`: maven、npm、go mod、cargo、makefile...

- 编译、打包...

5、`静态代码分析`:sonarqube

- 代码质量分析、漏洞分析: fastjson

java public void register(String passwd){

if("123456".equals(passwd)){
    //简单密码,是否确认使用; 
}

}


6、`单元测试`: Junit

7、`制品`:

- 把软件编译、打包成最终的软件包: `app-v1.jar`、`app-v2.jar`、`app-v3.jar`
- 把制品保存到 `制品库`: 对历史版本的集合,方便应急回退;
  - 私有仓库: Nexcus、JFrog

8、`构建推送镜像`:

- 打包制作成docker镜像。`docker build -f Dockerfile -t aaa:v1 .`
- 把镜像推送仓库: `docker hub`,`harbor`

9、`部署到K8s`

- kubectl、kubesphere、xxx: 应用部署
- 规划网络: Ingress/Service

10、`监控和运维`: promethus...

- 配合监控、预警软件:对整个平台进行监控管理;

Jenkins: 把2-10步进行自动化;

## 3、Jenkins工具

### 3.1 Jenkins入门

#### 3.1.1 Jenkins简介

Jenkins是一个开源的、可扩展的持续集成、交付、部署(软件/代码的编译、打包、部署)的基于web界面的平台。通过Jenkins可以实现自动化的持续集成和持续部署。

![image-20230226214711906](assets/image-20230226214711906.png) 

官网:https://www.jenkins.io/

中文社区网:https://www.jenkins-zh.cn/

官方文档:https://jenkins.io/zh/doc/

#### 3.1.2 Jenkins安装

具体步骤如下所示:

1、注意:此时安装的时候如果是阿里的docker加速器,不会下载最新版本jenkins或手动导入Jenkins镜像

shell docker load -i jenkins.tar


2、使用docker安装jenkins

shell docker run \ -u root \ -d \ --restart=always \ -p 8888:8080 \ -p 50000:50000 \ --name jenkins \ --platform linux/amd64 \ -v jenkins-data:/var/jenkins_home \ -v /var/run/docker.sock:/var/run/docker.sock \ -v $(which docker):/usr/bin/docker \ jenkins/jenkins:2.426.3


3、Jenkins国内插件源配置:https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json

访问路径: http://192.168.200.10:8888/

4、导入并解压资料中plugins压缩包 重启jenkins 将课后资料中plugins目录下所有内容复制到jenkins挂载目录

/var/lib/docker/volumes/jenkins-data/_data/plugins


5、重启jenkins服务

docker restart jenkins


6、第一次访问需要获取密码

````shell
# 查看初始密码
cat  /var/lib/docker/volumes/jenkins-data/_data/secrets/initialAdminPassword
````

![image-20230227133338564](assets/image-20230227133338564.png) 

7、进入容器内部查看jenkins服务密码 。按照提示选择**推荐安装插件**:(自动加载本地插件)

![image-20230227133610945](assets/image-20230227133610945.png) 

#### 3.1.3 Jenkins界面介绍

Jenkins主界面:

![image-20230227221741986](assets/image-20230227221741986.png) 

我的视图:展示的是当前用于对jenkins可操作的权限

blue Occean:查看构建历史的漂亮界面

#### 3.1.4 Jenkins入门案例

具体步骤:

1、创建自由风格的构建任务

2、指定构建过程要执行的操作

![image-20230729233510125](assets/image-20230729233510125.png)

shell echo "hello jenkins" pwd ls /


3、任务创建好了以后回到首页运行该任务

![image-20230227223330836](assets/image-20230227223330836.png) 

执行构建任务

4、查看历史任务构建情况

选择任务,查看历史构建

![image-20230227223427292](assets/image-20230227223427292.png) 



打开Blue occean查看历史构建任务

![image-20230227223539811](assets/image-20230227223539811.png) 

#### 3.1.5 流水线任务

之前采用Jenkins的自由风格构建的项目,每个步骤流程都要通过不同的方式设置,并且构建过程中整体流程是不可见的,无法确认每个流程花费的时间,并且问题不方便定位问题。

Jenkins的Pipeline可以让项目的发布整体流程可视化,明确执行的阶段,可以快速的定位问题。并且整个项目的生命周期可以通过一个Jenkinsfile文件管理,而且Jenkinsfile文件是可以放在项目中维护。

创建一个流水线任务,并指定流水线任务脚本

![image-20230227224234410](assets/image-20230227224234410.png) 



流水线语法介绍:

groovy pipeline { //开始一个流水线

agent any  //任何代理都可以执行这个流水线(集群【主+从jenkin[代理节点]】)

stages {  //阶段s
    stage('拉取代码') { //每个阶段
        steps { //步骤
            echo '通过git插件拉取-拉取代码完成'
            sh 'pwd'
        }
    }
    stage('编译构建') { //每个阶段
        steps {
            echo '通过Maven插件对项目源码进行-编译构建'
            sh 'ls /'
        }
    }
    stage('代码质量分析') { //每个阶段
        steps {
            echo '代码质量分析'
            sh 'echo 1111'
        }
    }
    stage('单元测试') { //每个阶段
        steps {
            echo '单元测试'
        }
    }

    stage('制作镜像') { //每个阶段
        steps {
            echo '制作镜像'
        }
    }
    stage('部署到k8s') { //每个阶段
        steps {
            echo '部署到k8s'
        }
    }
}

}




流水线语法查看:

![image-20230227224437888](assets/image-20230227224437888.png) 

### 3.2 部署项目

#### 3.2.1 流水线任务创建

以部署deploy项目为例,先将项目上传到gitee

具体步骤如下所示:

1、在deploy项目目录下创建一个Jenkinsfile文件,在该文件中通过定义流水线任务

2、推送代码到Gitee

3、在jenkins中创建一个流水线任务

4、配置Gitee仓库的地址

![image-20230228233731503](assets/image-20230228233731503.png) 

5、运行流水线任务查看构建控制台输出,可以看到代码已经拉取下来了

可以通过在服务器中jenkins安装目录下查看workspace,查看Gitee源代码是否下载成功

#### 3.2.2 其他环境搭建

1、在宿主机上安装JDK(配置环境变量)

> 1. 将课后资料中的jdk-17_linux-x64_bin.rpm上传到jenkins所在服务器
>
> 2. 安装 jdk 17
>
>    ```shell
>    sudo yum -y install ./jdk-17_linux-x64_bin.rpm
>    ```
>
> 3. 验证
>
>    ```shell
>    java -version
>    ```

2、在宿主机上安装Maven(配置环境变量)、配置阿里云镜像仓库地址  在/root目录下创建develop文件夹

>1. 在jenkins所在服务器创建目录用于存放Maven程序及Maven本地仓库
>
>  ```shell
>  mkdir -p /root/develop/maven/
>  mkdir -p /opt/repo/
>  ```
>
>2. 将课后资料中的apache-maven-3.5.4-bin.tar.gz上传到服务器 /root/develop/maven/目录下
>
>3. 解压
>
>  ```shell
>  tar -zxvf apache-maven-3.5.4-bin.tar.gz 
>  ```
>
>4. Maven程序安装目录:/opt/maven/apache-maven-3.5.4
>
>5. 修改Maven_HOME/conf/settings文件 配置本地仓库位置及阿里云Maven中央仓库
>
>  ```xml
>  <localRepository>/opt/repo</localRepository>
>  
>  
>  <mirror>
>      <id>alimaven</id> 
>      <name>aliyun maven</name> 
>      <url>http://maven.aliyun.com/nexus/content/groups/public/</url> 
>      <mirrorOf>central</mirrorOf> 
>  </mirror>
>  ```
>
>6. 配置环境变量
>
>  ```shell
>  vim /etc/profile
>  
>  #添加如下信息
>  export MAVEN_HOME=/root/develop/maven/apache-maven-3.5.4
>  export PATH=$PATH:$JAVA_HOME/bin:$MAVEN_HOME/bin
>  ```
>
>7. 加载配置
>
>  ```
>  source /etc/profile
>  ```
>
>8. 验证
>
>  ```shell
>  mvn -v
>  ```

3、给Jenkins配置全局maven:

![image-20230730112851091](assets/image-20230730112851091.png)

![image-20231116163230354](assets/image-20231116163230354.png)

4、此时配置全局MAVEN环境变量的时候失败,原因是因为并没有将本地maven环境挂载到容器的jenkins中

重新创建jenkins的docker容器

shell docker run \ -u root \ -d \ --restart=always \ -p 8888:8080 \ -p 50000:50000 \ --name jenkins \ --platform linux/amd64 \ -v jenkins-data:/var/jenkins_home \ -v /root/develop/maven/apache-maven-3.5.4:/root/develop/maven/apache-maven-3.5.4 \ -v /opt/repo:/opt/repo \ -v /var/run/docker.sock:/var/run/docker.sock \ -v $(which docker):/usr/bin/docker \ jenkins/jenkins:2.426.3


5、jenkins配置MAVNE环境变量

系统配置:

![image-20230730123533564](assets/image-20230730123533564.png)

全局属性菜单 将环境变量勾选上

![image-20230730123659064](assets/image-20230730123659064.png)

键值对列表点击新增按钮:

键:MAVEN_HOME 值:/root/develop/maven/apache-maven-3.5.4

键:PATH+EXTRA 值:$MAVEN_HOME/bin

![image-20230730130606736](assets/image-20230730130606736.png)

#### 3.2.3 项目编译打包(Docker镜像)

groovy /实现流水线核心文件:定义发布版本每个步骤/ pipeline { //开始一个流水线

agent any  //任何代理都可以执行这个流水线(集群【主+从jenkin[代理节点]】)


parameters {
    string(name: 'PRODUCT_VERSION', defaultValue: '1.0', description: '商品服务版本号')
}


stages {  //阶段s
    stage('编译构建准备工作') { //每个阶段
        steps {
            echo '编译构建清理'
            sh 'mvn clean'
        }
    }
    stage('构建同时制作镜像') { //每个阶段
        steps {
            echo '编译构建(打jar包)制作镜像,d上传镜像服务器'
            sh 'mvn package'
        }
    }
    stage('部署到k8s') { //每个阶段
        steps {
            echo '部署到服务器采用Docker方式运行容器'
            sh 'docker rm -f deploy-atguigu || true'
            sh "docker run -di --name deploy-atguigu -p 9999:8080 springboot_docker_demo:${params.PRODUCT_VERSION}"
        }
    }
}

}


进行构建测试。第一次执行需要耐心等待

![image-20230730132812916](assets/image-20230730132812916.png)

**注意**:

shell 在使用Jenkins部署Spring Boot项目时,构建 报xxxxx.RELEASE.pom.part.lock (No such file or directory) and ‘parent.relativePath’ points at wrong local POM的错误造成这个问题的原因是,使用Jenkins用户没有访问权限maven的本地仓库,所造成的


效果如下图所示

![image-20230730160030983](assets/image-20230730160030983.png)



### 3.3 其他使用方式

#### 3.3.1 参数化构建

官方文档地址:https://www.jenkins.io/zh/doc/book/pipeline/syntax/

具体步骤:

1、定义参数

groovy parameters { string(name: 'PRODUCT_VERSION', defaultValue: 'V1.0', description: '商品服务版本号') }


2、使用参数 

注意: 之前pipeline脚本中sh使用的是单引号  此处是使用双引号

groovy stage('制作镜像') {

        steps {
            sh "pwd;docker build -t deploy:${params.PRODUCT_VERSION} -f Dockerfile ."
        }
    }
    stage('部署到k8s') {
        steps {
            sh 'docker rm -f deploy-atguigu || true'
            sh "docker run -di --name deploy-atguigu -p 9999:8080 deploy:${params.PRODUCT_VERSION}"
        }
    }

3、本次演示之前需要将之前的deploy镜像手动删除 才能生效,实际生产环境下 删除动作可以通过shell脚本自动删除

4、执行效果

![image-20230730172258675](assets/image-20230730172258675.png)

![image-20230730173514260](assets/image-20230730173514260.png)

docker ps -a 查看镜像

![image-20230730173608407](assets/image-20230730173608407.png)



为了提高maven编译的速度,可以将maven打包过程中测试流程关闭

````shell
mvn clean package -DskipTests=true
````

#### 3.3.2 并行任务

groovy stage('代码质量分析') { //每个阶段

        parallel{
            stage('Branch A'){
                steps {
                    echo '代码质量分析--商品'
                    sh 'echo'
                }
            }
            stage('Branch B'){
                steps {
                    echo '代码质量分析--订单'
                    sh 'echo'
                }
            }
        }
    }
    stage('单元测试') { //每个阶段
        parallel{
            stage('Branch A'){
                steps {
                    echo '单元测试--商品接口'
                }
            }
            stage('Branch B') {
                steps {
                    echo '单元测试--订单接口'
                }
            }
        }

    }

```

执行效果:

image-20230730174856816

3.3.3 发送邮件测试

具体操作如下所示:

1、安装发送邮件插件

image-20230302163907374

2、开通邮箱服务器收发邮件功能

image-20230302172022741

image-20230730180456277

开启的时候需要发送提供手机验证码(扫描两次 发送两次)

3、jenkins系统配置中配置如下内容:

系统管理-->系统配置

  • 系统管理员邮箱(使用网易邮箱18201437328@163.com)

image-20230730181105033

4、邮件通知配置

image-20230730183640734

image-20230730182643482

进行测试:

image-20230302172409860

流水线集成发送邮件功能

stage('发送邮件') { //每个阶段
            steps { //步骤
                echo '邮件发送'
                mail bcc: '', body: 'k8s部署成功,可以开始测试/使用.', cc: 'a@qq.com,b@qq.com', from: 'lvhonglong_java@163.com', replyTo: '', subject: '服务部署成功', to: 'lvhonglong816@126.com'
            }
        }

借助于流水线语法生成流水线片段脚本:

image-20230302172942857

image-20230730184421874