持续集成交付CICD:Jenkins使用基于SaltStack的CD流水线部署前后端应用

news2025/1/11 15:45:12

目录

一、实验

1.Jenkins使用基于SaltStack的CD流水线部署后端应用

2.Jenkins使用基于SaltStack的CD流水线部署前端应用


一、实验

1.Jenkins使用基于SaltStack的CD流水线部署后端应用

(1)GitLab添加Token

(2)Jenkins添加凭据

(3)devops03-env 添加脚本

# sh service.sh devops03-devops-service 1.1.1 9099 start
APPNAME=$1
VERSION=$2
PORT=$3

start(){
    port_result=`netstat -anlpt | grep "${PORT}" || echo false`

    if [[ $port_result == "false" ]];then
        nohup java -jar -Dserver.port=${PORT}  ${APPNAME}-${VERSION}.jar >${APPNAME}.log.txt 2>&1 &
    else
       stop
       sleep 5
       nohup java -jar -Dserver.port=${PORT}  ${APPNAME}-${VERSION}.jar >${APPNAME}.log.txt 2>&1 &
    fi
}


stop(){
    pid=`netstat -anlpt | grep "${PORT}" | awk '{print $NF}' | awk -F '/' '{print $1}'`
    kill -15 $pid
}


check(){
    proc_result=`ps aux | grep java | grep "${APPNAME}" | grep -v grep || echo false`
    port_result=`netstat -anlpt | grep "${PORT}" || echo false`
    url_result=`curl -s http://localhost:${PORT} || echo false `

    if [[ $proc_result == "false" || $port_result == "false" || $url_result == "false" ]];then
        echo "error"
    else
        echo "ok"
    fi
}

case $4 in
    start)
        start
        sleep 5
        check
        ;;

    stop)
        stop
        sleep 5
        check
        ;;
    restart)
        stop
        sleep 5
        start
        sleep 5
        check
        ;;
    check)
        check
        ;;
    *)
        echo "sh service.sh {start|stop|restart|check}"
        ;;
esac

(4)Jenkins给后端项目CD流水线添加参数

(5)Jenkins安装插件HTTP Request

(5) 修改流水线代码

pipeline {
    agent { label "build" }
    stages{
        stage("PullArtifacts"){
            steps{
                script{
                    repoName = "${JOB_NAME}".split("/")[0]
                    env.projectName ="${JOB_NAME}".split("/")[-1].split("_")[0]

                    if ("${env.projectType}" == "maven"){
                        type="jar"
                    }
                    if ("${env.projectType}" == "npm"){
                        type="tar.gz"
                    }
                    PullArtifacts("${env.releaseVersion}","${env.projectName}",repoName,type)

                    env.pkgName="${env.projectName}-${env.releaseVersion}.${type}"
                }
            }
        }
        stage("DeployHost"){
            steps{
                script{
                    print("DeployHost")
                    // 文件内容写到本地
                    response = GetRepoFile(21, "service.sh", "master")
                    writeFile file: 'service.sh', text: "${response}"
                    sh "ls -a "


                    if ("${env.deployTool}" == "saltstack"){

                        targetHosts = "${env.saltHosts}"
                        println(targetHosts)
                        localDeployDir = "/srv/salt/${env.projectName}"
                        sh """
                            [ -d ${localDeployDir} ] || mkdir -p ${localDeployDir}
                            mv service.sh ${env.pkgName} ${localDeployDir}
        
                            # 清理发布目录
                            salt -L "${targetHosts}" cmd.run  "rm -fr ${targetDir}/${env.projectName}/* &&  mkdir -p ${targetDir}/${env.projectName} || echo file is exists"
            
                            # 发布应用
                            salt -L "${targetHosts}" cp.get_file salt://${env.projectName}/${env.pkgName} ${targetDir}/${env.projectName}

                            # 发布启动脚本
                            salt -L "${targetHosts}" cp.get_file salt://${env.projectName}/service.sh ${targetDir}/${env.projectName}

                            # 启动服务
                            salt -L "${targetHosts}" cmd.run  "cd ${targetDir}/${env.projectName} ;source /etc/profile  && sh service.sh ${env.projectName} ${env.releaseVersion} ${env.port} start"

                            # 检查服务
                            sleep 5
                            salt -L "${targetHosts}" cmd.run  "cd ${targetDir}/${env.projectName} ;source /etc/profile  && sh service.sh ${env.projectName} ${env.releaseVersion} ${env.port} check"
                                                        
                           """
                    }
                }
            }
        }
        stage("ServiceCtrl"){
            steps{
                script{
                    print("ServiceCtrl")
                }
            }
        }
        stage("HealthCheck"){
            steps{
                script{
                    print("HealthCheck")
                }
            }
        }
    }
}


