实例演示:如何在Kubernetes上大规模运行CI/CD

栏目: IT技术 · 发布时间: 6年前

内容简介:本周四晚上8:30,报名及观看链接:本文来自

本周四晚上8:30, 第二期k3s在线培训 如约开播!本期课程将介绍k3s的核心架构,如高可用架构以及containerd。一起来进阶探索k3s吧!

报名及观看链接: http://z-mz.cn/PmwZ

本文来自 Rancher Labs

在云原生领域中,Kubernetes累积了大量用例。它能够在云中部署应用容器、安排批处理job、处理工作负载以及执行逐步升级。Kubernetes使用高效的编排算法来处理这些操作,即便是大规模集群这些算法依旧表现良好。

此外,Kubernetes主要用例之一是运行持续集成或持续交付(CI/CD)流水线。也就是说,我们部署一个CI/CD容器的唯一实例,该实例将监控代码版本控制系统。所以,每当我们推送到该仓库时,该容器都会运行流水线步骤。其最终目标是达到一个“true or false”的状态。True即在集成阶段commit通过了各种测试,False即未通过测试。

除了以上描述的CI流水线之外,在CI测试通过之后,另一个流水线可以接管余下的过程,以处理发布过程的CD部分。在这一阶段,流水线将尝试将应用程序容器交付到生产中。

需要明白的是,这些操作是按需运行或者是由各种行为(如代码check-in、测试触发器、流程中上一步的结果等)自动触发的。因此我们需要一种机制来增加单个节点以运行那些流水线的步骤,并在不需要它们时将其淘汰。这种管理不可变基础架构的方法有助于我们节省资源并降低成本。

当然,最关键的机制就是Kubernetes,它具有声明式的结构和可定制性,因此可以让你在任何场景下高效地调度job、节点以及pod。

本文包括3个部分:第一部分我们将探讨目前在Kubernetes上运行最受欢迎的CI/CD平台。

接着我们将会看两个用例:第一个例子中,我们将简单地在Kubernetes上安装Jenkins以及对其进行配置以让我们可以在Kubernetes上使用这个流行的开源 工具 来运行我们的CI流水线;第二个例子中,我们将把这个Jenkins部署提高到一个新的水平。我们将会提供一些在Kubernetes中扩展CI/CD流水线的tips和建议。

最后,我们将会讨论在Kubernetes上大规模运行CI/CD的最合理的方法和实践。

本文的目标是让你彻底了解Kubernetes处理这些工作负载的效率。

实例演示:如何在Kubernetes上大规模运行CI/CD

适用于Kubernetes的CI/CD平台

Kubernetes是一个运行CI/CD的理想平台,因为它拥有许多特性使得在上面运行CI/CD更为简单。那么,到底有多少CI/CD的平台可以在Kubernetes上运行呢?可以这么说,只要它们能够被打包为一个容器,Kubernetes都能够运行它们。以下是几个最为流行的CI/CD平台:

  • Jenkins :Jenkins是最为流行也最为稳定的CI/CD平台。在世界范围内有数以千计的企业都在使用它,因为它拥有强大的生态和可扩展性。如果你打算要在Kubernetes上使用它,非常建议你安装它的官方插件。JenkinsX是专门为云原生领域设计的Jenkins版本。它与Kubernetes更加兼容,并且提供了更好的集成功能,如GitOps、自动CI/CD和预览环境。
  • Spinnaker :Spinnaker是一个可扩展的多云部署的CD平台,得到了Netflix的支持。使用相关的Helm Chart即可安装它。
    https://github.com/helm/charts ... naker
  • Drone :这是有多种功能的通用云原生CD平台。可以使用关联的Runner在Kubernetes中运行它。
  • GoCD :Thoughtworks的另一个CI/CD平台,提供了适用于云原生部署的各种工作流程和功能。它可以在Kubernetes中作为Helm Chart运行。

此外,还有一些与Kubernetes紧密合作的云服务,并提供诸如CircleCI和Travis的CI/CD流水线。如果你不打算托管CI/CD平台,那么这些也十分有用。

