基于K8s的DevOps平台实践(三)

news2024/11/15 16:56:41

文章目录

  • 前言
  • 1. Jenkins与k8s集成
    • 🍑 插件安装及配置
    • 🍑 演示动态slave pod
    • 🍑 Pod-Template中容器镜像的制作
    • 🍑 实践通过Jenkinsfile实现demo项目自动发布到kubenetes环境
  • 2. Jenkins集成Sonarqube
    • 🍑 sonarqube架构简介
    • 🍑 sonarqube on kubernetes环境搭建
    • 🍑 插件安装及配置
    • 🍑 Jenkinsfile集成sonarqube演示
  • 3. Jenkins集成robotFramework
    • 🍑 robot用例简介
    • 🍑 与 tools 工具镜像集成
    • 🍑 插件安装及配置
    • 🍑 实践通过Jenkinsfile实现demo项目的验收测试
  • 4. 总结与反思


前言

今天是「基于K8s的DevOps平台实践」的最后一篇,前两篇地址如下:

  • 基于K8s的DevOps平台实践(一)
  • 基于K8s的DevOps平台实践(二)

上面两篇均排在云原生领域榜第一

1. Jenkins与k8s集成

  1. Jenkins 如何对接 kubernetes 集群
  2. 使用 kubernetes 的 Pod-Template 来作为动态的 agent 执行 Jenkins 任务
  3. 如何制作 agent 容器实现不同类型的业务的集成
  4. 集成代码扫描、docker 镜像自动构建、k8s 服务部署、自动化测试

🍑 插件安装及配置

插件官方文档

  1. [系统管理] -> [插件管理] -> [搜索kubernetes] -> 直接安装

    若安装失败,请先更新 bouncycastle API Plugin 并重新启动Jenkins

  2. [系统管理] -> [系统配置] -> [Add a new cloud]

  3. 配置地址信息

    • Kubernetes 地址:https://kubernetes.default
    • Kubernetes 命名空间:jenkins
    • 服务证书不用写(我们在安装 Jenkins 的时候已经指定过 serviceAccount),均使用默认
    • 连接测试,成功会提示:Connection test successful
    • Jenkins地址:http://jenkins:8080
    • Jenkins 通道 :jenkins:50000
  4. 配置 Pod Template

    • 名称:jnlp-slave

    • 命名空间:jenkins

    • 标签列表:jnlp-slave,作为 agent 的 label 选择用

    • 连接 Jenkins 的超时时间(秒):300,设置连接 jenkins 超时时间

    • 工作空间卷:选择 hostpath,设置 /opt/jenkins,注意需要设置目录权限,否则 Pod 没有权限

在这里插入图片描述

$ chown -R 1000:1000 /opt/jenkins
$ chmod 700 /opt/jenkins

🍑 演示动态slave pod

# 为准备运行jnlp-slave-agent的pod的节点打上label
$ kubectl label node k8s-slave1 agent=true

### 回放一次多分支流水线develop分支
agent { label 'jnlp-slave'}

执行任务,会下载默认的 jnlp-slave 镜像,地址为 jenkins/inbound-agent:4.3-4,我们可以先在 k8s-master 节点拉取下来该镜像:

$ docker pull jenkins/inbound-agent:4.3-4

保存 jenkinsfile 提交后,会出现报错,因为我们的 agent 已经不再是宿主机,而是 Pod 中的容器内,报错如下:

在这里插入图片描述

因此我们需要将用到的命令行工具集成到 Pod 的容器内,但是思考如下问题:

  • 目前是用的 jnlp 的容器,是 java 的环境,我们在此基础上需要集成很多工具,能不能创建一个新的容器,让新容器来做具体的任务,jnlp-slave 容器只用来负责连接 jenkins-master
  • 针对不同的构建环境(java、python、go、nodejs),可以制作不同的容器,来执行对应的任务

🍑 Pod-Template中容器镜像的制作

为解决上述问题,我们制作一个 tools 镜像,集成常用的工具,来完成常见的构建任务,需要注意的几点:

  • 使用 alpine 基础镜像,自身体积比较小
  • 替换国内安装源
  • 为了使用 docker,安装了 docker
  • 为了克隆代码,安装 git
  • 为了后续做 python 的测试等任务,安装 python 环境
  • 为了在容器中调用 kubectl 的命令,拷贝了 kubectl 的二进制文件
  • 为了认证 kubectl,需要在容器内部生成 .kube 目录及 config 文件
$ mkdir tools;
$ cd tools;
$ cp `which kubectl` .
$ cp ~/.kube/config .

Dockerfile

jenkins/custom-images/tools/Dockerfile

FROM alpine:3.13.4
LABEL maintainer="inspur_lyx@hotmail.com"
USER root

RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories && \
    apk update && \
    apk add  --no-cache openrc docker git curl tar gcc g++ make \
    bash shadow openjdk8 python2 python2-dev py-pip python3-dev openssl-dev libffi-dev \
    libstdc++ harfbuzz nss freetype ttf-freefont && \
    mkdir -p /root/.kube && \
    usermod -a -G docker root

COPY config /root/.kube/

