13、基于Jenkins+K8s构建DevOps自动化运维管理平台(下)

目录

一、Jenkins Pipeline 语法介绍

1、 1JenkinsPipeline介绍;

1、 2为什么用JenkinsPipeline?;

1、 3Jenkinspipeline入门;

二、Pipeline 声明式语法实战讲解

三、Pipeline Scripted 语法

3、 1流程控制;

3、 2Declarativepipeline和Scriptedpipeline的比较;

四、基于 Jenkins+k8s+nexus+gitlab+harbor+sonarqube+springloud 构建 DevOps

4、 1安装码扫描工具sonarqube;

4、 2Jenkins界面添加harbor凭据;

4、 2.1添加凭据;

4、 2.2编写jenkinspipeline;

4、 3安装nexus;

4、 3.1安装nexus;

4、 3.2在pom.xml文件中声明发布的宿主仓库和release版本发布的仓库;

4、 3.3在settings.xml文件中配置由于用Maven分发构件到远程仓库需要认证,须要在~/.m2/settings.xml或者中加入验证信息;

4、 4安装gitlab;

4、 4.1安装gitlab;

4、 4.2登录gitlab;

4、 4.3在Jenkins安装插件;

4、 4.4在Jenkins上添加gitlab凭据;

4、 4.5在gitlab上新建项目;

4、 4.6配置公钥;

4、 4.7提交本地代码到gitlab;

4、 5测试跑通流程;


本篇文章所用到的资料文件下载地址:microservic-test.zip-kubernetes文档类资源-CSDN下载

一、Jenkins Pipeline 语法介绍

1.1 Jenkins Pipeline 介绍

Jenkins pipeline (流水线)是一套运行于 jenkins 上的工作流框架,将原本独立运行于单个或者多个节点的任务连接起来,实现单个任务难以完成的复杂流程编排与可视化。它把持续提交流水线(Continuous Delivery Pipeline)的任务集成到 Jenkins 中。

pipeline 是 jenkins2.X 最核心的特性, 帮助 jenkins 实现从 CI 到 CD 与 DevOps 的转变。

持续提交流水线(Continuous Delivery Pipeline)会经历一个复杂的过程:从版本控制、向用户和客户提交软件,软件的每次变更(提交代码到仓库)到软件发布(Release)。这个过程包括以一种可靠并可重复的方式构建软件,以及通过多个测试和部署阶段来开发构建好的软件(称为Build)。

总结:

  • Jenkins Pipeline 是一组插件,让 Jenkins 可以实现持续交付管道的落地和实施。
  • 持续交付管道(CD Pipeline)是将软件从版本控制阶段到交付给用户或客户的完整过程的自动化表现。
  • 软件的每一次更改(提交到源代码管理系统)都要经过一个复杂的过程才能被发布。

1.2 为什么用 Jenkins Pipeline?

本质上,Jenkins 是一个自动化引擎,它支持许多自动模式。 Pipeline 向 Jenkins 中添加了一组强大的工具,支持简单的 CI 到全面的 CD pipeline。通过对一系列的相关任务进行建模,用户可以利用 pipeline 的很多特性:

1、 代码:Pipeline以代码的形式实现,使团队能够编辑,审查和迭代其CD流程;
2、 可持续性:Jenkins重启或者中断后都不会影响PipelineJob;
3、 停顿:Pipeline可以选择停止并等待人工输入或批准,然后再继续Pipeline运行;
4、 多功能:Pipeline支持现实复杂的CD要求,包括循环和并行执行工作的能力;
5、 可扩展:Pipeline插件支持其DSL的自定义扩展以及与其他插件集成的多个选项;

DSL是 Domain Specific Language 的缩写,中文翻译为领域特定语言(下简称 DSL);而与 DSL 相对的就是 GPL,这里的 GPL 并不是我们知道的开源许可证,而是 General Purpose Language 的简称,即通用编程语言,也就是我们非常熟悉的 Objective-C、Java、Python 以及 C 语言等等。

1.3 Jenkins pipeline 入门

pipeline 脚本是由 groovy 语言实现的,但无需专门学习 groovy。

pipeline 支持两种语法:

  • -Declarative:声明式
  • -Scripted pipeline :脚本式

