您当前的位置:首页 > 电脑百科 > 程序开发 > 编程百科

使用 Jenkins 与 KubeVela 实现应用的持续交付

时间:2023-10-19 13:34:14  来源:微信公众号  作者:k8s技术圈

使用 Jenkins 与 KubeVela 实现应用的持续交付

KubeVela 打通了应用与基础设施之间的交付管控的壁垒,相较于原生的 Kube.NETes 对象,KubeVela 的 Application 更好地简化抽象了开发者需要关心的配置,将复杂的基础设施能力及编排细节留给了平台工程师。而 KubeVela 的 apiserver 则是进一步为开发者提供了使用 HTTP Request 直接操纵 Application 的途径,使得开发者即使没有 Kubernetes 的使用经验与集群访问权限也可以轻松部署自己的应用。

接下来我们就以 Jenkins 为基础,结合 KubeVela 来实现一个简单的应用持续交付的流程。

要实现一个简单的应用持续交付,我们需要做如下几件事情:

  • 需要一个 git 仓库来存放应用程序代码、测试代码,以及描述 KubeVela Application 的 YAML 文件。
  • 需要一个持续集成的工具帮你自动化完成程序代码的测试,并打包成镜像上传到仓库中。
  • 需要在 Kubernetes 集群上安装 KubeVela 并启用 apiserver 功能。

我们这里的演示 Demo 采用 Github 作为 git 仓库,Jenkins 作为 CI 工具,DockerHub 作为镜像仓库。应用程序以一个简单的 Golang HTTP Server 为例,整个持续交付的流程如下。

使用 Jenkins 与 KubeVela 实现应用的持续交付

交付流程

从整个流程可以看出开发者只需要关心应用的开发并使用 Git 进行代码版本的维护,即可自动走完测试流程并部署应用到 Kubernetes 集群中。

关于 Jenkins 在 Kubernetes 集群中的安装配置前面我们已经介绍过了,这里我们就不再赘述。

应用配置

这里我们采用了 Github 作为代码仓库,仓库地址为 https://github.com/cnych/KubeVela-demo-CICD-app,当然也可以根据各自的需求与喜好,使用其他代码仓库,如 Gitlab。为了 Jenkins 能够获取到 GitHub 中的更新,并将流水线的运行状态反馈回 GitHub,需要在 GitHub 中完成以下两步操作。

配置 Personal Access Token。注意将 repo:status 勾选,以获得向 GitHub 推送 Commit 状态的权限,将生成的 Token 复制下来,下面会用到。

使用 Jenkins 与 KubeVela 实现应用的持续交付

Personal Access Token

然后在 Jenkins 的 Credential 中加入 Secret Text 类型的 Credential 并将上述的 GitHub 的 Personal Access Token 填入。

使用 Jenkins 与 KubeVela 实现应用的持续交付

jenkins-secret-text

接下来到 Jenkins 的 Dashboard > Manage Jenkins > Configure System > GitHub 中点击 Add GitHub Server 并将刚才创建的 Credential 填入。完成后可以点击 Test connection 来验证配置是否正确。

使用 Jenkins 与 KubeVela 实现应用的持续交付

Add GitHub Server

由于我们这里的 Jenkins 位于本地环境,要让 GitHub 通过 Webhook 来触发 Jenkins,我们需要提供一个可访问的地址,这里我们可以使用 ngrok 来实现,首先前往 https://dashboard.ngrok.com 注册一个账号,将 Authtoken 和 APIKEY 记录下来。

export NGROK_AUTHTOKEN=<your-ngrok-authtoken>
export NGROK_API_KEY=<your-ngrok-apikey>

然后我们可以在本地 Kubernetes 集群中安装 ngrok ingress controller:

helm repo add ngrok https://ngrok.github.io/kubernetes-ingress-controller
# 使用下面命令安装 ngrok ingress controller
helm install ngrok-ingress-controller ngrok/kubernetes-ingress-controller 
--namespace ngrok-ingress-controller 
--create-namespace 
--set credentials.apiKey=$NGROK_API_KEY 
--set credentials.authtoken=$NGROK_AUTHTOKEN