RUN rm -rf /var/cache/apk/* 
#-----------------安装 kubectl--------------------#
COPY kubectl /usr/local/bin/
RUN chmod +x /usr/local/bin/kubectl
# ------------------------------------------------#

执行镜像构建并推送到仓库中:

$ docker build . -t 172.21.51.143:5000/devops/tools:v1
$ docker push 172.21.51.143:5000/devops/tools:v1

我们可以直接使用该镜像做测试:

## 启动临时镜像做测试
$ docker run --rm -ti 172.21.51.143:5000/devops/tools:v1 bash
# / git clone http://xxxxxx.git
# / kubectl get no
# / python3
#/ docker

## 重新挂载docker的sock文件
docker run -v /var/run/docker.sock:/var/run/docker.sock --rm -ti 172.21.51.143:5000/devops/tools:v1 bash

🍑 实践通过Jenkinsfile实现demo项目自动发布到kubenetes环境

实践通过 Jenkinsfile 实现 demo 项目自动发布到 kubenetes 环境

在这里插入图片描述

在卷栏目,添加卷,Host Path Volume,不然在容器中使用 docker 会提示 docker 服务未启动

在这里插入图片描述

tools 容器做好后,我们需要对 Jenkinsfile 做如下调整:

jenkins/pipelines/p8.yaml

pipeline {
    agent { label 'jnlp-slave'}
    
    options {
		buildDiscarder(logRotator(numToKeepStr: '10'))
		disableConcurrentBuilds()
		timeout(time: 20, unit: 'MINUTES')
		gitLabConnection('gitlab')
	}

    environment {
        IMAGE_REPO = "172.21.51.143:5000/myblog"
        DINGTALK_CREDS = credentials('dingTalk')
        TAB_STR = "\n                    \n                    "
    }

    stages {
        stage('printenv') {
            steps {
                script{
                    sh "git log --oneline -n 1 > gitlog.file"
                    env.GIT_LOG = readFile("gitlog.file").trim()
                }
                sh 'printenv'
            }
        }
        stage('checkout') {
            steps {
                container('tools') {
                    checkout scm
                }
                updateGitlabCommitStatus(name: env.STAGE_NAME, state: 'success')
                script{
                    env.BUILD_TASKS = env.STAGE_NAME + "√..." + env.TAB_STR
                }
            }
        }
        stage('build-image') {
            steps {
                container('tools') {
                    retry(2) { sh 'docker build . -t ${IMAGE_REPO}:${GIT_COMMIT}'}
                }
                updateGitlabCommitStatus(name: env.STAGE_NAME, state: 'success')
                script{
                    env.BUILD_TASKS += env.STAGE_NAME + "√..." + env.TAB_STR
                }
            }
        }
        stage('push-image') {
            steps {
                container('tools') {
                    retry(2) { sh 'docker push ${IMAGE_REPO}:${GIT_COMMIT}'}
                }
                updateGitlabCommitStatus(name: env.STAGE_NAME, state: 'success')
                script{
                    env.BUILD_TASKS += env.STAGE_NAME + "√..." + env.TAB_STR
                }
            }
        }
        stage('deploy') {
            steps {
                container('tools') {
                    sh "sed -i 's#{{IMAGE_URL}}#${IMAGE_REPO}:${GIT_COMMIT}#g' manifests/*"
                    timeout(time: 1, unit: 'MINUTES') {
                        sh "kubectl apply -f manifests/"
                    }
                }
                updateGitlabCommitStatus(name: env.STAGE_NAME, state: 'success')
                script{
                    env.BUILD_TASKS += env.STAGE_NAME + "√..." + env.TAB_STR
                }
            }
        }
    }
    post {
        success { 
            echo 'Congratulations!'
            sh """
                curl 'https://oapi.dingtalk.com/robot/send?access_token=${DINGTALK_CREDS_PSW}' \
                    -H 'Content-Type: application/json' \
                    -d '{
                        "msgtype": "markdown",
                        "markdown": {
                            "title":"myblog",
                            "text": "😄👍 构建成功 👍😄  \n**项目名称**:luffy  \n**Git log**: ${GIT_LOG}   \n**构建分支**: ${BRANCH_NAME}   \n**构建地址**:${RUN_DISPLAY_URL}  \n**构建任务**:${BUILD_TASKS}"
                        }
                    }'
            """ 
        }
        failure {
            echo 'Oh no!'
            sh """
                curl 'https://oapi.dingtalk.com/robot/send?access_token=${DINGTALK_CREDS_PSW}' \
                    -H 'Content-Type: application/json' \
                    -d '{
                        "msgtype": "markdown",
                        "markdown": {
                            "title":"myblog",
                            "text": "😖❌ 构建失败 ❌😖  \n**项目名称**:luffy  \n**Git log**: ${GIT_LOG}   \n**构建分支**: ${BRANCH_NAME}  \n**构建地址**:${RUN_DISPLAY_URL}  \n**构建任务**:${BUILD_TASKS}"
                        }
                    }'
            """
        }
        always { 
            echo 'I will always say Hello again!'
        }
    }
}

2. Jenkins集成Sonarqube

集成 sonarQube 实现代码扫描

Sonar 可以从以下七个维度检测代码质量,而作为开发人员至少需要处理前 5 种代码质量问题。

  1. 不遵循代码标准
    sonar 可以通过 PMD、CheckStyle、Findbugs 等等代码规则检测工具规范代码编写。
  2. 潜在的缺陷
    sonar 可以通过 PMD、CheckStyle、Findbugs 等等代码规则检测工具检 测出潜在的缺陷。
  3. 糟糕的复杂度分布
    文件、类、方法等,如果复杂度过高将难以改变,这会使得开发人员 难以理解它们, 且如果没有自动化的单元测试,对于程序中的任何组件的改变都将可能导致需要全面的回归测试。
  4. 重复
    显然程序中包含大量复制粘贴的代码是质量低下的,sonar 可以展示 源码中重复严重的地方。
  5. 注释不足或者过多
    没有注释将使代码可读性变差,特别是当不可避免地出现人员变动时,程序的可读性将大幅下降而过多的注释又会使得开发人员将精力过多地花费在阅读注释上,亦违背初衷。
  6. 缺乏单元测试
    sonar 可以很方便地统计并展示单元测试覆盖率。
  7. 糟糕的设计
    通过 sonar 可以找出循环,展示包与包、类与类之间的相互依赖关系,可以检测自定义的架构规则通过 sonar 可以管理第三方的 jar 包,可以利用 LCOM4 检测单个任务规则的应用情况,检测耦合。

🍑 sonarqube架构简介

如图所示:

在这里插入图片描述

  1. CS 架构
    • sonarqube scanner
    • sonarqube server
  2. SonarQube Scanner 扫描仪在本地执行代码扫描任务
  3. 执行完后,将分析报告被发送到 SonarQube 服务器进行处理
  4. SonarQube 服务器处理和存储分析报告导致 SonarQube 数据库,并显示结果在 UI 中

🍑 sonarqube on kubernetes环境搭建

  1. 资源文件准备

sonar/sonar.yaml

  • 和 gitlab 共享 postgres 数据库
  • 使用 ingress 地址 sonar.luffy.com 进行访问
  • 使用 initContainers 进行系统参数调整
apiVersion: v1
kind: Service
metadata:
  name: sonarqube
  namespace: jenkins
  labels:
    app: sonarqube
spec:
  ports:
  - name: sonarqube
    port: 9000
    targetPort: 9000
    protocol: TCP
  selector:
    app: sonarqube
---
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: jenkins
  name: sonarqube
  labels:
    app: sonarqube
spec:
  replicas: 1
  selector:
    matchLabels:
      app: sonarqube
  template:
    metadata:
      labels:
        app: sonarqube
    spec:
      initContainers:
      - command:
        - /sbin/sysctl
        - -w
        - vm.max_map_count=262144
        image: alpine:3.6
        imagePullPolicy: IfNotPresent
        name: elasticsearch-logging-init
        resources: {}
        securityContext:
          privileged: true
      containers:
      - name: sonarqube
        image: sonarqube:7.9-community
        ports:
        - containerPort: 9000
        env:
        - name: SONARQUBE_JDBC_USERNAME
          valueFrom:
            secretKeyRef:
              name: gitlab-secret
              key: postgres.user.root
        - name: SONARQUBE_JDBC_PASSWORD
          valueFrom:
            secretKeyRef:
              name: gitlab-secret
              key: postgres.pwd.root
        - name: SONARQUBE_JDBC_URL
          value: "jdbc:postgresql://postgres:5432/sonar"
        livenessProbe:
          httpGet:
            path: /sessions/new
            port: 9000
          initialDelaySeconds: 60
          periodSeconds: 30
        readinessProbe:
          httpGet:
            path: /sessions/new
            port: 9000
          initialDelaySeconds: 60
          periodSeconds: 30
          failureThreshold: 6
        resources:
          limits:
            cpu: 2000m
            memory: 4096Mi
          requests:
            cpu: 300m
            memory: 512Mi
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: sonarqube
  namespace: jenkins
spec:
  rules:
  - host: sonar.luffy.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service: 
            name: sonarqube
            port:
              number: 9000
  1. sonarqube 服务端安装

# 创建sonar数据库
$ kubectl -n jenkins exec -ti postgres-5859dc6f58-mgqz9 bash
#/ psql 
# create database sonar;

## 创建sonarqube服务器
$ kubectl create -f sonar.yaml

## 配置本地hosts解析
172.21.51.143 sonar.luffy.com

## 访问sonarqube,初始用户名密码为 admin/admin
$ curl http://sonar.luffy.com
  1. sonar-scanner的安装

    下载地址: sonar

  2. 演示sonar代码扫描功能

  • 在项目根目录中准备配置文件 sonar-project.properties
sonar.projectKey=myblog
sonar.projectName=myblog
# if you want disabled the DTD verification for a proxy problem for example, true by default
sonar.coverage.dtdVerification=false
# JUnit like test report, default value is test.xml
sonar.sources=blog,myblog
  • 配置 sonarqube 服务器地址

    • 由于sonar-scanner 需要将扫描结果上报给 sonarqube 服务器做质量分析,因此我们需要在 sonar-scanner 中配置 sonarqube 的服务器地址:

    • 在集群宿主机中测试,先配置一下 hosts 文件,然后配置 sonar 的地址:

$ cat /etc/hosts
172.21.51.143  sonar.luffy.com

$ cat sonar-scanner/conf/sonar-scanner.properties
#----- Default SonarQube server
#sonar.host.url=http://localhost:9000
sonar.host.url=http://sonar.luffy.com
#----- Default source code encoding
#sonar.sourceEncoding=UTF-8
  • 为了使所有的 pod 都可以通过sonar.luffy.com访问,可以配置 coredns 的静态解析
# 静态解析
$ kubectl -n kube-system edit cm coredns 
...
             hosts {
                 172.21.51.143 jenkins.luffy.com gitlab.luffy.com sonar.luffy.com
                 fallthrough
          }
  • 执行扫描
## 在项目的根目录下执行
$ /opt/sonar-scanner-4.2.0.1873-linux/bin/sonar-scanner  -X 
  • sonarqube 界面查看结果

    • 登录 sonarqube 界面查看结果,Quality Gates 说明

java 项目的配置文件通常格式为:

sonar.projectKey=eureka-cluster
sonar.projectName=eureka-cluster
# if you want disabled the DTD verification for a proxy problem for example, true by default
# JUnit like test report, default value is test.xml
sonar.sources=src/main/java
sonar.language=java
sonar.tests=src/test/java
sonar.java.binaries=target/classes

🍑 插件安装及配置

  1. 集成到 tools 容器中

    由于我们的代码拉取、构建任务均是在 tools 容器中进行,因此我们需要把 scanner 集成到我们的 tools 容器中,又因为 scanner 是一个 cli 客户端,因此我们直接把包解压好,拷贝到 tools 容器内部,配置一下 PATH 路径即可,注意两点:

    • 直接在 tools 镜像中配置 http://sonar.luffy.com

    • 由于 tools 已经集成了 java 环境,因此可以直接剔除 scanner 自带的 jre

    • 删掉 sonar-scanner/jre 目录

    • 修改 sonar-scanner/bin/sonar-scanner

use_embedded_jre=false

$ cd tools
$ cp -r /opt/sonar-scanner-4.2.0.1873-linux/ sonar-scanner
## sonar配置,由于我们是在Pod中使用,也可以直接配置:sonar.host.url=http://sonarqube:9000
$ cat sonar-scanner/conf/sonar-scanner.properties
#----- Default SonarQube server
sonar.host.url=http://sonar.luffy.com

#----- Default source code encoding
#sonar.sourceEncoding=UTF-8

$ rm -rf sonar-scanner/jre
$ vi sonar-scanner/bin/sonar-scanner
...
use_embedded_jre=false
...

Dockerfile

jenkins/custom-images/tools/Dockerfile2

FROM alpine:3.13.4
LABEL maintainer="inspur_lyx@hotmail.com"
USER root

RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories && \
    apk update && \
    apk add  --no-cache openrc docker git curl tar gcc g++ make \
    bash shadow openjdk8 python2 python2-dev py-pip python3-dev openssl-dev libffi-dev \
    libstdc++ harfbuzz nss freetype ttf-freefont && \
    mkdir -p /root/.kube && \
    usermod -a -G docker root

COPY config /root/.kube/


RUN rm -rf /var/cache/apk/*

#-----------------安装 kubectl--------------------#
COPY kubectl /usr/local/bin/
RUN chmod +x /usr/local/bin/kubectl
# ------------------------------------------------#

#---------------安装 sonar-scanner-----------------#
COPY sonar-scanner /usr/lib/sonar-scanner
RUN ln -s /usr/lib/sonar-scanner/bin/sonar-scanner /usr/local/bin/sonar-scanner && chmod +x /usr/local/bin/sonar-scanner
ENV SONAR_RUNNER_HOME=/usr/lib/sonar-scanner
# ------------------------------------------------#

重新构建镜像,并推送到仓库:

$ docker build . -t 172.21.51.143:5000/devops/tools:v2
$ docker push 172.21.51.143:5000/devops/tools:v2  
  1. 修改 Jenkins PodTemplate

    为了在新的构建任务中可以拉取 v2 版本的 tools 镜像,需要更新 PodTemplate

  2. 安装并配置 sonar 插件

    由于 sonarqube 的扫描的结果需要进行 Quality Gates 的检测,那么我们在容器中执行完代码扫描任务后,如何知道本次扫描是否通过了 Quality Gates,那么就需要借助于 sonarqube 实现的 jenkins 的插件。

    • 安装插件

      插件中心搜索 sonarqube,直接安装

    • 配置插件

      系统管理 -> 系统配置 -> SonarQube servers -> Add SonarQube

      • Name:sonarqube

      • Server URL:http://sonar.luffy.com

      • Server authentication token

        ① 登录 sonarqube -> My Account -> Security -> Generate Token

        ② 登录 Jenkins,添加全局凭据,类型为 Secret text

    • 如何在 jenkinsfile 中使用

      我们在 官方介绍 中可以看到:

🍑 Jenkinsfile集成sonarqube演示

jenkins/pipelines/p9.yaml

pipeline {
    agent { label 'jnlp-slave'}
    
    options {
		buildDiscarder(logRotator(numToKeepStr: '10'))
		disableConcurrentBuilds()
		timeout(time: 20, unit: 'MINUTES')
		gitLabConnection('gitlab')
	}

    environment {
        IMAGE_REPO = "172.21.51.143:5000/myblog"
        DINGTALK_CREDS = credentials('dingTalk')
        TAB_STR = "\n                    \n                    "
    }

    stages {
        stage('git-log') {
            steps {
                script{
                    sh "git log --oneline -n 1 > gitlog.file"
                    env.GIT_LOG = readFile("gitlog.file").trim()
                }
                sh 'printenv'
            }
        }        
        stage('checkout') {
            steps {
                container('tools') {
                    checkout scm
                }
                updateGitlabCommitStatus(name: env.STAGE_NAME, state: 'success')
                script{
                    env.BUILD_TASKS = env.STAGE_NAME + "√..." + env.TAB_STR
                }
            }
        }
        stage('CI'){
            failFast true
            parallel {
                stage('Unit Test') {
                    steps {
                        echo "Unit Test Stage Skip..."
                    }
                }
                stage('Code Scan') {
                    steps {
                        container('tools') {
                            withSonarQubeEnv('sonarqube') {
                                sh 'sonar-scanner -X'
                                sleep 3
                            }
                            script {
                                timeout(1) {
                                    def qg = waitForQualityGate('sonarqube')
                                    if (qg.status != 'OK') {
                                        error "未通过Sonarqube的代码质量阈检查,请及时修改!failure: ${qg.status}"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        stage('build-image') {
            steps {
                container('tools') {
                    retry(2) { sh 'docker build . -t ${IMAGE_REPO}:${GIT_COMMIT}'}
                }
                updateGitlabCommitStatus(name: env.STAGE_NAME, state: 'success')
                script{
                    env.BUILD_TASKS += env.STAGE_NAME + "√..." + env.TAB_STR
                }
            }
        }
        stage('push-image') {
            steps {
                container('tools') {
                    retry(2) { sh 'docker push ${IMAGE_REPO}:${GIT_COMMIT}'}
                }
                updateGitlabCommitStatus(name: env.STAGE_NAME, state: 'success')
                script{
                    env.BUILD_TASKS += env.STAGE_NAME + "√..." + env.TAB_STR
                }
            }
        }
        stage('deploy') {
            steps {
                container('tools') {
                    sh "sed -i 's#{{IMAGE_URL}}#${IMAGE_REPO}:${GIT_COMMIT}#g' manifests/*"
                    timeout(time: 1, unit: 'MINUTES') {
                        sh "kubectl apply -f manifests/"
                    }
                }
                updateGitlabCommitStatus(name: env.STAGE_NAME, state: 'success')
                script{
                    env.BUILD_TASKS += env.STAGE_NAME + "√..." + env.TAB_STR
                }
            }
        }
    }
    post {
        success { 
            echo 'Congratulations!'
            sh """
                curl 'https://oapi.dingtalk.com/robot/send?access_token=${DINGTALK_CREDS_PSW}' \
                    -H 'Content-Type: application/json' \
                    -d '{
                        "msgtype": "markdown",
                        "markdown": {
                            "title":"myblog",
                            "text": "😄👍 构建成功 👍😄  \n**项目名称**:luffy  \n**Git log**: ${GIT_LOG}   \n**构建分支**: ${BRANCH_NAME}   \n**构建地址**:${RUN_DISPLAY_URL}  \n**构建任务**:${BUILD_TASKS}"
                        }
                    }'
            """ 
        }
        failure {
            echo 'Oh no!'
            sh """
                curl 'https://oapi.dingtalk.com/robot/send?access_token=${DINGTALK_CREDS_PSW}' \
                    -H 'Content-Type: application/json' \
                    -d '{
                        "msgtype": "markdown",
                        "markdown": {
                            "title":"myblog",
                            "text": "😖❌ 构建失败 ❌😖  \n**项目名称**:luffy  \n**Git log**: ${GIT_LOG}   \n**构建分支**: ${BRANCH_NAME}  \n**构建地址**:${RUN_DISPLAY_URL}  \n**构建任务**:${BUILD_TASKS}"
                        }
                    }'
            """
        }
        always { 
            echo 'I will always say Hello again!'
        }
    }
}

若 Jenkins 执行任务过程中 sonarqube 端报类似下图的错:

在这里插入图片描述

则需要在 sonarqube 服务端进行如下配置,添加一个 webhook:

在这里插入图片描述

3. Jenkins集成robotFramework

集成 RobotFramework 实现验收测试

一个基于 Python 语言,用于验收测试和验收测试驱动开发(ATDD)的通用测试自动化框架,提供了一套特定的语法,并且有非常丰富的测试库 。

🍑 robot用例简介

robot/robot.txt

*** Settings ***
Library           RequestsLibrary
Library           SeleniumLibrary

*** Variables ***
${demo_url}       http://myblog.luffy/admin

*** Test Cases ***
api
    [Tags]  critical
    Create Session    api    ${demo_url}
    ${alarm_system_info}    RequestsLibrary.Get Request    api    /
    log    ${alarm_system_info.status_code}
    log    ${alarm_system_info.content}
    should be true    ${alarm_system_info.status_code} == 200

ui
    [Tags]  critical
    ${chrome_options} =     Evaluate    sys.modules['selenium.webdriver'].ChromeOptions()    sys, selenium.webdriver
    Call Method    ${chrome_options}   add_argument    headless
    Call Method    ${chrome_options}   add_argument    no-sandbox
    ${options}=     Call Method     ${chrome_options}    to_capabilities
    Open Browser    ${demo_url}/    browser=chrome       desired_capabilities=${options}
    sleep    2s
    Capture Page Screenshot
    Page Should Contain    Django
    close browser
# 使用tools镜像启动容器,来验证手动使用robotframework来做验收测试
$ docker run --rm -ti 172.21.51.143:5000/devops/tools:v2 bash
bash-5.0# apk add chromium chromium-chromedriver
$ cat requirements.txt
robotframework
robotframework-seleniumlibrary
robotframework-databaselibrary
robotframework-requests

#pip安装必要的软件包
$ pip install -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com -r requirements.txt 

#使用robot命令做测试
$ robot -d artifacts/ robot.txt

🍑 与 tools 工具镜像集成

FROM alpine:3.13.4
LABEL maintainer="inspur_lyx@hotmail.com"
USER root

RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories && \
    apk update && \
    apk add  --no-cache openrc docker git curl tar gcc g++ make \
    bash shadow openjdk8 python2 python2-dev py-pip python3-dev openssl-dev libffi-dev \
    libstdc++ harfbuzz nss freetype ttf-freefont chromium chromium-chromedriver && \
    mkdir -p /root/.kube && \
    usermod -a -G docker root


COPY config /root/.kube/

COPY requirements.txt /

RUN pip install -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com -r requirements.txt 


RUN rm -rf /var/cache/apk/* && \
    rm -rf ~/.cache/pip

#-----------------安装 kubectl--------------------#
COPY kubectl /usr/local/bin/
RUN chmod +x /usr/local/bin/kubectl
# ------------------------------------------------#

#---------------安装 sonar-scanner-----------------#
COPY sonar-scanner /usr/lib/sonar-scanner
RUN ln -s /usr/lib/sonar-scanner/bin/sonar-scanner /usr/local/bin/sonar-scanner && chmod +x /usr/local/bin/sonar-scanner
ENV SONAR_RUNNER_HOME=/usr/lib/sonar-scanner
# ------------------------------------------------#
$ docker build . -t 172.21.51.143:5000/devops/tools:v3

$ docker push 172.21.51.143:5000/devops/tools:v3

更新 Jenkins 中 kubernetes 中的 containers template

🍑 插件安装及配置

为什么要安装 robot 插件?

  1. 安装 robotFramework

    • 插件中心搜索 robotframework,直接安装
    • tools 集成 robot命令(之前已经安装)
  2. 与 jenkinsfile 的集成

    container('tools') {
        sh 'robot -i critical  -d artifacts/ robot.txt'
        echo "R ${currentBuild.result}"
        step([
            $class : 'RobotPublisher',
            outputPath: 'artifacts/',
            outputFileName : "output.xml",
            disableArchiveOutput : false,
            passThreshold : 80,
            unstableThreshold: 20.0,
            onlyCritical : true,
            otherFiles : "*.png"
        ])
        echo "R ${currentBuild.result}"
        archiveArtifacts artifacts: 'artifacts/*', fingerprint: true
    }

🍑 实践通过Jenkinsfile实现demo项目的验收测试

python-demo 项目添加 robot.txt 文件:

jenkins/pipelines/p10.yaml

pipeline {
    agent { label 'jnlp-slave'}
    
    options {
		buildDiscarder(logRotator(numToKeepStr: '10'))
		disableConcurrentBuilds()
		timeout(time: 20, unit: 'MINUTES')
		gitLabConnection('gitlab')
	}

    environment {
        IMAGE_REPO = "172.21.51.143:5000/myblog"
        DINGTALK_CREDS = credentials('dingTalk')
        TAB_STR = "\n                    \n                    "
    }

    stages {
        stage('git-log') {
            steps {
                script{
                    sh "git log --oneline -n 1 > gitlog.file"
                    env.GIT_LOG = readFile("gitlog.file").trim()
                }
                sh 'printenv'
            }
        }        
        stage('checkout') {
            steps {
                container('tools') {
                    checkout scm
                }
                updateGitlabCommitStatus(name: env.STAGE_NAME, state: 'success')
                script{
                    env.BUILD_TASKS = env.STAGE_NAME + "√..." + env.TAB_STR
                }
            }
        }
        stage('CI'){
            failFast true
            parallel {
                stage('Unit Test') {
                    steps {
                        echo "Unit Test Stage Skip..."
                    }
                }
                stage('Code Scan') {
                    steps {
                        container('tools') {
                            withSonarQubeEnv('sonarqube') {
                                sh 'sonar-scanner -X'
                                sleep 3
                            }
                            script {
                                timeout(1) {
                                    def qg = waitForQualityGate('sonarqube')
                                    if (qg.status != 'OK') {
                                        error "未通过Sonarqube的代码质量阈检查,请及时修改!failure: ${qg.status}"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        stage('build-image') {
            steps {
                container('tools') {
                    retry(2) { sh 'docker build . -t ${IMAGE_REPO}:${GIT_COMMIT}'}
                }
                updateGitlabCommitStatus(name: env.STAGE_NAME, state: 'success')
                script{
                    env.BUILD_TASKS += env.STAGE_NAME + "√..." + env.TAB_STR
                }
            }
        }
        stage('push-image') {
            steps {
                container('tools') {
                    retry(2) { sh 'docker push ${IMAGE_REPO}:${GIT_COMMIT}'}
                }
                updateGitlabCommitStatus(name: env.STAGE_NAME, state: 'success')
                script{
                    env.BUILD_TASKS += env.STAGE_NAME + "√..." + env.TAB_STR
                }
            }
        }
        stage('deploy') {
            steps {
                container('tools') {
                    sh "sed -i 's#{{IMAGE_URL}}#${IMAGE_REPO}:${GIT_COMMIT}#g' manifests/*"
                    timeout(time: 1, unit: 'MINUTES') {
                        sh "kubectl apply -f manifests/;sleep 20;"
                    }
                }
                updateGitlabCommitStatus(name: env.STAGE_NAME, state: 'success')
                script{
                    env.BUILD_TASKS += env.STAGE_NAME + "√..." + env.TAB_STR
                }
            }
        }
        stage('Accept Test') {
            steps {
                    container('tools') {
                        sh 'robot -i critical  -d artifacts/ robot.txt|| echo ok'
                        echo "R ${currentBuild.result}"
                        step([
                            $class : 'RobotPublisher',
                            outputPath: 'artifacts/',
                            outputFileName : "output.xml",
                            disableArchiveOutput : false,
                            passThreshold : 80,
                            unstableThreshold: 20.0,
                            onlyCritical : true,
                            otherFiles : "*.png"
                        ])
                        echo "R ${currentBuild.result}"
                        archiveArtifacts artifacts: 'artifacts/*', fingerprint: true
                    }
            }
        }
    }
    post {
        success { 
            echo 'Congratulations!'
            sh """
                curl 'https://oapi.dingtalk.com/robot/send?access_token=${DINGTALK_CREDS_PSW}' \
                    -H 'Content-Type: application/json' \
                    -d '{
                        "msgtype": "markdown",
                        "markdown": {
                            "title":"myblog",
                            "text": "😄👍 构建成功 👍😄  \n**项目名称**:luffy  \n**Git log**: ${GIT_LOG}   \n**构建分支**: ${BRANCH_NAME}   \n**构建地址**:${RUN_DISPLAY_URL}  \n**构建任务**:${BUILD_TASKS}"
                        }
                    }'
            """ 
        }
        failure {
            echo 'Oh no!'
            sh """
                curl 'https://oapi.dingtalk.com/robot/send?access_token=${DINGTALK_CREDS_PSW}' \
                    -H 'Content-Type: application/json' \
                    -d '{
                        "msgtype": "markdown",
                        "markdown": {
                            "title":"myblog",
                            "text": "😖❌ 构建失败 ❌😖  \n**项目名称**:luffy  \n**Git log**: ${GIT_LOG}   \n**构建分支**: ${BRANCH_NAME}  \n**构建地址**:${RUN_DISPLAY_URL}  \n**构建任务**:${BUILD_TASKS}"
                        }
                    }'
            """
        }
        always { 
            echo 'I will always say Hello again!'
        }
    }
}

在 Jenkins 中查看 robot 的构建结果。

4. 总结与反思

通过这三篇文章,主要学习了以下几个方面:

  1. 讲解最基础的 Jenkins 的使用
  2. Pipeline 流水线的使用
  3. Jenkinsfile 的使用
  4. 多分支流水线的使用
  5. 与 Kubernetes 集成,动态 jnlp slave pod 的使用
  6. 与 sonarqube 集成,实现代码扫描
  7. 与 Robotframework 集成,实现验收测试

但是,也存在一些问题:

  1. Jenkinsfile 过于冗长
  2. 多个项目配置 Jenkinsfile,存在很多重复内容
  3. 没有实现根据不同分支来部署到不同的环境
  4. Java 项目的构建
  5. k8s部署后,采用等待的方式执行后续步骤,不合理

后面会通过 sharedLibrary 对进行 CI/CD 流程进行一个优化

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

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

相关文章

初阶产品经理必看:如何快速进阶B端产品经理

​从去年开始,大批的互联网企业开始转战B端,众多传统企业也早在几年前就开始向互联网转型。 产业互联网的兴起,让一个岗位的潜藏价值正在逐渐爆发,尤其是富有经验的背景,更加让身价越来越高。 这个岗位就是&#xff…

QProcess的非阻塞式用法以及QApplication::processEvents的使用

一、QProcess的阻塞模式QProcess的应用场景非常广泛。可以使用它在qt程序中执行其他进程,并与之进行通信。当使用它执行一些终端命令和操作时,命令和操作往往是需要一定的时间的,这时QProcess本身提供了方法如:waitForStarted() /…

神经网络自适应PID控制及其应用

神经网络自适应PID控制及其应用 总结来自重庆大学宋永瑞教授2022暑期校园行学术会议 1. 研究背景 目前人工智能的发展为很多领域里的研究提供了可延展性,提供了新的研究问题的思路,无人系统和人工智能正走向深度融合,无人系统里具有核心驱动作…

C语言及算法设计课程实验三:最简单的C程序设计——顺序程序设计(四)

C语言及算法设计课程实验三:最简单的C程序设计——顺序程序设计(四)一、实验目的二、 实验内容2.4、将"China”译成密码三、 实验步骤3.4、顺序程序设计实验题目4:将"China”译成密码的实验步骤3.4.1、变量的定义与赋初…

Android EventBus源码深入解析

前言 EventBus:是一个针对Android进行了优化的发布/订阅事件总线。 github对应地址:EventBus 大家肯定都已经比较熟悉了,这里重点进行源码分析; EventBus源码解析 我们重点从以下三个方法入手,弄清楚register、unre…

关于sql注入这一篇就够了(适合入门)

本文章根据b站迪总课程总结出来,若有不足请见谅 目录 存在sql注入条件 判断数据库类型 注入mysql思路 判断网站是否存在注入点 判断列名数量(字段数) 文件读写操作 网站路径获取方法 注入类型 按注入点数据类型来分类 根据提交方式分类 猜测查询方式 sql…

(Java高级教程)第三章Java网络编程-第四节:TCP流套接字(ServerSocket)编程

文章目录一:Java流套接字通信模型二:相关API详解(1)ServerSocket(2)Socket三:TCP通信示例一:客户端发送什么服务端就返回什么(1)代码(2&#xff0…

量子计算(二十一):Deutsch-Josza算法

文章目录 Deutsch-Josza算法 Deutsch-Josza算法 量子算法是量子计算落地实用的最大驱动力,好的量子算法设计将更快速推动量子计算的发展。 Deutsch-Jozsa量子算法,简称D-J算法,DavidDeutsch和RichardJozsa早在1992年提出了该算法&#xff0…

分布式事务方案分析:两阶段和TCC方案(图+文)

1 缘起 补充事务相关知识过程中, 发现,默认的知识都是基于单体服务的事务,比如ACID, 然而,在一些复杂的业务系统中,采用微服务架构构建各自的业务, 就有了分布式事务的概念,比如&am…

一站式云原生体验|龙蜥云原生ACNS + Rainbond

关于 ACNS 龙蜥云原生套件 OpenAnolis Cloud Native Suite(ACNS)是由龙蜥社区云原生 SIG 推出的基于 Kubernetes 发行版本为基础而集成的套件能力,可以提供一键式部署,开箱即用,以及丰富的云原生基础能力,…

JProfiler的使用

一、安装 从https://www.ej-technologies.com/download/jprofiler/files获取,如果需要对服务器远程分析,注意服务器版本的jprofiler和windows版本一致。 二、监控一个本地进程 2.1 不使用idea 安装之后,打开jprofiler,点击红框…

电脑蓝屏并提示BAD_POOL_CALLER怎么办?

电脑蓝屏可以说是Windows的常见问题,各种各样的终止代码对应着不同的问题。如果你的蓝屏代码显示BAD_POOL_CALLER,这篇文章就是为你提供的。 可能导致BAD_POOL_CALLER蓝屏错误的原因: 1、硬件或软件不兼容 2、过时或错误的设备驱动程序 3…

DataWorks创建JavaUDF函数全流程

文章目录插件下载创建MaxCompute Studio项目创建MaxCompute Java Module编写Java UDF函数注意说明:这篇文章只是个人记录下,具体步骤都可以在官网找到。推荐看官网文档哈 插件下载 创建MaxCompute Studio项目 启动IntelliJ IDEA,在顶部菜单栏…

1806. 还原排列的最少操作步数

解法一: 根据题目的题目描述进行模拟,遇到偶数iii将arr[i]prem[i/2]arr[i] prem[i/2]arr[i]prem[i/2],遇到奇数iii,将arr[i]prem[(n−1i)/2]arr[i]prem[(n-1i)/2]arr[i]prem[(n−1i)/2] 时间复杂度: O(n2)O(n^2)O(n2), 最多会循环n次空间复杂度&#…

Nginx反向代理使用方法小总结

文章目录一、前言二、反向代理定义重申三、短网址方式代理四、多级域名方式代理五、通配符代理方式总结一、前言 本文只介绍代理转发到一个主机的方式,至于在代理时进行负载均衡大家需要自己尝试,也比较简单,在本专栏前面文章提到过&#xf…

(二)Redis概述与安装

目录 一、概述 1、特性 2、应用场景 二、安装 三、启动 1、前台启动(不推荐) 2、后台启动(推荐) 四、redis关闭 五、redis相关知识介绍 一、概述 1、特性 Redis是一个开源的key-value存储系统。和Memcached类似&#x…

TOOM舆情分析监控管理系统集成,舆情监控系统监测那些人群?

当前,互联网已成为思想文化信息的集散地和社会舆论的扩大器,舆情监控新闻、论坛博客、聚合新闻等等,做好舆情监控,至于监测那些人群,舆情分析监控是非常必要的,接下来我们简单了解TOOM舆情分析监控管理系统…

接口协议之抓包分析 TCP 协议

TCP 协议是在传输层中,一种面向连接的、可靠的、基于字节流的传输层通信协议。环境准备对接口测试工具进行分类,可以如下几类:网络嗅探工具:tcpdump,wireshark代理工具:fiddler,charles&#xf…

《移动通信》多章节部分重要习题(简答、单选、判断)

调制技术在移动通信中的作用? 调制有两个目的: 1 )经过调制可以使基带信号变换为带通信号。选择需要使用的载波频率 ( 简称载频 ) ,可以把信号的频谱从开始的频段转移到到所需要的频段上,从而使传输信号适应信道的要求,或是可以把许多个输入信号合起来应用于多路传…

开发模型 和 测试模型 详解

开发模型 开发模型 : ① 瀑布模型 ② 螺旋模型 ③ 增量模型 和 迭代模型 ④ 敏捷模型 (优点 缺点 适用场景)测试模型 : ① V模型 ② W模型瀑布模型优点/特点:线性结构,每个阶段 只执行一次是其他模型的一个基础框架缺点&#xff1…