## jenkins流水线

在上一章，已经将核心的环境给安装了，接下来我们可进行jenkins的流水线配置

> 这里开始配置的前提，需要将推荐插件下载，不安装插件流水线的功能都没有，同时检测`Publish Over SSH`插件是否已经安装，需要这个插件进行远程执行命令

## 配置凭据
我们需要先将密钥配置好，因为我们等下的流水线的git拉去代码要将密钥进行登录

在`系统管理/凭据/系统/全局凭据 (unrestricted)`中添加一个用户名和密码的凭据，这里我们可以填写我们git仓库的的账号即可

## 配置免密登录
这一步至关重要，由于我们会远程向其他服务器执行命名，需要先配置免密登录。

通常来说，jenkins只做拉去代码，打包发布成可执行的包，至于执行包发布给谁，可以通过ssh发送，对应的服务器只需要收到包，解压，然后直接启动即可，如果服务器资源不够，也可以考虑`127.0.0.1`当远程服务器

``` shell
#获取rsa密钥对
ssh-keygen -t rsa\

#将密钥进行拷贝
ssh-copy-id -i /root/.ssh/id_rsa.pub root\@localhost
```
按以上的提示一步一步回车即可

如果提示命令没有找到，需安装openssh客户端
``` shell
yum -y install openssh-clients\
```
## Publish over SSH配置
由于我们使用到这个插件进行命令与文件的传输

需要在`系统管理/System/Publish over SSH`中进行配置这个插件

主要就是针对的上方的免密登录功能

以下详细介绍每一个配置吧~
``` shell
name: 只是一个标识

Hostname: 远程ip，如果是本机可以localhost

Username：远程登录用户名，可以root

Remote Directory：远程传输根目录，待会传输文件的目录会拼接上这个，我是习惯传输到/home下，所以可以填写/home

Key 输入框粘贴 `/root/.ssh/id_rsa` 中的密钥，全部都要粘贴进去哦~
```
保存之前，可以进行测试，看以下是否成功！

## 环境变量配置
如果之前配置的环境变量，不是系统环境变量，需要单独为jenkins赋上

不然执行命令，将提示命令未找到，主要是dotnet与npm

我们可以在`系统管理/System`中的全局属性下有一个`环境变量`
``` shell
key: PATH
value: /usr/share/Modules/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/opt/dotnet:/opt/nodejs/node-v18.13.0-linux-x64/bin
```

### 后端脚本编写

有了环境，我们可以将我们的代码手动发布上传，测试一下是否可以手动执行dotnet运行，如果成功，将说明环境安装成功

之后，我们可以写两个脚本，一个启动、一个关闭，放到我们的程序入口，关于程序的启动和关闭，可以由脚本来控制会减少很多的问题及困难

我们其实已经在程序里带出来了，就是框架中的`start.sh`及`end.sh`

``` shell
#!/bin/bash
./end.sh
nohup dotnet Yi.Abp.Web.dll > /dev/null 2>&1 &
echo "Yi-启动成功!"


#!/bin/bash
kill $(lsof -t -i:19001)
echo "Yi-进程已关闭"

```

编写启动和停止脚本，我们还要给它赋值权限，否则不是一个有效的执行文件

``` shell
chmod +x start.sh
chmod +x end.sh
```

> 这里如果提示：unix编码问题 ^M
可以使用vim进行转码
``` shell
vim test.sh
:set ff=unix
:wq

```


## 流水线编写

好了，到了这步，如果你一切顺利，恭喜你，准备进入流水线的脚本编写了

> 心急吃不了热豆腐，我们得静下心来，这块需要慢慢配置，一点一点调试

首页->新建任务->流水线

> 以下脚本为Yi框架的cicd脚本，后端与前端及各个项目是不一样

我这里已经将脚本编写好，可根据实际情况进行更改，主要是密钥和授权等