现在,我们来看看如何在Kubernetes集群上安装Jenkins。

如何在Kubernetes上安装Jenkins

首先,我们需要安装Helm,它是Kubernetes的软件包管理器:

$ curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 > get_helm.sh

$ chmod 700 get_helm.sh

$ ./get_helm.sh -v v2.15.0

同样,我们还需要安装Tiller,以让Helm正常运行:

$ kubectl -n kube-system create serviceaccount tiller

serviceaccount/tiller created



~/.kube

$ kubectl create clusterrolebinding tiller --clusterrole cluster-admin --serviceaccount=kube-system:tiller

clusterrolebinding.rbac.authorization.k8s.io/tiller created



~/.kube

$ helm init --service-account tiller

$HELM_HOME has been configured at /Users/itspare/.helm.

完成这些步骤之后,我们需要运行检查命令,以查看deployment的配置值:

$ helm inspect values stable/jenkins > values.yml

仔细检查配置值并在需要的时候进行更改。然后安装Chart:

$ helm install stable/jenkins --tls \

--name jenkins \

--namespace jenkins

安装过程中会有一些关于下一步操作的说明:

注意:

  1.  运行以下命令获取”admin“用户的密码:
printf $(kubectl get secret --namespace default my-jenkins -o jsonpath="{.data.jenkins-admin-password}" | base64 --decode);echo
  1. 在相同的 shell 中获取Jenkins URL以访问这些命令:
export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/component=jenkins-master" -l "app.kubernetes.io/instance=my-jenkins" -o jsonpath="{.items[0].metadata.name}")

echo http://127.0.0.1:8080

kubectl --namespace default port-forward $POD_NAME 8080:8080

遵循这些步骤,它们将在 http://127.0.0.1:8080 启动代理服务器。

到那里输入你的用户名和密码。你将会拥有自己的Jenkins 服务器:

实例演示:如何在Kubernetes上大规模运行CI/CD

不过,请记住,还有许多配置选项尚未修改,你可以访问chart文档以了解更多信息:

https://github.com/helm/charts ... nkins

在默认情况下,服务器会安装好最基本的插件,如Git和Kubernetes-Jenkins,我们可以根据自己的需要安装其他插件。

总而言之,使用Helm安装Jenkins十分轻松。

使用K8S扩展CI/CD Jenkins流水线

既然我们已经大致了解CI/CD如何在Kubernetes上运行的,那么我们来看一个在Kubernetes中部署高度可扩展的Jenkins部署的示例用例。人们通常用它(进行了少量修改)来处理基础结构的CI/CD,开始吧!

使用Jenkins固定发行版