//下载制品
def PullArtifacts(version,projectName,repoName,type){
    repoUrl = "http://192.168.204.13:8081/repository"
    pkgPath = "${repoUrl}/${repoName}/${projectName}/${version}/${projectName}-${version}.${type}"
    sh "wget --http-user=admin --http-passwd=Admin123 ${pkgPath} -q"
}

// 封装HTTP
def HttpReq(reqType, reqUrl,reqBody ){
    def gitServer = "http://192.168.204.8:82/api/v4"
    withCredentials([string(credentialsId: '02dce3ff-4e46-4de2-b079-5dd6093d4f64', variable: 'GITLABTOKEN')]) {
        response = httpRequest acceptType: 'APPLICATION_JSON_UTF8',
                consoleLogResponseBody: true,
                contentType: 'APPLICATION_JSON_UTF8',
                customHeaders: [[maskValue: false, name: 'PRIVATE-TOKEN', value: "${GITLABTOKEN}"]],
                httpMode: "${reqType}",
                url: "${gitServer}/${reqUrl}",
                wrapAsMultipart: false,
                requestBody: "${reqBody}"

    }
    return response
}

//获取文件内容
def GetRepoFile(projectId,filePath, branchName ){
    //GET /projects/:id/repository/files/:file_path/raw
    apiUrl = "/projects/${projectId}/repository/files/${filePath}/raw?ref=${branchName}"
    response = HttpReq('GET', apiUrl, "")
    return response.content
}

(6)手动构建流水线

(7)watch命令观察

# watch -n 1 "ps aux | grep 9099"

(8) 成功

(9) GitLab后端项目新建分支

(10)Jenkins后端项目CI流水线手动构建

(11) 成功

(12)Nexus查看

(13)Jenkins手动构建后端项目CD流水线

(14)成功

(15)查看本地目录

# cd /optdevops03-devops-service/
# ls

2.Jenkins使用基于SaltStack的CD流水线部署前端应用

(1)主机安装nginx

1)添加 nginx 到 yum 源中
sudo rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm

2)安装 nginx (在把nginx添加到 yum 源之后,就可以使用 yum 安装了)
sudo yum install -y nginx

3)稍等一会,即可安装完成

4)启动 nginx
sudo systemctl start nginx.service

5)设置 nginx 开机自启动
sudo systemctl enable nginx.service

(2)nginx 配置信息


1)网站文件存放默认位置(Welcome to nginx 页面)
/usr/share/nginx/html

2)网站默认站点配置
/etc/nginx/conf.d/default.conf

3)自定义 nginx 站点配置文件存放目录
/etc/nginx/conf.d/

4)nginx 全局配置文件
/etc/nginx/nginx.conf

5)启动 nginx
service nginx start

6)关闭 nginx
service nginx stop

7)重启 nginx
service nginx restart
service nginx reload

8) 加成nginx
nginx -t

(3)Jenkins新建前端项目CD流水线

(4)添加参数

(5)修改nginx配置文件