### 后端流水线脚本：
``` java
pipeline {
    agent any

    stages {
        stage('git') {
            steps {
                git branch: 'abp', credentialsId: '38c9c74f-8658-4b8d-9ee7-d4c9923ef042', url: 'https://gitee.com/ccnetcore/Yi.git'
                echo '仓库克隆成功'
            }
        }
        stage('build') {
            steps {
                sh """
                cd Yi.Abp.Net8/src/Yi.Abp.Web;
                dotnet publish -c Release;
                """
                echo '构建成功'
            }
        }
        stage('zip') {
            steps {
                sh """
                mkdir -p ./publish
                7za a ./publish/publish_01.zip ./Yi.Abp.Net8/src/Yi.Abp.Web/bin/Release/net8.0/publish/*;
                """
                echo '压缩包成功'
            }
        }
        stage('publish') {
            steps {
                sshPublisher(publishers: [sshPublisherDesc(configName: 'ccnetcore', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '''cd /home/yi/net8
echo 开始解压
unzip -o /home/yi/build/publish_01.zip  -d ./
echo 开始启动
sh start.sh
echo 启动成功''', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: 'yi/build', remoteDirectorySDF: false, removePrefix: 'publish', sourceFiles: 'publish/publish_01.zip')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: true)])
                echo '发布成功'
            }
        }
    }
}

```
### 前端rbac脚本：
``` shell
pipeline {
    agent any

    stages {
        stage('git') {
            steps {
                git branch: 'abp', credentialsId: '38c9c74f-8658-4b8d-9ee7-d4c9923ef042', url: 'https://gitee.com/ccnetcore/Yi.git'
                echo '仓库克隆成功'
            }
        }
        stage('build') {
            steps {
                sh """
                cd Yi.RuoYi.Vue3;
                npm config set registry https://registry.npm.taobao.org;
                npm i;
                npm run build:prod;
                """
                echo '构建成功'
            }
        }
        stage('zip') {
            steps {
                sh """
                mkdir -p ./publish
                7za a ./publish/publish_rbac_01.zip ./Yi.RuoYi.Vue3/dist/*;
                """
                echo '压缩包成功'
            }
        }
        stage('publish') {
            steps {
                sshPublisher(publishers: [sshPublisherDesc(configName: 'ccnetcore', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '''cd /home/yi/rbac
echo 开始解压
unzip -o /home/yi/build/publish_rbac_01.zip  -d ./
echo 替换完成''', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: 'yi/build', remoteDirectorySDF: false, removePrefix: 'publish', sourceFiles: 'publish/publish_rbac_01.zip')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: true)])
                echo '发布成功'
            }
        }
    }
}

```

### 前端bbs脚本
``` shell
pipeline {
    agent any

    stages {
        stage('git') {
            steps {
                git branch: 'abp', credentialsId: '38c9c74f-8658-4b8d-9ee7-d4c9923ef042', url: 'https://gitee.com/ccnetcore/Yi.git'
                echo '仓库克隆成功'
            }
        }
        stage('build') {
            steps {
                sh """
                cd Yi.Bbs.Vue3;
                npm config set registry https://registry.npm.taobao.org;
                npm install;
                npm run build;
                """
                echo '构建成功'
            }
        }
        stage('zip') {
            steps {
                sh """
                mkdir -p ./publish
                7za a ./publish/publish_bbs_01.zip ./Yi.Bbs.Vue3/dist/*;
                """
                echo '压缩包成功'
            }
        }
        stage('publish') {
            steps {
                sshPublisher(publishers: [sshPublisherDesc(configName: 'ccnetcore', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '''cd /home/yi/bbs
echo 开始解压
unzip -o /home/yi/build/publish_bbs_01.zip  -d ./
echo 替换完成''', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: 'yi/build', remoteDirectorySDF: false, removePrefix: 'publish', sourceFiles: 'publish/publish_bbs_01.zip')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: true)])
                echo '发布成功'
            }
        }
    }
}

```

编写完成之后，可以逐步一下一下进行测试，看看哪里有问题再进行更改

> 以上脚本，都是一步一个脚印，一晚一行代码磨出来的，比较适合现在的场景，可推荐使用，坑比较少

## 进阶
后续，你可以尝试`gitlab+jenkins+harbor+docker+k8s`的路线，这块橙子也是搭建过好几次，但需求点过于多，比较费劲，同时一般只有非常大型的项目才用的上，再次就不过多赘述了，想讲实战讲清楚，估计是当前篇幅至少10倍以上，里面的坑我之前pdf简单汇总了一次，大概就有23面以上，现在可能很有很多工具，安装应该没有那么简单了，不过我还暂时没有去接触的场景，如果你想像我一样，可以一起播撒这颗种子，让更多人的收获

## 结语
可以看的出来，一个大家认为很简答的cicd，如果像从零开始一下一下搭建出来，坑还是蛮多的，爬出这些坑也是比较费事，并没有网上说的那么容易

本人这种环境搭建不下10次以上，也只是`无他，熟能生巧而已`

> 搞的多了，也就麻了，水来土挡，坑来我填

最后，如果你这边怀着激动心情，讲上述的过程全部跑成功了,那么恭喜你啦~我亲爱的朋友，这篇文章教程就有它真正的意义了！

