KubeSphere DevOps 构建流水线

1,844 阅读4分钟

概述

DevOps 是一系列做法和工具,可以使 IT 和软件开发团队之间的流程实现自动化。其中,随着敏捷软件开发日趋流行,持续集成 (CI) 和持续交付 (CD) 已经成为该领域一个理想的解决方案。在 CI/CD 工作流中,每次集成都通过自动化构建来验证,包括编码、发布和测试,从而帮助开发者提前发现集成错误,团队也可以快速、安全、可靠地将内部软件交付到生产环境。
不过,传统的 Jenkins Master-Agent 架构(即多个 Agent 为一个 Master 工作)有以下不足。

如果 Master 宕机,整个 CI/CD 流水线会崩溃。 资源分配不均衡,一些 Agent 的流水线任务 (Job) 出现排队等待,而其他 Agent 处于空闲状态。 不同的 Agent 可能配置环境不同,并需要使用不同的编码语言。这种差异会给管理和维护带来不便。

了解 KubeSphere DevOps

KubeSphere DevOps 工程支持源代码管理工具,例如 GitHub、Git 和 SVN。用户可以通过图形编辑面板 (Jenkinsfile out of SCM) 构建 CI/CD 流水线,或者从代码仓库 (Jenkinsfile in SCM) 创建基于 Jenkinsfile 的流水线。

KubeSphere CI/CD 流水线工作流

KubeSphere CI/CD 流水线基于底层 Kubernetes Jenkins Agent 而运行。这些 Jenkins Agent 可以动态扩缩,即根据任务状态进行动态供应或释放。Jenkins Master 和 Agent 以 Pod 的形式运行在 KubeSphere 节点上。Master 运行在其中一个节点上,其配置数据存储在一个存储卷 (Volume) 中。Agent 运行在各个节点上,但可能不会一直处于运行状态,而是根据需求动态创建并自动删除。 ​

当 Jenkins Master 收到构建请求,会根据标签动态创建运行在 Pod 中的 Jenkins Agent 并注册到 Master 上。当 Agent 运行完任务后,将会被释放,相关的 Pod 也会被删除。

动态供应 Jenkins Agent

动态供应 Jenkins Agent 有以下优势: 资源分配合理:KubeSphere 动态分配已创建的 Agent 至空闲节点,避免因单个节点资源利用率高而导致任务排队等待。 高可扩缩性:当 KubeSphere 集群因资源不足而导致任务长时间排队等待时,您可以向集群新增节点。 高可用性:当 Jenkins Master 故障时,KubeSphere 会自动创建一个新的 Jenkins Master 容器,并将存储卷挂载至新创建的容器,保证数据不会丢失,从而实现集群高可用。

DevOps 开发

启用 DevOps

  1. 以 admin 身份登录控制台,点击左上角的平台管理,选择集群管理

2.点击自定义资源 CRD,在搜索栏中输入 clusterconfiguration,点击搜索结果查看其详细页面。 image.png3.在资源列表中,点击 ks-installer 右侧的 ,选择编辑配置文件image.png 4.在该 YAML 文件中,搜寻到 devops,将 enabled 的 false 改为 true。完成后,点击右下角的更新,保存配置 image.png 5.然后输入以下命令查看安装日志

kubectl logs -n kubesphere-system $(kubectl get pod -n kubesphere-system -l app=ks-install -o jsonpath='{.items[0].metadata.name}') -f

6.出现此界面即为安装成功 image.png

集成SonarQube

1.请先安装 Helm,以便后续使用该工具安装 SonarQube。例如,运行以下命令安装 Helm 3:

curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash

2.安装sonarqube服务器

helm upgrade --install sonarqube sonarqube --repo https://charts.kubesphere.io/main -n kubesphere-devops-system  --create-namespace --set service.type=NodePort

3.执行以下命令获取sonarqube服务器地址

