devops-5:从0开始构建一条完成的CI CD流水线

这篇具有很好参考价值的文章主要介绍了devops-5:从0开始构建一条完成的CI CD流水线。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

从0开始构建一条完成的CI CD流水线

前文中已经讲述了静态、动态增加agent节点,以动态的k8s cloud为例,下面就以Maven构建Java程序为例,开始构建出一条完整的CI CD流水线。
实现功能目标:
 1.分别可以根据分支和tag从源码仓库clone代码
 2.拿到源码后开始编译
 3.构建image,并push到镜像仓库
 4.部署到对应k8s集群
 5.部署成功后,钉钉告警
以上是此pipeline实现的功能,后续计划:
 1.通过webhooks实现源码仓库push代码后,自动出发pipeline运行
 2.增加SonarQube代码质量检测步骤
 3.配合argoCD实现自动CD
 
后续文章会陆续更新,敬请期待。
镜像准备
以k8s cloud当做agent的话,肯定需要一个基础镜像,镜像中需要有git、java和maven这些必要的工具环境,当然,可以使用jenkins提供的tools功能来配置工具导入到环境中,例如:
    tools {
        maven 'apache-maven-3.8.6' 
    }
这种方式是比较方便的,但是每到一个新宿主机都要去主动下载一遍,还需要在jenkins中配置下载地址和方式,迁移时也比较麻烦,所以这里就采用一劳永逸的方法,把这些环境都提前打包到agent的镜像中,方便以后使用。
这里选用的基础镜像是jenkins官方的agent镜像:
docker pull jenkins/agent:latest
这个官方镜像内已经包含git、java环境,以及后边需要和jenkins master建立连接的agent.jar包,所以我们只需再将maven包打包进去即可。
 
maven工具包的准备
官方下载maven包:
wget https://dlcdn.apache.org/maven/maven-3/3.8.6/binaries/apache-maven-3.8.6-bin.tar.gz
 
maven的配置(可选)
很多java程序会用maven来进行构建,maven中又存在很多依赖组件(常用的是jar包、war包、pom等,也可把Zip包等通过POM文件定义为依赖组件),这个时候就会有一个仓库的概念,这个仓库分为三种类型,即:
  1. central:中央仓库,是由Maven社区提供的资源仓库,它包含了大量的常用程序库组件(jar包)。默认Maven的中央仓库地址为:http://repo1.maven.org/maven2/
  2. local:本地仓库,是存放maven环境本地的一个文件夹,此文件夹在第一次运行Maven命令时就创建了。Maven在执行构建任务时,根据依赖关系从中心仓库、或远程仓库下载依赖组件到本地仓库,然后本地仓库的内容供项目引用。
  3. remote:远程仓库,例如项目需要指定外部其他公司、或开源组织的jar包,这些依赖组件通用性等原因,未纳入Maven中央仓库,这个时候就要手动指定一个私有的远程仓库来拉取依赖。
修改Maven中央仓库地址
一般Maven的中央仓库由于网络问题会访问不到,这个时候可以修改地址为国内的Maven仓库地址或者公司私有的仓库地址,例如阿里的:http://maven.aliyun.com/nexus/content/groups/public
修改步骤是要修改apache-maven-3.8.6/conf/settings.xml文件中以下字段:
devops-5:从0开始构建一条完成的CI CD流水线
修改为:
    <mirror>
      <id>nexus-aliyun</id>
      <mirrorOf>central</mirrorOf>
      <name>Nexus aliyun</name>
      <url>http://maven.aliyun.com/nexus/content/groups/public</url>
    </mirror>
若修改后未生效,可以检查代码pom.xml中是否指定了仓库地址,类似语句:
<repositories>
    <repository>
        <id>springsource-repos</id>
        <name>SpringSource Repository</name>
        <url>http://repo.spring.io/release/</url>
    </repository>
</repositories>
修改Maven本地仓库路径
Maven本地仓库路径默认为 ${user.home}/.m2/repository
devops-5:从0开始构建一条完成的CI CD流水线
可以直接在此进行修改,也可以在构建时用参数指定:
mvn clean install -Dmaven.repo.local=/home/maven/local_repo/
也可以在构建时指定配置文件地址:
mvn clean install -s /home/maven/settings.xml
开始构建镜像
准备好的物料包及Dockerfile:
[root@node01 agent-jenkins]# ls
apache-maven-3.8.6.tar.gz  Dockerfile  jenkins-agent kubectl.tar.gz
这里要说下jenkins-agent这个脚本文件,这个脚本文件也是官方提供的,源码文件在这里:https://github.com/jenkinsci/docker-inbound-agent,这是专门用来agent连接jenkins master的,采用的jnlp的方式。
 
