創(chuàng)新互聯(lián)專注于茄子河網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗(yàn)。 熱誠(chéng)為您提供茄子河營(yíng)銷型網(wǎng)站建設(shè),茄子河網(wǎng)站制作、茄子河網(wǎng)頁(yè)設(shè)計(jì)、茄子河網(wǎng)站官網(wǎng)定制、成都微信小程序服務(wù),打造茄子河網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供茄子河網(wǎng)站排名全網(wǎng)營(yíng)銷落地服務(wù)。
首先,我們需要安裝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正常運(yùn)行:
$ 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.
完成這些步驟之后,我們需要運(yùn)行檢查命令,以查看deployment的配置值:
$ helm inspect values stable/jenkins > values.yml
仔細(xì)檢查配置值并在需要的時(shí)候進(jìn)行更改。然后安裝Chart:
$ helm install stable/jenkins --tls \
--name jenkins \
--namespace jenkins
安裝過(guò)程中會(huì)有一些關(guān)于下一步操作的說(shuō)明:
注意:
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 啟動(dòng)代理服務(wù)器。
到那里輸入你的用戶名和密碼。你將會(huì)擁有自己的Jenkins 服務(wù)器:
不過(guò),請(qǐng)記住,還有許多配置選項(xiàng)尚未修改
在默認(rèn)情況下,服務(wù)器會(huì)安裝好最基本的插件,如Git和Kubernetes-Jenkins,我們可以根據(jù)自己的需要安裝其他插件。
總而言之,使用Helm安裝Jenkins十分輕松。
既然我們已經(jīng)大致了解CI/CD如何在Kubernetes上運(yùn)行的,那么我們來(lái)看一個(gè)在Kubernetes中部署高度可擴(kuò)展的Jenkins部署的示例用例。人們通常用它(進(jìn)行了少量修改)來(lái)處理基礎(chǔ)結(jié)構(gòu)的CI/CD,開(kāi)始吧!
雖然官方Jenkins鏡像很適合入門,但它需要的配置超出了我們的期望。許多用戶會(huì)選擇一個(gè)固定的發(fā)行版,如my-bloody-jenkins(https://github.com/odavid/my-bloody-jenkins ),它提供了一個(gè)較為完整的預(yù)安裝插件以及配置選項(xiàng)。在可用的插件中,我們使用saml插件、SonarQubeRunner、Maven和Gradle。
它能夠使用以下命令通過(guò)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文件是我們要預(yù)安裝到鏡像中的其他插件列表:
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發(fā)生更改,我們就使用此通用Jenkinsfile來(lái)構(gòu)建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中的一些大中型實(shí)例組成,用于Jenkins jobs。接下來(lái),我們進(jìn)入下一個(gè)部分。
為了擴(kuò)展我們的一些Jenkins slaves,我們使用Pod模板并將標(biāo)簽分配給特定的agent。因此在我們的Jenkinsfiles中,我們可以為jobs引用它們。例如,我們有一些需要構(gòu)建安卓應(yīng)用程序的agent。因此,我們引用以下標(biāo)簽:
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,該文件與上一個(gè)文件類似,用于構(gòu)建master。每當(dāng)我們對(duì)Dockerfile進(jìn)行更改時(shí),agent都會(huì)重建鏡像。這為我們的CI/CD基礎(chǔ)架構(gòu)提供了極大的靈活性。
盡管我們?yōu)閐eployment分配了特定數(shù)量的節(jié)點(diǎn),但我們還可以通過(guò)啟用cluster autoscaling,來(lái)完成更多的事情。這意味著在工作負(fù)載增加和峰值的情況下,我們可以增加額外的節(jié)點(diǎn)來(lái)處理job。目前,如果我們有固定數(shù)量的節(jié)點(diǎn),那么我們只能處理固定數(shù)量的job?;谝韵率聦?shí),我們可以進(jìn)行粗略地估計(jì):每個(gè)slave通常分配500ms CPU和256MB內(nèi)存,并且設(shè)置一個(gè)很高的并發(fā)。這根本不現(xiàn)實(shí)。
舉個(gè)例子,當(dāng)你的版本被大幅削減并且需要部署大量微服務(wù)時(shí),可能會(huì)發(fā)生上述情況。然后,大量的job堆積在流水線,造成嚴(yán)重的延誤。
在這種情況下,我們可以增加該階段的節(jié)點(diǎn)數(shù)。例如,我們可以添加額外的VM實(shí)例,然后在過(guò)程結(jié)束時(shí)將其刪除。
我們可以在命令行中使用自動(dòng)伸縮選項(xiàng)來(lái)配置“Vertical”或“集群”自動(dòng)伸縮選項(xiàng)。但是,此方法需要仔細(xì)計(jì)劃和配置,因?yàn)橛袝r(shí)會(huì)發(fā)生以下情況:
越來(lái)越多的job達(dá)到平穩(wěn)階段
Autoscaler增加新的節(jié)點(diǎn),但是需要10分鐘來(lái)進(jìn)行部署和分配
舊的job已經(jīng)完成任務(wù),新的job將填補(bǔ)空白,進(jìn)而減少了對(duì)新節(jié)點(diǎn)的需求
新節(jié)點(diǎn)可用,但需要X分鐘保持穩(wěn)定且未利用,X由–scale-down-unneeded-time標(biāo)志定義
同樣的事情每天發(fā)生很多次
在這種情況下,最好是根據(jù)我們的特定需求進(jìn)行配置,或者只是增加當(dāng)天的節(jié)點(diǎn)數(shù),并在流程結(jié)束后將其還原。所有這些都與尋找最佳方法來(lái)利用所有資源并使成本最小化有關(guān)。
在任何情況下,我們都應(yīng)該有一個(gè)可伸縮且易于使用的Jenkins集群。對(duì)于每個(gè)job,都會(huì)創(chuàng)建一個(gè)pod來(lái)運(yùn)行特定的流水線,并在完成后將其銷毀