安装完成后为 Jenkins 创建一个 ngrok 的 ingress 路由:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
 name: jenkins-ngrok
 namespace: kube-ops
spec:
 ingressClassName: ngrok
 rules:
   - host: prompt-adjusted-sculpin.ngrok-free.app
     http:
       paths:
         - backend:
             service:
               name: jenkins
               port:
                 name: web
           path: /
           pathType: Prefix

上面的 host 域名是 ngrok 为我们分配的,你可以在 ngrok 的控制台中手动创建,应用上面的 ingress 对象后我们就可以通过 ngrok 为我们分配的域名来访问 Jenkins 了。

使用 Jenkins 与 KubeVela 实现应用的持续交付

ngrok jenkins

接下来我们就可以在 GitHub 的代码仓库的设定里添加 Webhook,将 Jenkins 的地址对应的 Webhook 地址填入 <ngrok domAIn>/github-webhook/,这样该代码仓库的所有 Push 事件推送到 Jenkins 中。

使用 Jenkins 与 KubeVela 实现应用的持续交付

github webhook

编写应用

我们这里采用的应用是一个基于 Golang 语言编写的简单的 HTTP Server。在代码中,声明了一个名叫 VERSION 的常量,并在访问该服务时打印出来。同时还附带一个简单的测试,用来校验 VERSION 的格式是否符合标准。

// main.go
package main

import (
    "fmt"
    "net/http"
)

const VERSION = "0.1.0-v1alpha1"

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        _, _ = fmt.Fprintf(w, "Version: %sn", VERSION)
    })
    if err := http.ListenAndServe(":8088", nil); err != nil {
        println(err.Error())
    }
}

测试代码如下所示:

// main_test.go

package main

import (
    "regexp"
    "testing"
)

const verRegex string = `^v?([0-9]+)(.[0-9]+)?(.[0-9]+)?` +
    `(-([0-9A-Za-z-]+(.[0-9A-Za-z-]+)*))?` +
    `(+([0-9A-Za-z-]+(.[0-9A-Za-z-]+)*))?$`

func TestVersion(t *testing.T) {
    if ok, _ := regexp.MatchString(verRegex, VERSION); !ok {
        t.Fatalf("invalid version: %s", VERSION)
    }
}

在应用交付时需要将 Golang 服务打包成镜像并以 KubeVela Application 的形式发布到 Kubernetes 集群中,因此在代码仓库中还包含 Dockerfile 文件,用来描述镜像的打包方式。

# Dockerfile
FROM golang:1.13-rc-alpine3.10 as builder
WORKDIR /app
COPY main.go .
RUN go build -o kubevela-demo-cicd-app main.go

FROM alpine:3.10
WORKDIR /app
COPY --from=builder /app/kubevela-demo-cicd-app /app/kubevela-demo-cicd-app
ENTRYPOINT ./kubevela-demo-cicd-app
EXPOSE 8088

配置 CI 流水线

在这里我们将包含两条流水线,一条是用来进行测试的流水线 (对应用代码运行测试) ,一条是交付流水线 (将应用代码打包上传镜像仓库,同时更新目标环境中的应用,实现自动更新) 。

测试流水线

在 Jenkins 中创建一条新的名为 KubeVela-demo-CICD-app-test 的流水线:

使用 Jenkins 与 KubeVela 实现应用的持续交付

测试流水线

然后配置构建触发器为 GitHub hook trigger for GITScm polling:

使用 Jenkins 与 KubeVela 实现应用的持续交付

构建触发器

在这条流水线中,首先是采用了 golang 的镜像作为执行环境,方便后续运行测试。然后将分支配置为 GitHub 仓库中的 dev 分支,代表该条流水线被 Push 事件触发后会拉取 dev 分支上的内容并执行测试,测试结束后将流水线的状态回写至 GitHub 中。这里我们使用的是基于 Kubernetes 的动态 Slave Agent,因此在流水线中需要配置 Kubernetes 的相关信息,包括 Kubernetes 的地址、Service Account 等。