虽然官方Jenkins镜像很适合入门,但它需要的配置超出了我们的期望。许多用户会选择一个固定的发行版,如my-bloody-jenkins( https://github.com/odavid/my-bloody-jenkins ),它提供了一个较为完整的预安装插件以及配置选项。在可用的插件中,我们使用saml插件、SonarQubeRunner、Maven和Gradle。

它能够使用以下命令通过Helm Chart安装:

$ helm repo add odavid https://odavid.github.io/k8s-helm-charts

$ helm install odavid/my-bloody-jenkins

我们选择使用以下Dockerfile部署自定义镜像:

FROM odavid/my-bloody-jenkins:2.190.2-161



USER jenkins



COPY plugins.txt /usr/share/jenkins/ref/

RUN /usr/local/bin/install-plugins.sh < /usr/share/jenkins/ref/plugins.txt



USER root

其中plugins.txt文件是我们要预安装到镜像中的其他插件列表:

build-monitor-plugin

xcode-plugin

rich-text-publisher-plugin

jacoco

scoverage

dependency-check-jenkins-plugin

greenballs

shiningpanda

pyenv-pipeline

s3

pipeline-aws

appcenter

multiple-scms

Testng-plugin

然后,只要dockerfile发生更改,我们就使用此通用Jenkinsfile来构建master:

!/usr/bin/env groovy

node('generic') {

try {

def dockerTag, jenkins_master

stage('Checkout') {

checkout([

$class: 'GitSCM',

branches: scm.branches,

doGenerateSubmoduleConfigurations: scm.doGenerateSubmoduleConfigurations,

extensions: [[$class: 'CloneOption', noTags: false, shallow: false, depth: 0, reference: '']],

userRemoteConfigs: scm.userRemoteConfigs,

])

def version = sh(returnStdout: true, script: "git describe --tags `git rev-list --tags --max-count=1`").trim()

def tag = sh(returnStdout: true, script: "git rev-parse --short HEAD").trim()

dockerTag = version + "-" + tag

println("Tag: " + tag + " Version: " + version)

}

stage('Build Master') {

jenkins_master = docker.build("jenkins-master", "--network=host .")

}

stage('Push images') {

docker.withRegistry("https://$env.DOCKER_REGISTRY", 'ecr:eu-west-2:jenkins-aws-credentials') {

jenkins_master.push("${dockerTag}")

}

}

if(env.BRANCH_NAME == 'master') {

stage('Push Latest images') {

docker.withRegistry("https://$env.DOCKER_REGISTRY", 'ecr:eu-west-2:jenkins-aws-credentials') {

jenkins_master.push("latest")

}

}

stage('Deploy to K8s cluster') {

withKubeConfig([credentialsId: 'dev-tools-eks-jenkins-secret',

serverUrl: env.TOOLS_EKS_URL]) {

sh "kubectl set image statefulset jenkins jenkins=$env.DOCKER_REGISTRY/jenkins-master:${dockerTag}"

}

}

}

currentBuild.result = 'SUCCESS'

} catch(e) {

currentBuild.result = 'FAILURE'

throw e

}

}

我们所使用的专用集群由AWS中的一些大中型实例组成,用于Jenkins jobs。接下来,我们进入下一个部分。

使用专用的Jenkins Slaves和标签(label)

为了扩展我们的一些Jenkins slaves,我们使用Pod模板并将标签分配给特定的agent。因此在我们的Jenkinsfiles中,我们可以为jobs引用它们。例如,我们有一些需要构建安卓应用程序的agent。因此,我们引用以下标签:

pipeline {

agent { label "android" }

…

并且将使用特定于安卓的pod模板。我们使用这一Dockerfile,例如:

FROM dkr.ecr.eu-west-2.amazonaws.com/jenkins-jnlp-slave:latest



RUN apt-get update && apt-get install -y -f --no-install-recommends xmlstarlet



ARG GULP_VERSION=4.0.0

ARG CORDOVA_VERSION=8.0.0

SDK version and build-tools version should be different

ENV SDK_VERSION 25.2.3

ENV BUILD_TOOLS_VERSION 26.0.2

ENV SDK_CHECKSUM 1b35bcb94e9a686dff6460c8bca903aa0281c6696001067f34ec00093145b560

ENV ANDROID_HOME /opt/android-sdk

ENV SDK_UPDATE tools,platform-tools,build-tools-25.0.2,android-25,android-24,android-23,android-22,android-21,sys-img-armeabi-v7a-android-26,sys-img-x86-android-23

ENV LD_LIBRARY_PATH ${ANDROID_HOME}/tools/lib64/qt:${ANDROID_HOME}/tools/lib/libQt5:$LD_LIBRARY_PATH/

ENV PATH ${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools

RUN curl -SLO "https://dl.google.com/android/repository/tools_r${SDK_VERSION}-linux.zip" \

&& echo "${SDK_CHECKSUM} tools_r${SDK_VERSION}-linux.zip" | sha256sum -c - \

&& mkdir -p "${ANDROID_HOME}" \

&& unzip -qq "tools_r${SDK_VERSION}-linux.zip" -d "${ANDROID_HOME}" \

&& rm -Rf "tools_r${SDK_VERSION}-linux.zip" \

&& echo y | ${ANDROID_HOME}/tools/android update sdk --filter ${SDK_UPDATE} --all --no-ui --force \

&& mkdir -p ${ANDROID_HOME}/tools/keymaps \

&& touch ${ANDROID_HOME}/tools/keymaps/en-us \

&& yes | ${ANDROID_HOME}/tools/bin/sdkmanager --update

RUN chmod -R 777 ${ANDROID_HOME} && chown -R jenkins:jenkins ${ANDROID_HOME}

我们还使用了Jenkinsfile,该文件与上一个文件类似,用于构建master。每当我们对Dockerfile进行更改时,agent都会重建镜像。这为我们的CI/CD基础架构提供了极大的灵活性。

使用自动伸缩

尽管我们为deployment分配了特定数量的节点,但我们还可以通过启用cluster autoscaling,来完成更多的事情。这意味着在工作负载增加和峰值的情况下,我们可以增加额外的节点来处理job。目前,如果我们有固定数量的节点,那么我们只能处理固定数量的job。基于以下事实,我们可以进行粗略地估计:每个slave通常分配500ms CPU和256MB内存,并且设置一个很高的并发。这根本不现实。

举个例子,当你的版本被大幅削减并且需要部署大量微服务时,可能会发生上述情况。然后,大量的job堆积在流水线,造成严重的延误。

在这种情况下,我们可以增加该阶段的节点数。例如,我们可以添加额外的VM实例,然后在过程结束时将其删除。

我们可以在命令行中使用自动伸缩选项来配置“Vertical”或“集群”自动伸缩选项。但是,此方法需要仔细计划和配置,因为有时会发生以下情况:

  1. 越来越多的job达到平稳阶段
  2. Autoscaler增加新的节点,但是需要10分钟来进行部署和分配
  3. 旧的job已经完成任务,新的job将填补空白,进而减少了对新节点的需求
  4. 新节点可用,但需要X分钟保持稳定且未利用,X由–scale-down-unneeded-time标志定义
  5. 同样的事情每天发生很多次

在这种情况下,最好是根据我们的特定需求进行配置,或者只是增加当天的节点数,并在流程结束后将其还原。所有这些都与寻找最佳方法来利用所有资源并使成本最小化有关。

在任何情况下,我们都应该有一个可伸缩且易于使用的Jenkins集群。对于每个job,都会创建一个pod来运行特定的流水线,并在完成后将其销毁。

大规模使用K8s进行CI / CD的最佳实践

现在我们已经了解了Kubernetes有哪些CI/CD平台以及如何在你的集群上安装一个平台。接下来,我们将讨论一些大规模运行它们的方法。

首先,选择Kubernetes发行版是我们需要考虑的最关键因素之一。找到最合适的解决方案才能够进行下一步。

其次,选择合适的 Docker 镜像仓库和应用程序包管理器同样重要。我们需要寻找可以按需快速检索的安全可靠的镜像管理。至于软件包管理器,Helm是一个不错的选择,因为它可以发现、共享和使用为Kubernetes构建的软件。

第三,使用现代集成流程,如GitOps和ChatOps,在易用性和可预测性方面提供了显著优势。将Git用作单一数据源,使我们可以运行“通过拉取请求进行操作”,从而简化了对基础架构和应用程序的部署控制。使用诸如企业微信或钉钉之类的团队协作工作来触发CI/CD流水线的自动化任务,有助于我们消除重复劳动并简化集成。

总体而言,如果我们想更深入地了解,你可以自定义或开发自己的K8S Operator,与K8S API配合更紧密。使用自定义operator的好处很多,因为它们可以建立更好的自动化体验。

最后,我们可以说Kubernetes和CI/CD平台是天合之作。如果你刚刚入门Kubernetes生态系统,那么你可以尝试集成一个CI/CD流水线。这是了解Kubernetes内部运作方式的好方法,关键是要留出机动空间,方便将来容易更改。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

High Performance Python

High Performance Python

Andrew Lewis / O'Reilly Media, Inc. / 2010-09-15 / USD 34.99

Chapter 1. Introduction Section 1.1. The High Performance Buzz-word Chapter 2. The Theory of Computation Section 2.1. Introduction Section 2.2. Problems Section 2.3. Models of Computati......一起来看看 《High Performance Python》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

SHA 加密
SHA 加密

SHA 加密工具