查看Dockerfile内容
[root@node01 agent-jenkins]# cat Dockerfile 
FROM jenkins/agent:latest

USER root

ADD apache-maven-3.8.6.tar.gz /opt/
ADD kubectl.tar.gz /usr/local/bin/
ENV PATH $PATH:/opt/apache-maven-3.8.6/bin/
COPY jenkins-agent /usr/local/bin/
CMD ["/bin/sh","-c","/usr/local/bin/jenkins-agent"]
用于CD环节的工具,这里添加了kubectl命令,可根据需要添加。
 
构建镜像
# docker build -t registry.example.com:5000/jenkins/agent:v1 .
# docker push registry.example.com:5000/jenkins/agent:v1
registry.example.com:5000 是我的私有仓库
 
配置k8s cloud的pod Template
前边镜像准备完毕,下边要准备一个pod yaml模板,来运行每次临时加入和运行job的agent,默认情况下,k8s cloud会有一个名称为jnlp的容器专门来和jenkins master连接,然后我们可以再启动一个容器专门来跑Pipeline的job,但这里有一点要注意,如果pod中有多个容器,我们需要在Pipeline中指定某个在哪个容器中运行,这个具体怎么指定后边再说,我们这里采用覆盖截jnlp容器的方式来实现全部的工作都由一个container来完成,最终pod Template如下:
apiVersion: "v1"
kind: "Pod"
metadata:
  name: jenkins-agent
  namespace: "default"
spec:
  containers:
  - env:
    - name: "MAVEN_HOME"
      value: "/opt/apache-maven-3.8.6/"
    image: "registry.example.com:5000/jenkins/agent:v1"
    imagePullPolicy: "IfNotPresent"
    name: "jnlp"
    resources:
      limits:
        memory: "2G"
        cpu: "1500m"
      requests:
        memory: "1G"
        cpu: "100m"
    volumeMounts:
    - mountPath: "/root/.m2"
      name: "m2"
      readOnly: false
    - mountPath: "/home/jenkins/agent"
      name: "workspace-volume"
      readOnly: false
    - mountPath: "/usr/bin/docker"
      name: "docker-client"
      readOnly: true
    - mountPath: "/var/run/docker.sock"
      name: "docker-engine"
      readOnly: true
  volumes:
  - hostPath:
      path: "/root/.m2"
      type: "DirectoryOrCreate"
    name: "m2"
  - hostPath:
      path: "/home/jenkins"
    name: "workspace-volume"
  - hostPath:
      path: "/usr/bin/docker"
      type: File
    name: "docker-client"
  - hostPath:
      path: "/var/run/docker.sock"
      type: Socket
    name: "docker-engine"
这里有四个volume:
  • m2:这个是用作maven的本地仓库路径,使用hostpath挂载到了本地目录,当然也可以存储到某些共享存储中,目的就是让依赖包只下载一次。
  • workspace-volume:这个是将jenkins的工作目录也使用hostpath挂载。
  • docker-client:docker命令的挂载,用于build、push等命令
  • docker-engine:docker engine的挂载,用于build、push等
 
gitlab项目克隆
simple-java-maven-app项目地址:https://github.com/jenkins-docs/simple-java-maven-app,将此项目克隆到本地gitlab即可。
网访问github慢的话,可以git我的码云:https://gitee.com/vfancloud/simple-java-maven-app.git
 
Pipeline编写
创建凭证
1.代码仓库我们使用前边搭建的gitlab,需要提前将gitlab的用户凭证在Jenkins创建好,方便后边Jenkins下载代码使用:
系统管理—>凭证管理—>创建Username with password类型凭证(id需要记住,Pipeline中会使用)
devops-5:从0开始构建一条完成的CI CD流水线
 
2.我们的服务是部署在k8s集群中,所以还需要目标k8s的kubeconfig凭证,用来管理操控目标k8s:
系统管理—>凭证管理—>创建Secret file类型凭证
devops-5:从0开始构建一条完成的CI CD流水线
一般项目都会有多个环境,所以每个环境的kubeconfig凭证都要提前创建好。
 