void setBuildStatus(String message, String state) {
  step([
      $class: "GitHubCommitStatusSetter",
      reposSource: [$class: "ManuallyEnteredRepositorySource", url: "https://github.com/cnych/KubeVela-demo-CICD-app"],
      contextSource: [$class: "ManuallyEnteredCommitContextSource", context: "ci/jenkins/test-status"],
      errorHandlers: [[$class: "ChangingBuildStatusErrorHandler", result: "UNSTABLE"]],
      statusResultSource: [ $class: "ConditionalStatusResultSource", results: [[$class: "AnyBuildResult", message: message, state: state]] ]
  ]);
}

pipeline {
  agent {
    kubernetes {
      cloud 'Kubernetes'
      containerTemplate {
        name 'golang'
        image 'golang:1.13-rc-alpine3.10'
        command 'cat'
        ttyEnabled true
      }
      serviceAccount 'jenkins'
    }
  }

  stages {
    stage('Prepare') {
        steps {
            script {
                def checkout = git branch: 'dev', url: 'https://github.com/cnych/KubeVela-demo-CICD-app.git'
                env.GIT_COMMIT = checkout.GIT_COMMIT
                env.GIT_BRANCH = checkout.GIT_BRANCH
                echo "env.GIT_BRANCH=${env.GIT_BRANCH},env.GIT_COMMIT=${env.GIT_COMMIT}"
            }
            setBuildStatus("Test running", "PENDING");
        }
    }
    stage('Test') {
        steps {
          container('golang') {
            sh 'CGO_ENABLED=0 GOCACHE=$(pwd)/.cache go test *.go'
          }
        }
    }
  }

  post {
    success {
        setBuildStatus("Test success", "SUCCESS");
    }
    failure {
        setBuildStatus("Test failed", "FAILURE");
    }
  }
}

我们可以使用上面的代码来执行流水线:

使用 Jenkins 与 KubeVela 实现应用的持续交付

测试流水线

部署流水线

类似测试流水线创建一个名为 KubeVela-demo-CICD-app-deploy 的部署流水线,首先将代码仓库中的分支拉取下来,区别是这里采用 prod 分支。然后使用 Docker 进行镜像构建并推送至远端镜像仓库。构建成功后,再将 Application 对应的 YAML 文件转换为 JSON 文件并注入 GIT_COMMIT,最后向 KubeVela apiserver 发送请求进行创建或更新。

首先我们需要通过 VelaUX 来创建一个应用,这里我们创建一个名为 kubevela-demo-app 的应用,包含一个名为 kubevela-demo-app-web 的组件,组件类型为 webservice,并将组件的镜像设置为 cnych/kubevela-demo-cicd-app,如下图所示:

使用 Jenkins 与 KubeVela 实现应用的持续交付

kubevela app

在应用面板上,我们可以找到一个默认的触发器,点击 手动触发,我们可以看到 Webhook URL 和 Curl Command,我们可以在 Jenkins 的流水线中使用任意一个。

使用 Jenkins 与 KubeVela 实现应用的持续交付

触发器

Webhook URL 是这个触发器的触发地址,在 Curl Command 里,还提供了手动 Curl 该触发器的请求示例。我们来详细解析一下请求体:

{
  // 必填,此次触发的更新信息
  "upgrade": {
    // Key 为应用的名称
    "<application-name>": {
      // 需要更新的值,这里的内容会被 Patch 更新到应用上
      "image": "<image-name>"
    }
  },
  // 可选,此次触发携带的代码信息
  "codeInfo": {
    "commit": "<commit-id>",
    "branch": "<branch>",
    "user": "<user>"
  }
}