声明式pipeline 语法规则官网:流水线语法

声明式语法包括以下核心流程:

1、 pipeline:声明其内容为一个声明式的pipeline脚本;
2、 agent:执行节点(job运行的slave或者master节点);
3、 stages:阶段集合,包裹所有的阶段(例如:打包,部署等各个阶段);
4、 stage:阶段,被stages包裹,一个stages可以有多个stage;
5、 steps:步骤,为每个阶段的最小执行单元,被stage包裹;
6、 post:执行构建后的操作,根据构建结果来执行对应的操作;

根据上面流程创建一个简单的 pipeline:

pipeline{
    agent any
    stages{
        stage("This is first stage"){
            steps("This is first step"){
                echo "I am xianchao"
            }
        }
    }
    post{
        always{
            echo "The process is ending"
        }
    }
}

语法解释

  • **Pipeline:**作用域:应用于全局最外层,表明该脚本为声明式 pipeline。是否必须:必须
  • agent:作用域:可用在全局与 stage 内。agent 表明此 pipeline 在哪个节点上执行;是否必须:是

参数:any、none、label、node、docker、dockerfile

agent any 运行在任意的可用节点上

agent none 全局不指定运行节点,由各自 stage 来决定

agent { label 'master' } 运行在指定标签的机器上,具体标签名称由 agent 配置决定

agent { 
     node {
         label  'my-defined-label'
         customWorkspace 'xxxxxxx'
    } 
}
# node{ label 'master'} 和 agent { label 'master' } 一样,但是 node 可以扩展节点信息,允许额外的选项 (比如 customWorkspace )。

agent { docker 'python' } 使用指定的容器运行流水线

agent {
    docker {
        image 'maven:3-alpine'
        label 'my-defined-label'
        args  '-v /tmp:/tmp'
    }
}

# 定义此参数时,执行 Pipeline 或 stage 时会动态的在具有 label 'my-defined-label' 标签的 node 提供 docker 节点去执行 Pipelines。docker 还可以接受一个 args,直接传递给 docker run 调用。
agent {
    // Equivalent to "docker build -f Dockerfile.build --build-arg version=1.0.2 ./build/
    dockerfile {
        filename 'Dockerfile.build'
        dir 'build'
        label 'my-defined-label'
        additionalBuildArgs  '--build-arg version=1.0.2'
    }
}

二、Pipeline 声明式语法实战讲解

创建一个任务 -> 输入上面代码 -> 立即构建 -> Build with Parameters -> 开始构建

*

控制台输出观察构建结果

*

三、Pipeline Scripted 语法

Groovy 脚本不一定适合所有使用者,因此 jenkins 创建了 Declarative pipeline,为编写Jenkins 管道提供了一种更简单、更有主见的语法。但是由于脚本化的 pipeline 是基于 groovy 的一种 DSL 语言,所以与 Declarative pipeline 相比为 jenkins 用户提供了更巨大的灵活性和可扩展性。

3.1 流程控制

pipeline 脚本同其它脚本语言一样,从上至下顺序执行,它的流程控制取决于 Groovy 表达式,如 if/else 条件语句,举例如下:

node {
    stage('Example') {
        if (env.BRANCH_NAME == 'master') {
            echo 'I only execute on the master branch'
        } else {
            echo 'I execute elsewhere'
        }
    }
}

3.2 Declarative pipeline 和 Scripted pipeline 的比较

  • 共同点:

  两者都是 pipeline 代码的持久实现,都能够使用 pipeline 内置的插件或者插件提供的 stage,两者都可以利用共享库扩展。

  • 区别:

  两者不同之处在于语法和灵活性。Declarative pipeline 对用户来说,语法更严格,有固定的组织结构,更容易生成代码段,使其成为用户更理想的选择。但是 Scripted pipeline 更加灵活,因为Groovy 本身只能对结构和语法进行限制,对于更复杂的 pipeline 来说,用户可以根据自己的业务进行灵活的实现和扩展。

四、基于 Jenkins+k8s+nexus+gitlab+harbor+sonarqube+springloud 构建 DevOps

4.1 安装码扫描工具 sonarqube