# /etc/nginx/nginx.conf
  1 
  2 user  nginx;
  3 worker_processes  auto;
  4 
  5 error_log  /var/log/nginx/error.log notice;
  6 pid        /var/run/nginx.pid;
  7 
  8 
  9 events {
 10     worker_connections  1024;
 11 }
 12 
 13 
 14 http {
 15     include       /etc/nginx/mime.types;
 16     default_type  application/octet-stream;
 17 
 18     log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
 19                       '$status $body_bytes_sent "$http_referer" '
 20                       '"$http_user_agent" "$http_x_forwarded_for"';
 21 
 22     access_log  /var/log/nginx/access.log  main;
 23 
 24     sendfile        on;
 25     tcp_nopush      on;
 26     tcp_nodelay     on;
 27     types_hash_max_size 2048;
 28 
 29 
 30     keepalive_timeout  65;
 31 
 32     #gzip  on;
 33 
 34     include /etc/nginx/conf.d/*.conf;
 35 
 36 
 37 server {
 38     listen 8099;
 39     server_name _;
 40     root /usr/share/nginx/html/devops03-devops-ui;
 41 
 42     # Load configuration files for the default server block.
 43     include /etc/nginx/default.d/*.conf;
 44 
 45     location / {
 46     }
 47 
 48     error_page 404 /404.html;
 49         location = /40x.html {
 50     }
 51 
 52     error_page 500 502 503 504 /50x.html;
 53         location = /50x.html {
 54     }
 55  }

# nginx -t

# curl 127.0.0.1:8099

验证:

(6)修改前端项目CD流水线代码

pipeline {
    agent { label "build" }
    stages{
        stage("PullArtifacts"){
            steps{
                script{
                    repoName = "${JOB_NAME}".split("/")[0]
                    env.projectName ="${JOB_NAME}".split("/")[-1].split("_")[0]

                    if ("${env.projectType}" == "maven"){
                        type="jar"
                    }
                    if ("${env.projectType}" == "npm"){
                        type="tar.gz"
                    }
                    PullArtifacts("${env.releaseVersion}","${env.projectName}",repoName,type)

                    env.pkgName="${env.projectName}-${env.releaseVersion}.${type}"
                }
            }
        }
        stage("DeployHost"){
            steps{
                script{
                    print("DeployHost")


                    if ("${env.deployTool}" == "saltstack"){

                        targetHosts = "${env.saltHosts}"
                        println(targetHosts)
                        localDeployDir = "/srv/salt/${env.projectName}"
                        sh """
                            [ -d ${localDeployDir} ] || mkdir -p ${localDeployDir}
                            mv ${env.pkgName} ${localDeployDir}
        
                            # 清理发布目录
                            salt -L "${targetHosts}" cmd.run  "rm -fr ${targetDir}/${env.projectName}/* &&  mkdir -p ${targetDir}/${env.projectName} || echo file is exists"
            
                            # 发布应用
                            salt -L "${targetHosts}" cp.get_file salt://${env.projectName}/${env.pkgName} ${targetDir}/${env.projectName}
                   
                           """
                    }
                }
            }
        }
        stage("ServiceCtrl"){
            steps{
                script{
                    print("ServiceCtrl")
                    localDeployDir = "/srv/salt/${env.projectName}"

                    if ("${env.projectType}" == "maven") {
                        // 文件内容写到本地
                        response = GetRepoFile(21, "service.sh", "master")
                        writeFile file: 'service.sh', text: "${response}"
                        sh "ls -a "

                        sh """
                             mv service.sh  ${localDeployDir}
                             # 发布启动脚本
                             salt -L "${targetHosts}" cp.get_file salt://${env.projectName}/service.sh ${targetDir}/${env.projectName}
                             
                             # 启动服务
                             salt -L "${targetHosts}" cmd.run  "cd ${targetDir}/${env.projectName} ;source /etc/profile  && sh service.sh ${env.projectName} ${env.releaseVersion} ${env.port} start"
    
                             # 检查服务
                             sleep 5
                             salt -L "${targetHosts}" cmd.run  "cd ${targetDir}/${env.projectName} ;source /etc/profile  && sh service.sh ${env.projectName} ${env.releaseVersion} ${env.port} check"
                            
                            
                        """
                    }

                    if ("${env.projectType}" == "npm") {
                        sh """
                             # 启动服务
                             salt -L "${targetHosts}" cmd.run  "cd ${targetDir}/${env.projectName} ;tar zxf ${env.pkgName}"

                            """


                    }

                }
            }
        }
        stage("HealthCheck"){
            steps{
                script{
                    print("HealthCheck")
                }
            }
        }
    }
}


//下载制品
def PullArtifacts(version,projectName,repoName,type){
    repoUrl = "http://192.168.204.13:8081/repository"
    pkgPath = "${repoUrl}/${repoName}/${projectName}/${version}/${projectName}-${version}.${type}"
    sh "wget --http-user=admin --http-passwd=Admin123 ${pkgPath} -q"
}

// 封装HTTP
def HttpReq(reqType, reqUrl,reqBody ){
    def gitServer = "http://192.168.204.8:82/api/v4"
    withCredentials([string(credentialsId: '02dce3ff-4e46-4de2-b079-5dd6093d4f64', variable: 'GITLABTOKEN')]) {
        response = httpRequest acceptType: 'APPLICATION_JSON_UTF8',
                consoleLogResponseBody: true,
                contentType: 'APPLICATION_JSON_UTF8',
                customHeaders: [[maskValue: false, name: 'PRIVATE-TOKEN', value: "${GITLABTOKEN}"]],
                httpMode: "${reqType}",
                url: "${gitServer}/${reqUrl}",
                wrapAsMultipart: false,
                requestBody: "${reqBody}"

    }
    return response
}

//获取文件内容
def GetRepoFile(projectId,filePath, branchName ){
    //GET /projects/:id/repository/files/:file_path/raw
    apiUrl = "/projects/${projectId}/repository/files/${filePath}/raw?ref=${branchName}"
    response = HttpReq('GET', apiUrl, "")
    return response.content
}

(7)Jenkins手动构建前端项目CD流水线

(8)成功

(9)GitLab前端项目新建分支

(10)Jenkins手动构建前端项目CI流水线

(11)成功

(12)Nexus查看

(13)Jenkins手动构建前端项目CD流水线

(14)命令观察

# watch -n 1 "ls devops03-devops-ui"

# for i in `seq 1000`; do sleep 1 ; curl http://127.0.0.1:8099; echo -e "\n\n\n";done

(15) 查看本地目录

# cd /usr/share/nginx/html/
# ls

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1314116.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据分析的基本步骤

了解过数据分析的概念之后,我们再来说下数据分析的常规步骤。 明确目标 首先我们要确定一个目标,即我们要从数据中得到什么。比如我们要看某个指标A随时间的变化趋势,以期进行简单的预测。 数据收集 当确定了目标之后,就有了取…

RT-DETR 图片目标计数 | 特定目标进行计数

全类别计数特定类别计数如何使用 RT-DETR 进行对象计数 有很多同学留言说想学 RT-DETR 目标计数。那么今天这篇博客,我将教大家如何使用 RT-DETR 进行对象计数。RT-DETR 是一种非常强大的对象检测模型,它可以识别图像中的各种对象。我们将学习如何利用这个模型对特定对象进行…

四十六、Redis哨兵

目录 一、哨兵的作用及原理 1、哨兵的结构和作用如下: 2、服务状态监控 3、选举新的master 4、小结 二、RedisTemplate的哨兵模式 一、哨兵的作用及原理 Redis提供了哨兵(Sentinel)机制来实现主从集群的自动故障恢复。 1、哨兵的结构和作…

11.jvm第三方工具使用实践

目录 概述GCEasy官网jvm内存占用情况关键性能指标堆内存与元空间优化 MAT安装MAT相关概念说明内存泄漏与内存溢出shallow heap及retained heapoutgoing references与incoming referencesDominator Tree GCViewerArthas下载安装与启动jdk8jdk 11jdk11自定义boot jarjdk17 常用命…

FIFO的Verilog设计(三)——最小深度计算

文章目录 前言一、FIFO的最小深度写速度快于读速度写速度等于或慢于读速度 二、 举例说明1. FIFO写时钟为100MHz,读时钟为80Mhz情况一:一共需要传输2000个数据,求FIFO的最小深度情况二:100个时钟写入80个数据,1个时钟读…

怎样下载微博视频而不至于发生“403 Forbidden“现象?

近段时间不知道从什么时候开始,微博视频都不让从网页下载了。以前是看到有想要下载的微博视频,就点进去微博详情页用谷歌浏览器F12进入调试的方式,选“Network”->“Media”->重新F5刷新页面等待调试框里出现链接->在链接上鼠标右键…

Nginx(四层+七层代理)+Tomcat实现负载均衡、动静分离

一、Tomcat多实例部署 具体步骤请看我之前的博客 写文章-CSDN创作中心https://mp.csdn.net/mp_blog/creation/editor/134956765?spm1001.2014.3001.9457 1.1 访问测试多实例的部署 1.2 分别在三个tomcat服务上部署jsp的动态页面 mkdir /usr/local/tomcat/webapps/test vim …

vue中实现PDF文件流预览

代码示例 <template><div class"print"><div v-if"!viewShow" class"opt-box"><div style"height: 700px; overflow: auto;"><el-table :data"tableData" border><el-table-column prop…

如何拍摄超级大像素图片,超级大像素有哪些应用

引言&#xff1a; 在数字摄影领域&#xff0c;超级大像素照片是指通过高像素的相机或拼接多张照片合成的照片。这样的照片具有更高的分辨率&#xff0c;细节更加清晰&#xff0c;绘画质感更强。那么如何拍摄超级大像素照片&#xff0c;超级大像素可以用在哪些领域呢。 一&…

C++使用回调函数的两种方式

一.函数指针 #include <iostream>typedef void (*callback)(int ,int); class MyTest { public:void setCallback(callback cb){m_callback = cb;}void add(int a, int b){m_callback(a, b);}private:callback m_callback; };void onCallback(int a, int b) {std::cout …

设计模式-策略(Strategy)模式

又被称为政策&#xff08;方针&#xff09;模式策略模式(Strategy Design Pattern)&#xff1a;封装可以互换的行为&#xff0c;并使用委托来决定要使用哪一个策略模式是一种行为设计模式&#xff0c;它能让你定义一系列算法&#xff0c;并将每种算法分别放入独立的类中&#x…

【导航栏内容的设置 Objective-C语言】

一、那接下来呢,我们就来做一做,关于导航控制器, 1.设置它顶部的导航栏儿内容的东西, 1)我们刚刚讲过的这个,通过代码去跳转、返回、 2)通过storyboard去跳转、返回、 但是,这两种情况,大家是不是已经注意到,导航栏里面,没有任何内容, 然后呢,返回,这是红色,…

centos下:mysql一些指令+mysql首次修改密码+mysql忘记密码修改

操作 查看mysql运行状态 systemctl status mysqld 停止mysql systemctl stop mysqld 启动mysql systemctl start mysqld 重启mysql systemctl restart mysqld 开启mysql开机自启动 systemctl enable mysqld 关闭mysql开机自启动 systemctl disable mysqld 查看具体的报错日…

动态内存管理,malloc和calloc以及realloc函数用法

目录 一.malloc函数的介绍 malloc的用法 举个例子 注意点 浅谈数据结构里的动态分配空间 二.calloc函数的介绍 三.realloc函数的介绍 四.柔性数组的介绍 为什么有些时候动态内存函数头文件是malloc.h,有些时候却是stdlib.h 一.malloc函数的介绍 malloc其实就是动态开辟…

innerHTML、innerText、textContent有什么区别

innerHTML、innerText、textContent有什么区别 在 HTML 中&#xff0c;innerHTML、innerText、 和textContent是 DOM&#xff08;文档对象模型&#xff09;的属性。它们允许我们读取和更新 HTML 元素的内容。 但它们在包含的内容以及处理 HTML 标签的方式有不同的行为。 读完…

安恒明御安全网关 aaa_local_web_preview文件上传漏洞复现

0x01 产品简介 明御安全网关秉持安全可视、简单有效的理念,以资产为视角,构建全流程防御的下一代安全防护体系,并融合传统防火墙、入侵检测、入侵防御系统、防病毒网关、上网行为管控、VPN网关、威胁情报等安全模块于一体的智慧化安全网关。 0x02 漏洞概述 明御安全网关在…

jmeter,断言:响应断言、Json断言

一、响应断言 接口A请求正常返回值如下&#xff1a; {"status": 10013, "message": "user sign timeout"} 在该接口下创建【响应断言】元件&#xff0c;配置如下&#xff1a; 若断言成功&#xff0c;则查看结果树的接口显示绿色&#xff0c;若…

Spring Boot启动慢如何分析

如果发现项目启动慢&#xff0c;你知道怎么分析慢的原因吗&#xff1f; 分析方法 自定义监听器 SpringApplicationRunListener是Spring Boot中的一个接口&#xff0c;它的作用是在SpringApplication运行的各个阶段提供回调接口&#xff0c;以便我们可以在这些阶段执行自定义…

PPT插件-好用的插件-放映笔、绘图板-大珩助手

放映笔 幻灯片放映时&#xff0c;工具在幻灯片的左下方&#xff0c;本工具在幻灯片的右侧&#xff0c;可以移动&#xff0c;可以方便在右侧讲课时候使用 绘图板 可在绘图板上写签名、绘制图画、写字等等&#xff0c;点画笔切换橡皮擦&#xff0c;点插入绘图&#xff0c;将背景…

jenkins学习19 - pipline 构建项目生成 allure报告并发送邮箱

前言 个人其实一直的不太喜欢用邮箱发送报告&#xff0c;测试报告用邮件通知这都是五六年前的事情了&#xff0c;但有部分小伙伴依然执着于发邮件报告通知。 这里整理了下发邮箱通知的教程。 配置你的邮箱 配置邮箱这一步最繁琐&#xff0c;由于每个人使用的邮箱不一样&…