upgrade 下是本次触发要携带的更新信息,在应用名下,是需要被 Patch 更新的值。默认推荐的是更新镜像 image,也可以扩展这里的字段来更新应用的其他属性。codeInfo 中是代码信息,可以选择性地携带,比如 commit ID、分支、提交者等,一般这些值可以通过在 CI 系统中使用变量替换来指定。

然后我们可以是部署流水线中使用上面的触发器来部署应用,的代码如下所示:

void setBuildStatus(String message, String state) {
  step([
      $class: "GitHubCommitStatusSetter",
      reposSource: [$class: "ManuallyEnteredRepositorySource", url: "https://github.com/cnych/KubeVela-demo-CICD-app"],
      contextSource: [$class: "ManuallyEnteredCommitContextSource", context: "ci/jenkins/deploy-status"],
      errorHandlers: [[$class: "ChangingBuildStatusErrorHandler", result: "UNSTABLE"]],
      statusResultSource: [ $class: "ConditionalStatusResultSource", results: [[$class: "AnyBuildResult", message: message, state: state]] ]
  ]);
}
pipeline {
    agent {
      kubernetes {
        cloud 'Kubernetes'
        defaultContainer 'jnlp'
        yaml '''
        spec:
          serviceAccountName: jenkins
          containers:
          - name: golang
            image: golang:1.13-rc-alpine3.10
            command:
            - cat
            tty: true
          - name: docker
            image: docker:latest
            command:
            - cat
            tty: true
            env:
            - name: DOCKER_HOST
              value: tcp://docker-dind:2375
'''
      }
    }
    stages {
        stage('Prepare') {
            steps {
                script {
                    def checkout = git branch: 'prod', url: 'https://github.com/cnych/KubeVela-demo-CICD-app.git'
                    env.GIT_COMMIT = checkout.GIT_COMMIT
                    env.GIT_BRANCH = checkout.GIT_BRANCH
                    echo "env.GIT_BRANCH=${env.GIT_BRANCH},env.GIT_COMMIT=${env.GIT_COMMIT}"
                    setBuildStatus("Deploy running", "PENDING");
                }
            }
        }
        stage('Build') {
            steps {
              withCredentials([[$class: 'UsernamePasswordMultiBinding',
                  credentialsId: 'docker-auth',
                  usernameVariable: 'DOCKER_USER',
                  passwordVariable: 'DOCKER_PASSWORD']]) {
                  container('docker') {
                      sh """
                      docker login -u ${DOCKER_USER} -p ${DOCKER_PASSWORD}
                      docker build -t cnych/kubevela-demo-cicd-app .
                      docker push cnych/kubevela-demo-cicd-app
                      """
                  }
              }
            }
        }
        stage('Deploy') {
            steps {
                sh '''#!/bin/bash
                    set -ex
                    curl -X POST -H 'content-type: application/json' --url http://vela.k8s.local/api/v1/webhook/x0i7t8jdsz2uvime -d '{"action":"execute","upgrade":{"kubevela-demo-app":{"image":"cnych/kubevela-demo-cicd-app"}},"codeInfo":{"commit":"","branch":"","user":""}}'
                '''
            }
        }
    }
    post {
        success {
            setBuildStatus("Deploy success", "SUCCESS");
        }
        failure {
            setBuildStatus("Deploy failed", "FAILURE");
        }
    }
}

测试效果

在完成上述的配置流程后,持续交付的流程便已经搭建完成。我们可以来检验一下它的效果。

使用 Jenkins 与 KubeVela 实现应用的持续交付

状态

我们首先将 main.go 中的 VERSION 字段修改为 Bad Version Number,即:

const VERSION = "Bad Version Number"

然后提交该修改至 dev 分支,我们可以看到 Jenkins 上的测试流水线被触发运行,失败后将该状态回写给 GitHub。

使用 Jenkins 与 KubeVela 实现应用的持续交付

ci test status

使用 Jenkins 与 KubeVela 实现应用的持续交付

ci test github status

我们重新将 VERSION 修改为 0.1.1,然后再次提交。可以看到这一次测试流水线成功完成执行,并在 GitHub 对应的 Commit 上看到了成功的标志。