# 在 node2 上操作下面命令
[root@k8s-node2 ~]# docker run -d --restart=always --name postgres10 -p 5432:5432 -e POSTGRES_USER=sonar -e POSTGRES_PASSWORD=123456 postgres

# 设置虚拟内存
[root@k8s-node2 ~]# sysctl -w vm.max_map_count=262144
[root@k8s-node2 ~]# sysctl -a|grep vm.max_map_count
[root@k8s-node2 ~]# vi /etc/sysctl.conf
vm.max_map_count=262144

[root@k8s-node2 ~]# docker run -d --restart=always --name sonarqube7.9 -p 9000:9000 --link postgres10 -e SONARQUBE_JDBC_URL=jdbc:postgresql://postgres10:5432/sonar -e  SONARQUBE_JDBC_USERNAME=sonar -e SONARQUBE_JDBC_PASSWORD=123456 -v sonarqube_conf:/opt/sonarqube/conf -v sonarqube_extensions:/opt/sonarqube/extensions -v sonarqube_logs:/opt/sonarqube/logs -v sonarqube_data:/opt/sonarqube/data sonarqube

容器日志报错信息:

ERROR: [1] bootstrap checks failed. You must address the points described in the following [1] lines before starting Elasticsearch.
bootstrap check failure [1] of [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
ERROR: Elasticsearch did not exit normally - check the logs at /opt/sonarqube/logs/sonarqube.log

解决办法:设置虚拟内存

在jenkins 中安装 sonarqube 插件:

系统管理 -> 插件管理 -> 可选插件:搜索 sonar,找到 Sonarqube Scanner -> 选择Sonarqube Scanner 直接安装 -> 安装之后重启 jenkins 即可

*

登录sonarqube web 界面:node2 ip:9000,默认账号密码都为 admin,在 sonarqube 的 web 界面创建一个 token:

*

*把 copy 后面的一串 token 记录下来:0e7e0d837275659b83c25015b0a69f2a00285568

*

回到 k8s 的控制节点

# 上传代码项目压缩包并解压
[root@k8s-master1 ~]# unzip -o microservic-test.zip 
[root@k8s-master1 ~]# cd microservic-test/

# 把代码上传到 sonarqube
mvn sonar:sonar -Dsonar.host.url=http://192.168.78.145:9000 -Dsonar.login=0e7e0d837275659b83c25015b0a69f2a00285568

可以查看我的这篇文章安装 maven:Linux 下安装 JDK 和 Maven 环境_Stars.Sky的博客-CSDN博客

注意:此次实验只做演示作用,生成环境中根据实际情况操作。此次代码目前不支持这个版本的sonarqube,所以这个上传到 sonarqube 是有问题的,会报错版本不支持,结果大家可以不用看,了解过程就可以。

4.2 Jenkins 界面添加 harbor 凭据

需要有一台 harbor 服务,我的 harbor 安装在了192.168.78.138 的机器上。

可以查看我这篇文章安装 harbor:[【云原生 | Docker 高级篇】11、Docker 私有镜像仓库 Harbor 安装及使用教程_Stars.Sky的博客-CSDN博客][_ Docker _11_Docker _ Harbor _Stars.Sky_-CSDN]

4.2.1 添加凭据

首页------> 系统管理 ------> 管理凭据 ------> 点击 Stores scoped to Jenkins 下的第一行 jenkins,显示如下:

*

点击这个全局凭据,出现如下

*

点击添加凭据,出现如下

*

  • username:admin
  • password:Harbor12345
  • ID:harbor
  • 描述:随意

4.2.2 编写 jenkins pipeline

因为镜像要上传到 harbor 私有镜像仓库,所以需要在 harbor 上创建一个项目,项目名称是 jenkins-demo,如下所示:

*

上面项目创建成功之后,执行如下步骤:在 jenkins 新建一个任务 ------> 输入一个任务名称处输入 jenkins-harbor ------> 流水线 ------> 确定 ------> 在 Pipeline script 处输入如下内容

*

修改为自己的 harbor ip 和 GitHub 地址,同时也需要在 GitHub 项目上修改 k8s-dev-harbor.yaml、k8s-qa-harbor.yaml 和 k8s-prod-harbor.yaml 的镜像名称 ip :

node('test') {
    stage('Clone') {
        echo "1.Clone Stage"
        git url: "https://github.com/loveyou2333/jenkins-sample.git"
        script {
            build_tag = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim()
        }
    }
    stage('Test') {
      echo "2.Test Stage"

    }
    stage('Build') {
        echo "3.Build Docker Image Stage"
        sh "docker build -t 192.168.78.138/jenkins-demo/jenkins-demo:${build_tag} ."
    }
    stage('Push') {
        echo "4.Push Docker Image Stage"
        withCredentials([usernamePassword(credentialsId: 'harbor', passwordVariable: 'dockerHubPassword', usernameVariable: 'dockerHubUser')]) {
            sh "docker login 192.168.78.138 -u ${dockerHubUser} -p ${dockerHubPassword}"
            sh "docker push 192.168.78.138/jenkins-demo/jenkins-demo:${build_tag}"
        }
    }
    stage('Deploy to dev') {
        echo "5. Deploy DEV"
		sh "sed -i 's/<BUILD_TAG>/${build_tag}/' k8s-dev-harbor.yaml"
        sh "sed -i 's/<BRANCH_NAME>/${env.BRANCH_NAME}/' k8s-dev-harbor.yaml"
//        sh "bash running-devlopment.sh"
        sh "kubectl apply -f k8s-dev-harbor.yaml  --validate=false"
	}	
	stage('Promote to qa') {	
		def userInput = input(
            id: 'userInput',

            message: 'Promote to qa?',
            parameters: [
                [
                    $class: 'ChoiceParameterDefinition',
                    choices: "YES\nNO",
                    name: 'Env'
                ]
            ]
        )
        echo "This is a deploy step to ${userInput}"
        if (userInput == "YES") {
            sh "sed -i 's/<BUILD_TAG>/${build_tag}/' k8s-qa-harbor.yaml"
            sh "sed -i 's/<BRANCH_NAME>/${env.BRANCH_NAME}/' k8s-qa-harbor.yaml"
//            sh "bash running-qa.sh"
            sh "kubectl apply -f k8s-qa-harbor.yaml --validate=false"
            sh "sleep 6"
            sh "kubectl get pods -n qatest"
        } else {
            //exit
        }
    }
	stage('Promote to pro') {	
		def userInput = input(

            id: 'userInput',
            message: 'Promote to pro?',
            parameters: [
                [
                    $class: 'ChoiceParameterDefinition',
                    choices: "YES\nNO",
                    name: 'Env'
                ]
            ]
        )
        echo "This is a deploy step to ${userInput}"
        if (userInput == "YES") {
            sh "sed -i 's/<BUILD_TAG>/${build_tag}/' k8s-prod-harbor.yaml"
            sh "sed -i 's/<BRANCH_NAME>/${env.BRANCH_NAME}/' k8s-prod-harbor.yaml"
//            sh "bash running-production.sh"
            sh "cat k8s-prod-harbor.yaml"
            sh "kubectl apply -f k8s-prod-harbor.yaml --record --validate=false"
        }
    }
}

*

4.3 安装 nexus

Nexus 服务器是一个代码包管理的服务器,可以理解 Nexus 服务器是一个巨大的 Library 仓库。Nexus 可以支持管理的工具包括 Maven、npm 等,对于 JAVA 开发来说,只要用到 Maven 管理就可以了。

Nexus 服务器作用:因为传统的中央仓库在国外,其地理位置比较远,下载速度比较缓慢。因此,当公司开发人员数量越来越多时,如果不架设一台自己的 Nexus 服务器,会产生大量的流量阻塞带宽,并且在出现一些不可抗原因(光缆被挖断)导致无法连接到中央仓库时,开发就会因为无法下载相关依赖包而进度停滞。因此在本地环境部署一台私有的 Nexus 服务器来缓存所有依赖包,并且将公司内部开发的私有包也部署上去,方便其他开发人员下载,是非常有必要的。因为 Nexus 有权限控制,因此外部人员是无法得到公司内部开发的项目包的。

下面将介绍如何将自己的 maven 构件发布到 nexus 私服上呢?

4.3.1 安装 nexus

在harbor 服务器上安装

[root@harbor harbor]# docker run -d --restart=always -p 8081:8081 -p 8082:8082 -p 8083:8083 -v /etc/localtime:/etc/localtime --name nexus3  sonatype/nexus3

docker logs nexus3 在日志中,会看到一条消息:Started Sonatype Nexus OSS 3.37.3-02 这意味着 Nexus Repository Manager 可以使用了。现在转到浏览器并打开 http://192.168.78.138:8081/

*

4.3.2 在 pom.xml 文件中声明发布的宿主仓库和 release 版本发布的仓库

<!-- 发布构件到Nexus -->
    <distributionManagement>
        <repository>
            <id>releases</id>
            <name>nexus-releases</name>
            <url>http://192.168.78.138:8081/repository/maven-releases/</url>
        </repository>
        <snapshotRepository>
            <id>snapshots</id>
            <name>nexus-snapshots</name>
            <url>http://192.168.78.138:8081/repository/maven-snapshots/</url>
        </snapshotRepository>
    </distributionManagement>

4.3.3 在 settings.xml 文件中配置由于用 Maven 分发构件到远程仓库需要认证,须要在 ~/.m2/settings.xml 或者中加入验证信息

<servers>  
   <server>  
           <id>public</id>  
           <username>admin</username>  
           <password>123456</password>  
       </server>  
   <server>  
           <id>releases</id>  
           <username>admin</username>  
           <password>123456</password>  
       </server>  
   <server>  
           <id>snapshots</id>  
           <username>admin</username>  
           <password>123456</password>  
       </server>  
 </servers>  

注意:第二、第三步的文件内容是开发来做的,运维只需要第一步安装即可,也可以自己了解一下。settings.xml 中 server 元素下 id 的值必须与 POM 中 repository 或snapshotRepository 下 id 的值完全一致 。

4.4 安装 gitlab

4.4.1 安装 gitlab

在192.168.78.140 服务器上安装(生产环境中可以单独一个服务器上安装独立的服务,性能好)

[root@client01 ~]# docker run -d -p 443:443 -p 80:80 -p 222:22 --name gitlab --restart always -v /home/gitlab/config:/etc/gitlab -v /home/gitlab/logs:/var/log/gitlab -v /home/gitlab/data:/var/opt/gitlab gitlab/gitlab-ce

# 修改配置文件,在最后面添加下面内容
[root@client01 ~]# vim /home/gitlab/config/gitlab.rb 
external_url 'http://192.168.78.128'
gitlab_rails['gitlab_ssh_host'] = '192.168.78.128'
gitlab_rails['gitlab_shell_ssh_port'] = 22

# 重启 gitlab 服务
[root@client01 ~]# docker restart gitlab 

4.4.2 登录 gitlab

在浏览器访问 192.168.78.128 进入gitlab,在页面注册账号后,不能登录:

*

解决办法——重置密码:

Gitlab 重装密码官网文档:Reset a user's password | GitLab

[root@client01 ~]# docker exec -it gitlab sh
# gitlab-rails console -e production        # 启动 Ruby on Rails 控制台,等待控制台加载完毕
irb(main):005:0> u=User.where(id:1).first
=> #<User id:1 @root>
irb(main):006:0> u.password='qwe123456'
=> "qwe123456"
irb(main):007:0> u.password_confirmation='qwe123456'
=> "qwe123456"
irb(main):008:0> u.save!
=> true
irb(main):009:0> exit
# exit

重新登录 gitlab:

  • 用户名是 root
  • 密码是 qwe123456

*

4.4.3 在 Jenkins 安装插件

安装git 插件:系统管理 - 插件管理- 可选插件 - 搜索 git 安装即可

*

4.4.4 在 Jenkins 上添加 gitlab 凭据

*

4.4.5 在 gitlab 上新建项目

点击右上角的 new project -> Create blank project :

*

4.4.6 配置公钥

[root@client01 ~]# ssh-keygen -t rsa

[root@client01 ~]# cat .ssh/id_rsa.pub 
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8t5LbIE+U29JBAR5UbgZeaKe330yExlMoErPWRAzCoYtFcf2wXBpbzMLTxfsBjr/lBwoJ2BcLOQC30AWkXM3rdwzZHoWFn7r+6DnWxcEbrbNBwUJCf3X9RHBh7e4HlY3hbJEx1Y6Tl/rKnxtg0ASuiUfyiVDSVPcUwcIX8WVuUBvXQU8RHRowFWGcZYaX7RxVswrLObtTLg0CZQ0kUAn6j10wFH2nHdjljBBYjg9WlRc++bE71HSroOENnAvqX6dN7Io86HX0sV66abyNuP2CrJpuR6UZc4iZ9cPyw2E8jzAi9fpMWTwSrwr9yT1zCAFf0ysC7AM98VnX4CwIQm9P root@client01

*

*

4.4.7 提交本地代码到 gitlab

# 上传本地代码文件 microservic-test.zip
[root@client01 ~]# yum install git -y
[root@client01 ~]# unzip microservic-test.zip 
[root@client01 microservic-test]# git init    # 建仓
[root@client01 microservic-test]# git add *   # 把当前文件夹所有代码提交 
[root@client01 microservic-test]# git config --global user.email "163.com"
[root@client01 microservic-test]# git config --global user.name "sky"
[root@client01 microservic-test]# git commit -m "add microservic-test"    # 代码提交到缓冲区
[root@client01 microservic-test]# git remote add origin http://192.168.78.128/root/microservic-test.git                    # 代码提交到远程仓库
[root@client01 microservic-test]# git push -u origin master    # 输入 gitlab 账号和密码

回到gitlab 首页,可以看到,已经有项目了:

*

4.5 测试跑通流程

上传jenkins-jnlp-v2.tar.gz 文件到 node1、node2 并手动解压,在 http://192.168.78.143:30002/configureClouds/,把 Container Template 镜像改成 jenkins-jnlp-v2.tar.gz 压缩包解压之后的镜像 xianchao/jenkins-jnlp:v2:

*修改 gitlab 上 portal.yaml 文件:

*

把image 镜像变成:192.168.78.138/microservice/jenkins-demo:v1

注意:192.168.78.138 为 Harbor 服务器 ip,且需要在 harbor 里提前创建这个 microservice 仓库。

打开Jenkins,新建流水线,流水线名字是 mvn-gitlab-harbor-springcloud,在 Pipeline Script 处输入如下内容(根据实际情况修改):

node('test') {
   stage('Clone') {
       echo "1.Clone Stage"
      git credentialsId: 'gitlab', url: 'http://192.168.78.128/root/microservic-test.git '
       script {
           build_tag = sh(returnStdout: true, script: 'git rev-parse --shortHEAD').trim()
       }
    }

   stage('Test') {
     echo "2.Test Stage"
    }
   stage('mvn') {
     sh "mvn clean package -D maven.test.skip=true"
    }
   stage('Build') {
       echo "3.Build Docker Image Stage"
       sh "cd /home/jenkins/agent/workspace/mvn-gitlab-harbor-springcloud/portal-service"
       sh "docker build --tag 192.168.78.138/microservice/jenkins-demo:v1 /home/jenkins/agent/workspace/mvn-gitlab-harbor-springcloud/portal-service/"
    }
   stage('Push') {
       echo "4.Push Docker Image Stage"
       withCredentials([usernamePassword(credentialsId: 'harbor',passwordVariable: 'dockerHubPassword', usernameVariable: 'dockerHubUser')]) {
           sh "docker login 192.168.78.138 -u ${dockerHubUser} -p ${dockerHubPassword}"
           sh "docker push 192.168.78.138/microservice/jenkins-demo:v1"
       }
    }
     stage('Promoteto pro') {    
    sh "kubectl apply -f /home/jenkins/agent/workspace/mvn-gitlab-harbor-springcloud/k8s/portal.yaml"
      }
}

立即构建即可!!!

上一篇文章:【Kubernetes 企业项目实战】06、基于 Jenkins+K8s 构建 DevOps 自动化运维管理平台(中)_Stars.Sky的博客-CSDN博客_k8s运维管理平台

下一篇文章:【Kubernetes 企业项目实战】07、最新一代微服务网格 Istio 入门到企业实战(上)_Stars.Sky的博客-CSDN博客