3.镜像仓库的账号密码也要提前准备好,Username with password类型即可。
devops-5:从0开始构建一条完成的CI CD流水线
安装插件
一些常用的必须插件,要提前安装:
  1. Git
  2. Git Parameter
  3. DingTalk
  4. build user vars plugin
Pipeline
此Pipeline起一个示例效果,有些功能点可以省略或者选择使用,酌情增删即可:
pipeline {
    agent {
      kubernetes {
        cloud 'kubernetes-internal'  //指定cloud name
        inheritFrom 'jenkins-agent'  //指定podTemplate,新版本已经不再用label指定
        namespace 'default'
      }
    }
    environment {
        GIT_CERT = credentials('vfan-gitlab')  //gitlab用户凭证
        HARBOR_HOST = 'registry.example.com:5000'
        SERVER_NAME = 'simple-java-maven-app'
    }
/*    tools {
        maven 'apache-maven-3.8.6' 镜像有maven环境了,可以不指定
    } */   
    options {
        buildDiscarder(logRotator(numToKeepStr: '10'))  //保持历史构建的最大个数
        timeout(20)  //默认单位分钟,20分钟
        timestamps()  //Pipeline开始时间以及每个step执行开始时间
    }
    parameters {
        choice(
            name: 'GIT_REPO_URL',
            choices: 'http://10.85.122.128:880/vfan/simple-java-maven-app.git',
            description: 'Git Repo example environment'
        )
        choice(
            name: 'GIT_TYPE',
            choices: ['branch', 'tag'],
            description: 'Git Repo example brance'
        )
        choice(
            name: 'GIT_REPO_BRANCE',
            choices: ['master', 'dev', 'test'],
            description: 'Git Repo example brance'
        )
        gitParameter name: 'GIT_TAG',
            type: 'PT_TAG',
            branch: 'master',
            branchFilter: '.*',
            defaultValue: '',
            selectedValue: 'TOP',
            sortMode: 'DESCENDING_SMART',
            listSize: '1',
                description: 'Select you git tag.'
        choice(
            name: 'ENVIRONMENT', 
            choices: ['INT', 'DEV', 'PROD'], 
            description: 'Select deployment environment'
        )
    }
    stages {
        stage('git clone branch') {
            when {
                 expression { params.GIT_TYPE == "branch" }
            }
            steps {
                git(
                    branch: params.GIT_REPO_BRANCE, 
                    credentialsId: env.GIT_CERT, 
                    url: params.GIT_REPO_URL
                )
            }
            post {
                success {
                    sh '''
                    echo "use branch build"
                    git status
                    '''
                }
            }
        }
        stage('git clone tag') {
            when {
                 expression { params.GIT_TYPE == "tag" }
            }
            steps {
              checkout([$class: 'GitSCM', 
              branches: [[name: "${GIT_TAG}"]], 
              userRemoteConfigs: [[credentialsId: env.GIT_CERT, url: params.GIT_REPO_URL]]])
            }
            post {
                success {
                    sh '''
                    echo "use tag build"
                    git status
                    '''
                }
            }
        }
        stage('Maven Build') {
            steps {
                sh 'mvn -B -DskipTests clean package'
            }
        }
        stage('Test') {
            steps {
                sh 'mvn test'
            }
            post {
                always {
                    junit 'target/surefire-reports/*.xml'
                }
            }
        }
        stage('Deliver') {
            steps {
                sh './jenkins/scripts/deliver.sh'
            }
        }
        stage('Docker build && push') {
            steps {
                withCredentials([usernamePassword(credentialsId: 'harbor-auth', passwordVariable: 'HARBOR_PASSWD', usernameVariable: 'HARBOR_USER')]) {
                    sh '''
                        echo "Other operations..."
                        echo "Start building..."
                        date -d "+8 hour" +%Y%m%d_%H%M%S > /tmp/date
                        BUILD_TIME=`cat /tmp/date`
                        docker build --build-arg APP_NAME=simple-java-maven-app -t ${HARBOR_HOST}/${SERVER_NAME}:${GIT_REPO_BRANCE}_${BUILD_TIME} .
                        echo "Build complete."
                        docker login $HARBOR_HOST -u $HARBOR_USER -p $HARBOR_PASSWD
                        docker push ${HARBOR_HOST}/${SERVER_NAME}:${GIT_REPO_BRANCE}_${BUILD_TIME}
                        docker rmi ${HARBOR_HOST}/${SERVER_NAME}:${GIT_REPO_BRANCE}_${BUILD_TIME}
                    '''
                }
            }
        }
        stage('Deploy to k8s'){
            input{
                message "Should we continue deploy?"
                ok "Yes, we should."

            }
            environment {
                // 提前创建好secret file类型的凭据
                KUBE_CONFIG_INT = credentials('mycluster_int')
                // KUBE_CONFIG_DEV = credentials('mycluster_dev')
                // KUBE_CONFIG_PROD = credentials('mycluster_prod')
            }
            steps{
                sh'''
                    BUILD_TIME=`cat /tmp/date`
                    case $ENVIRONMENT in
                        "INT")
                            kubectl set image deployment ${SERVER_NAME} --kubeconfig=${KUBE_CONFIG_INT} app=${HARBOR_HOST}/${SERVER_NAME}:${GIT_REPO_BRANCE}_${BUILD_TIME}
                            kubectl rollout status deployment ${SERVER_NAME} --kubeconfig=${KUBE_CONFIG_INT}
                        ;;
                        "DEV")
                            kubectl set image deployment ${SERVER_NAME} --kubeconfig=${KUBE_CONFIG_DEV} app=${HARBOR_HOST}/${SERVER_NAME}:${GIT_REPO_BRANCE}_${BUILD_TIME}
                            kubectl rollout status deployment ${SERVER_NAME} --kubeconfig=${KUBE_CONFIG_DEV}
                        ;;
                    esac
                    echo "Deployment complete."
                '''
            }
        }
    }
    post { 
        success{ 
            echo 'Deployment succeeded.'
            dingtalk (
                robot: 'myapp-dingding-robot',
                type: 'MARKDOWN',  // 发什么类型的消息,有TEXT、LINK、MARKDOWN、和ACTION_CARD,参考https://jenkinsci.github.io/dingtalk-plugin/guide/pipeline.html
                at: [],
                atAll: false,
                title: 'Jenkins发版成功',
                text: [
                    "## 构建结果:**${currentBuild.result}**",
                    '---',
                    "## 构建信息",
                    '---',
                    "- 项目名称:${SERVER_NAME}",
                    "- 构建环境:${ENVIRONMENT}",
                    "- 构建分支:${GIT_REPO_BRANCE}",
                    "- 构建标签:${GIT_TAG}",
                    "- 项目地址:${GIT_REPO_URL}",
                    "- 构建用户:${env.BUILD_USER}"
                    ],
            //    messageUrl: '',
            //    picUrl: '',
            //    singleTitle: '',
            //    btns: [],
            //    btnLayout: '', 
            //    hideAvatar: false
            )
        }
        failure{
            echo "Deployment failed."
            dingtalk (
                robot: 'myapp-dingding-robot',
                type: 'MARKDOWN',  // 发什么类型的消息,有TEXT、LINK、MARKDOWN、和ACTION_CARD,参考https://jenkinsci.github.io/dingtalk-plugin/guide/pipeline.html
                at: [],
                atAll: false,
                title: 'Jenkins发版失败',
                text: [
                    "## 构建结果:**${currentBuild.result}**",
                    '---',
                    "## 构建信息",
                    '---',
                    "- 项目名称:${SERVER_NAME}",
                    "- 构建环境:${ENVIRONMENT}",
                    "- 构建分支:${GIT_REPO_BRANCE}",
                    "- 构建标签:${GIT_TAG}",
                    "- 项目地址:${GIT_REPO_URL}",
                    "- 构建用户:${env.BUILD_USER}"
                    ],
            //    messageUrl: '',
            //    picUrl: '',
            //    singleTitle: '',
            //    btns: [],
            //    btnLayout: '', 
            //    hideAvatar: false
            )
        }
    }
}

 文章来源地址https://www.toymoban.com/news/detail-419448.html