使用 Jenkins 与 KubeVela 实现应用的持续交付

ci test status

使用 Jenkins 与 KubeVela 实现应用的持续交付

ci test github status

接下来我们在 GitHub 上提交 Pull Request 尝试将 dev 分支上的更新合并至 prod 分支上。

使用 Jenkins 与 KubeVela 实现应用的持续交付

PR

可以看到在 Jenkins 的部署流水线成功运行结束后,GitHub 上 prod 分支最新的 Commit 也显示了成功的标志。

使用 Jenkins 与 KubeVela 实现应用的持续交付

ci test status

使用 Jenkins 与 KubeVela 实现应用的持续交付

ci test github status

我们的应用已经成功部署了,当前 Deployment 的副本数是 3,并且还有一个 Ingress 对象,这时我们可以访问 Ingress 所配置的域名,成功显示了当前的版本号。

$ vela ls
APP                     COMPONENT               TYPE            TRAITS          PHASE   HEALTHY STATUS          CREATED-TIME
kubevela-demo-app       kubevela-demo-app       webservice      scaler,gateway  running healthy Ready:3/3       2023-10-14 19:11:59 +0800 CST
$ kubectl get pods
NAME                                     READY   STATUS    RESTARTS       AGE
kubevela-demo-app-675896596f-87kxl       1/1     Running   0              9m39s
kubevela-demo-app-675896596f-q5pvz       1/1     Running   0              9m39s
kubevela-demo-app-675896596f-v895m       1/1     Running   0              44m
$ kubectl get ingress
NAME                CLASS   HOSTS                              ADDRESS   PORTS   AGE
kubevela-demo-app   Nginx   kubevela-demo-cicd-app.k8s.local             80      10m
$ curl -H "Host: kubevela-demo-cicd-app.k8s.local" http://<ingress controller address>
Version: 0.1.1

如果想实现金丝雀发布,则可以使用上节的 kruise rollout 来实现,至此,我们便已经成功实现了一整套持续交付流程。在这个流程中,应用的开发者借助 KubeVela + Jenkins 的能力,可以轻松完成应用的迭代更新、集成测试、自动发布与滚动升级,而整个流程在各个环节也可以按照开发者的喜好和条件选择不同的工具,比如使用 Gitlab 替代 GitHub,或是使用 TravisCI 替代 Jenkins。

参考文档:https://kubevela.io/docs/tutorials/jenkins/。



