本周四晚上8:30, 第二期k3s在线培训如约开播!本期课程将介绍k3s的核心架构,如高可用架构以及containerd。一块儿来进阶探索k3s吧!报名及观看连接:http://z-mz.cn/PmwZnode
本文来自Rancher Labslinux
在云原生领域中,Kubernetes累积了大量用例。它可以在云中部署应用容器、安排批处理job、处理工做负载以及执行逐步升级。Kubernetes使用高效的编排算法来处理这些操做,即使是大规模集群这些算法依旧表现良好。android
此外,Kubernetes主要用例之一是运行持续集成或持续交付(CI/CD)流水线。也就是说,咱们部署一个CI/CD容器的惟一实例,该实例将监控代码版本控制系统。因此,每当咱们推送到该仓库时,该容器都会运行流水线步骤。其最终目标是达到一个“true or false”的状态。True即在集成阶段commit经过了各类测试,False即未经过测试。git
除了以上描述的CI流水线以外,在CI测试经过以后,另外一个流水线能够接管余下的过程,以处理发布过程的CD部分。在这一阶段,流水线将尝试将应用程序容器交付到生产中。github
须要明白的是,这些操做是按需运行或者是由各类行为(如代码check-in、测试触发器、流程中上一步的结果等)自动触发的。所以咱们须要一种机制来增长单个节点以运行那些流水线的步骤,并在不须要它们时将其淘汰。这种管理不可变基础架构的方法有助于咱们节省资源并下降成本。算法
固然,最关键的机制就是Kubernetes,它具备声明式的结构和可定制性,所以可让你在任何场景下高效地调度job、节点以及pod。docker
本文包括3个部分:第一部分咱们将探讨目前在Kubernetes上运行最受欢迎的CI/CD平台。shell
接着咱们将会看两个用例:第一个例子中,咱们将简单地在Kubernetes上安装Jenkins以及对其进行配置以让咱们能够在Kubernetes上使用这个流行的开源工具来运行咱们的CI流水线;第二个例子中,咱们将把这个Jenkins部署提升到一个新的水平。咱们将会提供一些在Kubernetes中扩展CI/CD流水线的tips和建议。json
最后,咱们将会讨论在Kubernetes上大规模运行CI/CD的最合理的方法和实践。xcode
本文的目标是让你完全了解Kubernetes处理这些工做负载的效率。
Kubernetes是一个运行CI/CD的理想平台,由于它拥有许多特性使得在上面运行CI/CD更为简单。那么,到底有多少CI/CD的平台能够在Kubernetes上运行呢?能够这么说,只要它们可以被打包为一个容器,Kubernetes都可以运行它们。如下是几个最为流行的CI/CD平台:
此外,还有一些与Kubernetes紧密合做的云服务,并提供诸如CircleCI和Travis的CI/CD流水线。若是你不打算托管CI/CD平台,那么这些也十分有用。
如今,咱们来看看如何在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
安装过程当中会有一些关于下一步操做的说明:
注意:
printf $(kubectl get secret --namespace default my-jenkins -o jsonpath="{.data.jenkins-admin-password}" | base64 --decode);echo
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 服务器:
不过,请记住,还有许多配置选项还没有修改,你能够访问chart文档以了解更多信息:
https://github.com/helm/chart...
在默认状况下,服务器会安装好最基本的插件,如Git和Kubernetes-Jenkins,咱们能够根据本身的须要安装其余插件。
总而言之,使用Helm安装Jenkins十分轻松。
既然咱们已经大体了解CI/CD如何在Kubernetes上运行的,那么咱们来看一个在Kubernetes中部署高度可扩展的Jenkins部署的示例用例。人们一般用它(进行了少许修改)来处理基础结构的CI/CD,开始吧!
虽然官方Jenkins镜像很适合入门,但它须要的配置超出了咱们的指望。许多用户会选择一个固定的发行版,如my-bloody-jenkins(https://github.com/odavid/my-... ),它提供了一个较为完整的预安装插件以及配置选项。在可用的插件中,咱们使用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,咱们使用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”或“集群”自动伸缩选项。可是,此方法须要仔细计划和配置,由于有时会发生如下状况:
在这种状况下,最好是根据咱们的特定需求进行配置,或者只是增长当天的节点数,并在流程结束后将其还原。全部这些都与寻找最佳方法来利用全部资源并使成本最小化有关。
在任何状况下,咱们都应该有一个可伸缩且易于使用的Jenkins集群。对于每一个job,都会建立一个pod来运行特定的流水线,并在完成后将其销毁。
如今咱们已经了解了Kubernetes有哪些CI/CD平台以及如何在你的集群上安装一个平台。接下来,咱们将讨论一些大规模运行它们的方法。
首先,选择Kubernetes发行版是咱们须要考虑的最关键因素之一。找到最合适的解决方案才可以进行下一步。
其次,选择合适的Docker镜像仓库和应用程序包管理器一样重要。咱们须要寻找能够按需快速检索的安全可靠的镜像管理。至于软件包管理器,Helm是一个不错的选择,由于它能够发现、共享和使用为Kubernetes构建的软件。
第三,使用现代集成流程,如GitOps和ChatOps,在易用性和可预测性方面提供了显著优点。将Git用做单一数据源,使咱们能够运行“经过拉取请求进行操做”,从而简化了对基础架构和应用程序的部署控制。使用诸如企业微信或钉钉之类的团队协做工做来触发CI/CD流水线的自动化任务,有助于咱们消除重复劳动并简化集成。
整体而言,若是咱们想更深刻地了解,你能够自定义或开发本身的K8S Operator,与K8S API配合更紧密。使用自定义operator的好处不少,由于它们能够创建更好的自动化体验。
最后,咱们能够说Kubernetes和CI/CD平台是天合之做。若是你刚刚入门Kubernetes生态系统,那么你能够尝试集成一个CI/CD流水线。这是了解Kubernetes内部运做方式的好方法,关键是要留出机动空间,方便未来容易更改。