测试运行Pipeline
devops-5:从0开始构建一条完成的CI CD流水线
运行完成,钉钉也已收到通知,后续更新更多内容。

到了这里,关于devops-5:从0开始构建一条完成的CI CD流水线的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • CI/CD流水线插件在服务质量看护中的实践

    CI/CD 是一种通过在应用开发阶段引入自动化来频繁向客户交付应用的方法。CI/CD 的核心概念是持续集成、持续交付和持续部署。 作为一种面向开发和运维团队的解决方案,CI/CD 主要针对在集成新代码时所引发的问题(亦称:“集成地狱”)。 具体而言,CI/CD 可让持续自动化

    2024年01月23日
    浏览(87)
  • CI/CD---使用新版云效流水线自动部署Java项目

    两大基本前提: 1、有一个自己的云服务器 2、项目代码已经提交到代码仓库,如gitee,github等 为什么需要流水线 1、除了第一次需要新建流水线,配置脚本外,后续所有的部署只需要提交代码后,点击运行流水线就行 。 2、流水线还可以回滚,此功能太过友好了。 3、当然,

    2024年02月06日
    浏览(61)
  • 在 CI/CD流水线中运行自动化单元测试的4个原因

    目录 什么是单元测试? C#中的单元测试示例 我需要在CI/CD 流水线中运行自动化测试吗? 开发人员代码验证反馈循环 预验证 步步为营 减少“另一个开发人员写了这段代码”的问题 单元测试 什么是单元测试? 单元测试是一小段代码,用于测试应用程序编写的代码的逻辑。单

    2024年02月16日
    浏览(91)
  • 你以为搞个流水线每天跑,团队就在使用CI/CD实践了?

    在实践中,很多团队对于DevOps 流水线没有很透彻的理解,要不就创建一大堆流水线,要不就一个流水线通吃。实际上,流水线的设计和写代码一样,需要基于“业务场景”进行一定的设计编排,特别是很多通过“开源工具”搭建的流水线,更需要如此(商业的一体化平台大部

    2024年02月08日
    浏览(52)
  • Azure DevOps构建CICD流水线

    Azure AKS Azure CR Azure DevOps .NET Core示例 Dockerfile deploy.yaml Java示例 Dockerfile deploy.yaml 注册Azure AD应用 打开Azure portal,导航到Azure AD 选择应用注册,点击新注册 输入应用名称,点击注册 创建客户端密码 分配应用订阅的参与者角色 导航到订阅,选择Access control(IAM),点击添加按钮,

    2024年02月09日
    浏览(83)
  • (十六)devops持续集成开发——jenkins流水线构建之邮件通知

    本节内容主要介绍jenkins在流水线任务构建完成后的通知操作,使用jenkins的邮件通知插件完成构建任务结束的通知。一般项目发布都会通知相关的责任人,这样项目发布在出现问题时能够及时的处理。 ①在插件中心安装Email Extension邮件通知插件 ②申请一个发送邮件的邮箱服务

    2024年02月21日
    浏览(63)
  • (十五)devops持续集成开发——jenkins流水线构建策略配置及触发器的使用

    本节内容我们主要介绍在Jenkins流水线中,其构建过程中的一些构建策略的配置,例如通过远程http构建、定时任务构建、轮询SCM构建、参数化构建、Git hook钩子触发构建等,可根据不同的需求完成不同构建策略的配置。 - 构建策略说明: - 测试验证 - 构建说明 - 测试验证 - 配置

    2024年02月21日
    浏览(92)
  • 【jenkins】jenkins流水线构建打包jar,生成docker镜像,重启docker服务的过程,在jenkins上一键完成,实现提交代码自动构建的功能

     【jenkins】jenkins流水线构建打包jar,生成docker镜像,重启docker服务的过程,在jenkins上一键完成,实现提交代码自动构建,服务重启,服务发布的功能。一键实现。非常的舒服。 这是 shell脚本  脚本名称: startup.sh   本脚本的功能是在jenkins 构建完项目后,通过jar包生成dock

    2024年02月11日
    浏览(52)
  • [Gitlab CI] 自动取消旧流水线

    当某一分支开启 Merge Request 后只要提交一次 commit 就会自动创建一个新的流水线,此时之前的 Pipeline 不会被取消,经过下面的设置后可以实现自动取消旧流水线的功能。 ❗️通过提交(commit)触发的同一分支流水线可以自动冗余取消,但是通过手动触发的同一分支流水线不会

    2024年03月12日
    浏览(72)
  • CI-持续集成 — 软件工业“流水线”技术实现

    持续集成(Continuous Integration)是一种软件开发实践。在本系列文章的前一章节已经对其背景及理论体系进行了介绍。本小节则承接前面提出的理论构想进行具体的技术实现。 《Google软件测试之道》: \\\"每天,Google都要测试和发布数百万个源文件,亿万行代码。数以亿计的构建

    2024年02月12日
    浏览(64)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包