Tags:Jenkins   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
使用 Jenkins 与 KubeVela 实现应用的持续交付
KubeVela 打通了应用与基础设施之间的交付管控的壁垒,相较于原生的 Kubernetes 对象,KubeVela 的 Application 更好地简化抽象了开发者需要关心的配置,将复杂的基础设施能力及...【详细内容】
2023-10-19  Search: Jenkins  点击:(258)  评论:(0)  加入收藏
从零搭建vue + jenkins 超详细教程
相信vue很多人都已经很熟悉了,利用脚手架很容易搭建一个vue项目 但项目多了以后每次部署测试环境就相当麻烦,还容易出错 所以趁这两天不忙,研究一下jenkins,也总算是入门了 jen...【详细内容】
2020-10-17  Search: Jenkins  点击:(257)  评论:(0)  加入收藏
Jenkins 安装和配置
Jenkins 安装 官网:http://jenkins-ci.org/ 官网帮助中心:https://wiki.jenkins-ci.org/display/JENKINS/Use+Jenkins 官网使用 Tomcat 部署方式指导:https://wiki.jenkins-ci...【详细内容】
2019-10-23  Search: Jenkins  点击:(725)  评论:(0)  加入收藏
▌简易百科推荐
即将过时的 5 种软件开发技能!
作者 | Eran Yahav编译 | 言征出品 | 51CTO技术栈(微信号:blog51cto) 时至今日,AI编码工具已经进化到足够强大了吗?这未必好回答,但从2023 年 Stack Overflow 上的调查数据来看,44%...【详细内容】
2024-04-03    51CTO  Tags:软件开发   点击:(5)  评论:(0)  加入收藏
跳转链接代码怎么写?
在网页开发中,跳转链接是一项常见的功能。然而,对于非技术人员来说,编写跳转链接代码可能会显得有些困难。不用担心!我们可以借助外链平台来简化操作,即使没有编程经验,也能轻松实...【详细内容】
2024-03-27  蓝色天纪    Tags:跳转链接   点击:(12)  评论:(0)  加入收藏
中台亡了,问题到底出在哪里?
曾几何时,中台一度被当做“变革灵药”,嫁接在“前台作战单元”和“后台资源部门”之间,实现企业各业务线的“打通”和全域业务能力集成,提高开发和服务效率。但在中台如火如荼之...【详细内容】
2024-03-27  dbaplus社群    Tags:中台   点击:(8)  评论:(0)  加入收藏
员工写了个比删库更可怕的Bug!
想必大家都听说过删库跑路吧,我之前一直把它当一个段子来看。可万万没想到,就在昨天,我们公司的某位员工,竟然写了一个比删库更可怕的 Bug!给大家分享一下(不是公开处刑),希望朋友们...【详细内容】
2024-03-26  dbaplus社群    Tags:Bug   点击:(5)  评论:(0)  加入收藏
我们一起聊聊什么是正向代理和反向代理
从字面意思上看,代理就是代替处理的意思,一个对象有能力代替另一个对象处理某一件事。代理,这个词在我们的日常生活中也不陌生,比如在购物、旅游等场景中,我们经常会委托别人代替...【详细内容】
2024-03-26  萤火架构  微信公众号  Tags:正向代理   点击:(10)  评论:(0)  加入收藏
看一遍就理解:IO模型详解
前言大家好,我是程序员田螺。今天我们一起来学习IO模型。在本文开始前呢,先问问大家几个问题哈~什么是IO呢?什么是阻塞非阻塞IO?什么是同步异步IO?什么是IO多路复用?select/epoll...【详细内容】
2024-03-26  捡田螺的小男孩  微信公众号  Tags:IO模型   点击:(8)  评论:(0)  加入收藏
为什么都说 HashMap 是线程不安全的?
做Java开发的人,应该都用过 HashMap 这种集合。今天就和大家来聊聊,为什么 HashMap 是线程不安全的。1.HashMap 数据结构简单来说,HashMap 基于哈希表实现。它使用键的哈希码来...【详细内容】
2024-03-22  Java技术指北  微信公众号  Tags:HashMap   点击:(11)  评论:(0)  加入收藏
如何从头开始编写LoRA代码,这有一份教程
选自 lightning.ai作者:Sebastian Raschka机器之心编译编辑:陈萍作者表示:在各种有效的 LLM 微调方法中,LoRA 仍然是他的首选。LoRA(Low-Rank Adaptation)作为一种用于微调 LLM(大...【详细内容】
2024-03-21  机器之心Pro    Tags:LoRA   点击:(12)  评论:(0)  加入收藏
这样搭建日志中心,传统的ELK就扔了吧!
最近客户有个新需求,就是想查看网站的访问情况。由于网站没有做google的统计和百度的统计,所以访问情况,只能通过日志查看,通过脚本的形式给客户导出也不太实际,给客户写个简单的...【详细内容】
2024-03-20  dbaplus社群    Tags:日志   点击:(4)  评论:(0)  加入收藏
Kubernetes 究竟有没有 LTS?
从一个有趣的问题引出很多人都在关注的 Kubernetes LTS 的问题。有趣的问题2019 年,一个名为 apiserver LoopbackClient Server cert expired after 1 year[1] 的 issue 中提...【详细内容】
2024-03-15  云原生散修  微信公众号  Tags:Kubernetes   点击:(6)  评论:(0)  加入收藏
站内最新
站内热门
站内头条