export NODE_PORT=$(kubectl get --namespace kubesphere-devops-system -o jsonpath="{.spec.ports[0].nodePort}" services sonarqube-sonarqube)
export NODE_IP=$(kubectl get nodes --namespace kubesphere-devops-system -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT

image.png 4.查看SonarQube pod 状态,待全部安装完成功运行后访问服务器,然后使用admin/admin账户密码登录 5.依次点击 MyAccount->security->generate 生成token复制并保留 image.png 6.获取 Jenkins 的 SonarQube Webhook 地址

export NODE_PORT=$(kubectl get --namespace kubesphere-devops-system -o jsonpath="{.spec.ports[0].nodePort}" services ks-jenkins)
export NODE_IP=$(kubectl get nodes --namespace kubesphere-devops-system -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT/sonarqube-webhook/

image.png 7.依次点击 AdministrationConfigurationWebhooks 创建一个 Webhook。 image.png 8.将 SonarQube 配置添加到 ks-installer (参考步骤四中截图的sonarqube配置) 9.登录Jenkins,账号密码同kubesphere (地址获取参考步骤6 去掉后缀) 10.点击 系统管理-> 系统配置-> 找到 SonarQube Servers 一栏 添加凭证,secret 输入步骤5生成号的token, 类型选择Secret text ,ID 自定义。随后填写sonarqube 服务信息 image.png image.png 11.将 sonarqubeURL 添加到 KubeSphere 控制台,就可以直接通过控制台直接跳转到sonarqube image.png

#执行命令 添加sonarqube 地址并保存
kubectl edit  cm -n kubesphere-system  ks-console-config

image.png 12.重启ks-apiserver和ks-console

kubectl -n kubesphere-system rollout restart deploy ks-apiserver
kubectl -n kubesphere-system rollout restart deploy ks-console

image.png

集成流水线

1.使用kubesphere 创建企业空间,创建企业空间管理员,项目管理员,项目开发员,参考kubesphere.com.cn/docs/quick-… 2.使用项目管理员创建一个devOps项目 image.png 3.点击项目创建流水线,在参数化构建地方加三个String参数。分别是 REGISTRY docker 镜像仓库地址,DOCKERHUB_NAMESPACE docker仓库名称空间,APP_NAME 项目名称 image.png 4.凭证的添加,在devops工程下面创建凭证 image.png image.png git账号和dockerhub账户都属于账户凭证一类,输入账号密码即可。sonarqube则需要选择秘密文本类型,将之前保存的token粘贴即可。

5.点击流水线进入其详情页面。要使用图形编辑面板,请点击流水线选项卡下的编辑流水线。在弹出对话框中,点击**自定义流水线,进行编辑。**或者编辑jenkinsfile。下面用jenkinsfile示例: jenkins流水线语法传送门

pipeline {
  agent { # 指示 Jenkins 为整个流水线分配一个执行器(在 Jenkins 环境中的任何可用代理/节点上)和工作区
    node {
      label 'maven' # 整个流水线将会运行在标签为maven的节点上
    }

  }
  stages {
    stage('Checkout SCM') { # 拉取代码,需要携带id为gitee-id的凭证信息
      agent none
      steps {
        git(url: 'https://gitee.com/xxx.git', credentialsId: 'gitee-id', branch: 'master', changelog: true, poll: false)
      }
    }

    stage('Unit Test') { #执行单元测试
      steps {
        container('maven') { # 指定容器
          sh 'mvn clean -o -gs `pwd`/configuration/settings.xml test' #在指定容器下执行shell脚本
        }

      }
    }

    stage('Code Analysis') { #执行代码分析
      steps {
        container('maven') {
          withCredentials([string(credentialsId : 'sonar-token' ,variable : 'SONAR_TOKEN' ,)]) {
            withSonarQubeEnv('sonar') { #携带凭证 使用sonar环境 执行脚本
              sh 'mvn sonar:sonar -o -gs `pwd`/configuration/settings.xml -Dsonar.login=$SONAR_TOKEN'
            }

          }

          timeout(unit: 'HOURS', activity: true, time: 1) { # 无日志输出后开始计算超时时间
            waitForQualityGate 'true' #等待质量分析是否影响后续业务继续进行
            #代码质量检查标准来源于SonarQube的 Quality Gate (质量阈),如果需要自定义检查标准请前往 SonarQube 设置
          }

        }

      }
    }

    stage('Build and Push') { # 构建并发布
      agent none
      steps {
        container('maven') { #根据dockerFile构建镜像并push到远端仓库
          sh 'mvn -o -Dmaven.test.skip=true -gs `pwd`/configuration/settings.xml clean package'
          sh 'docker build -f Dockerfile-online -t $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:SNAPSHOT-$BUILD_NUMBER .'
          withCredentials([usernamePassword(credentialsId : 'dockerhub-id' ,passwordVariable : 'DOCKER_PASSWORD' ,usernameVariable : 'DOCKER_USERNAME' ,)]) {
            sh 'echo "$DOCKER_PASSWORD" | docker login $REGISTRY -u "$DOCKER_USERNAME" --password-stdin'
          }

          sh 'docker push $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:SNAPSHOT-$BUILD_NUMBER'
        }

      }
    }

    stage('update-yml') { #更新deployment的部署文件中容器镜像为刚刚push的
      agent none
      steps {
        container('maven') {
          sh 'sed -i "s/\\$REGISTRY\\/\\$DOCKERHUB_NAMESPACE\\/\\$APP_NAME:\\$TAG_NAME/\\"$REGISTRY\\/$DOCKERHUB_NAMESPACE\\/$APP_NAME:SNAPSHOT-$BUILD_NUMBER\\"/g" `pwd`/deploy/prod-ol/devops-sample.yaml'
        }

      }
    }

    stage('Artifacts') { #保存构建的jar包到项目构建空间下
      steps {
        archiveArtifacts 'target/*.jar'
      }
    }

    stage('Deploy to Dev') { #部署到dev
      agent none
      steps {
        input '是否部署至dev环境' # 提示用户,如果同意stage会继续
        container('maven') {
          sh '''kubectl apply -f `pwd`/deploy/prod-ol/devops-sample.yaml
kubectl apply -f `pwd`/deploy/prod-ol/devops-sample-svc.yaml'''
        }

      }
    }

  }
}

6.运行流水线 image.png 查看日志 image.png 7.查看代码分析 image.png image.png 8.查看工作负载 image.png 查看部署成功的应用 image.png 返回上层查看服务,查看暴露端口并进行访问 image.png 访问成功! image.png 9.也可登录Jenkins查看构建 image.png