前言
本月中旬,Jenkins Operator 正式成为 Jenkins 的子项目[1],这将在很大水平上弥合 Jenkins 和 Kubernetes 之间的鸿沟。
Operator 是 Kubernetes 的一种扩大机制,用户能够利用这种扩大机制来让本人的利用以 Kubernetes native(k8s 原生)的形式在 kubernetes 平台上运行起来。对于 Operator 更多具体的内容,能够在 Kubernetes 官网文档[2]上查看。
Jenkins 是一款社区弱小、API & 插件丰盛、用户泛滥且开源的继续交付工具。为了让 Jenkins 能在 Kubernetes 上更好的运行,Jenkins 社区提供了 Jenkins Operator。Jenkins Operator 是基于不可变性和申明式的配置即代码来构建的。对于 Operator 的其余信息能够在Jenkins Operator GitHub 和 Jenkins Operator 官网文档[3]进行查看。
以下演示过程中所波及的代码均在 https://github.com/majinghe/jenkins-operator.git 库中,须将上述库的代码下载到本地,再执行后续操作。
入门篇:jenkins-operator 的介绍及装置
装置
装置的前提条件:
- 一个版本为 1.11+ 的 Kubernetes 集群
- kubectl 的版本为 1.11+
第一步:Jenkins CRD 创立
执行以下命令来创立 Jenkins CRD
$ kubectl apply -f jenkins_crd.yamlcustomresourcedefinition.apiextensions.k8s.io/jenkins.jenkins.io createdcustomresourcedefinition.apiextensions.k8s.io/jenkinsimages.jenkins.io created
第二步:Jenkins Operator 的装置
此 Operator 是 jenkins-operator 的外围,次要的目标是用来对 jenkins 这种资源的治理,包含创立、删除等,后续会演示。此 Operator 的装置有两种形式:
- 用
kubectl
来实现装置 - 用
helm
来实现装置
对于两种形式的不同应用命令,能够官网进行查看,本文抉择用 kubectl 来实现。先创立一个 namespace:
$ kubectl create ns jenkins$ kubectl create ns jenkins
执行 operator 装置命令:
$ kubectl -n jenkins apply -f jenkins_operator.yamlserviceaccount/jenkins-operator createdrole.rbac.authorization.k8s.io/jenkins-operator createdrolebinding.rbac.authorization.k8s.io/jenkins-operator createddeployment.apps/jenkins-operator created
查看 jenkins namespace 上面的 pod:
$ kubectl -n jenkins get pods -wNAME READY STATUS RESTARTS AGEjenkins-operator-548d76f664-hp6pm 0/1 Pending 0 0sjenkins-operator-548d76f664-hp6pm 0/1 ContainerCreating 0 1sjenkins-operator-548d76f664-hp6pm 1/1 Running 0 34s
第三步:创立 Jenkins 实例
此时如果创立一个 Jenkins 实例,Operator 就会监听到这个事件,从而依据咱们对 Jenkins 实例的形容(Jenkins 实例的形容文件 ,以 yaml 格局呈现)来创立实例。对于实例的形容文件的格局内容,能够在这儿进行查看。本文应用的文件及内容解释如下:
apiVersion: jenkins.io/v1alpha2kind: Jenkinsmetadata: name: jenkinsspec:/*configurationAsCode 用来形容 jenkins configruation 局部的内容,比方 Github Server、Slack、LDAP 等的配置。上述内容通过 Jenkins Configuration As Code 的模式来组织的。下文会给大家展现用法*/ configurationAsCode: configurations: - name: jenkins-config serviceAccount: annotations: kubernetes.io/service-account: jenkins master: basePlugins: /*配置与 master 相干的一些配置,比方想要装置的必要插件*/ - name: kubernetes version: "1.29.2" plugins: /*配置与 master 相干的一些配置,比方想要装置的其余插件*/ - name: ldap version: "2.4" - name: github version: "1.33.1" containers: /*master 容器的配置,包含镜像、资源限度、环境变量等*/ - name: jenkins-master image: jenkins/jenkins:lts imagePullPolicy: Always env: - name: JENKINS_HOME value: /var/lib/jenkins resources: limits: cpu: 1500m memory: 2Gi requests: cpu: "1" memory: 500Mi
上述文件依赖于 jenkins-config 这个对 jenkins configuration 的形容,须要先创立 jenkins-config 这部分内容,此内容是以 configmap 的模式来形容 jenkins configuration 的配置的,诸如LDAP、GitHub Server 等。具体内容可参考如下:
apiVersion: v1kind: ConfigMapmetadata: name: jenkins-configdata: jenkins.yaml: | security: scriptApproval: /*Script Approval 配置局部*/ approvedSignatures: - "method groovy.json.JsonSlurper parse java.io.Reader" unclassified: slackNotifier: /*slack 配置局部*/ teamDomain: slack-test tokenCredentialId: "slack-token" gitHubPluginConfig: /*GitHub Server 配置局部*/ configs: - name: "GitHub" apiUrl: "https://api.github.com/v3/" credentialsId: "github-token" manageHooks: true jenkins: clouds: /*kubernetes 配置局部*/ - kubernetes: jenkinsTunnel: "jenkins-operator-slave-jenkins.jenkins.svc.cluster.local:50000" jenkinsUrl: "http://jenkins-operator-http-jenkins.jenkins.svc.cluster.local:8080" name: "kubernetes" namespace: "jenkins" retentionTimeout: 15 serverUrl: "https://kubernetes.default.svc.cluster.local:443" systemMessage: "<Cloud Native DevSecOps>" securityRealm: ldap: /*LDAP 配置,依据你的 LDAP 配置信息批改即可*/ configurations: - server: "xxxx" rootDN: "xxxx" userSearchBase: "xxxx" userSearch: "xxxx" groupSearchBase: "xxxxxx" groupMembershipStrategy: fromGroupSearch: filter: ""
接下来只须要将上述内容写入 yaml 文件创建 configmap 即可:
$ kubectl -n jenkins apply -f config.yamlconfigmap/jenkins-config created
随后,创立 Jenkins 实例:
$ kubectl -n jenkins apply -f jenkins.yamljenkins.jenkins.io/jenkins created
此时,能够在 operator pod 的 log 中看到如下信息:
021-04-04T08:21:44.049Z INFO controller-jenkins base/pod.go:159 Creating a new Jenkins Master Pod jenkins/jenkins-jenkins {"cr": "jenkins"}
阐明,operator 曾经捕捉到创立 Jenkins 实例这个事件,随后就会去依据实例的形容来创立,能够查看 jenkins namespace 上面的 pod:
$ kubectl -n jenkins get pods -wNAME READY STATUS RESTARTS AGEjenkins-jenkins 2/2 Running 0 13djenkins-operator-548d76f664-hp6pm 1/1 Running 0 13d
发现多了一个 jenkins-jenkins
的pod,这就是创立进去的 jenkins master 的pod。
如果想通过 ingress 来对外暴漏 jenkins 的服务,则能够依照上面的 yaml 文件来创立 ingress 资源:
apiVersion: networking.k8s.io/v1kind: Ingressmetadata: name: jenkins annotations: kubernetes.io/ingress.class: "nginx" nginx.ingress.kubernetes.io/redirect-to-https: "True"spec: tls: - hosts: - xiaomage.devops.com secretName: jenkins-tls rules: - host: xiaomage.devops.com http: paths: - path: / pathType: Prefix backend: service: name: jenkins-operator-http-jenkins port: number: 8080
接着通过拜访 https://xiaomage.devops.com 来拜访 jenkins 界面。登陆的用户名和明码能够通过如下命令获取:
$ kubectl -n jenkins get secrets jenkins-operator-credentials-jenkins -o jsonpath='{.data.user}' | base64 -D$ kubectl -n jenkins get secrets jenkins-operator-credentials-jenkins -o jsonpath='{.data.password}' | base64 -D
此外,也能够通过 port-forward 的形式来应用 jenkins:
$ kubectl -n jenkins port-forward pods/jenkins-jenkins 8080:8080
间接拜访 http://localhost:8080 即可拜访 jenkins 界面。获取登陆用户名和明码的办法同上。
至此,通过 jenkins-operator 装置 jenkins 的过程曾经完满实现,接下来是应用篇。
进阶篇:应用
传统的应用办法就是在界面上点击创立 jenkins job,而后进行配置,最初再应用。然而 jenkins-operator 提供了另外一个 operator— Seed Jobs,顾名思义,就是可能实现 job 的主动发现。其背地的原理其实是借助 Jenkins Job DSL 和 Configuration As Code:也行将 job 通过 DSL 来进行形容(形容包含 Job 名称,配置,Pipeline 脚本等),而后将这种形容的代码寄存到 GitHub 上。Seed Jobs 依据配置来主动捕捉 job 增加的动作,从而实现 job 的创立。
Seed Job 的应用前提是 job 定义文件和 job pipeline 文件须要具备如下的文件目录构造:
cicd/├── jobs│ └── job-dsl-file└── pipelines └── pipeline-file
Seed Job 能够通过在 jenkins 的配置文件中增加如下内容来启用:
apiVersion: jenkins.io/v1alpha2kind: Jenkinsmetadata: name: jenkinsspec: master: # 可参考第一局部中的相干配置内容 seedJobs: - id: Demo targets: "cicd/jobs/demo_pipeline.groovy" # job dsl 脚本的地位 credentialType: basicSSHUserPrivateKey credentialID: github-ssh-key description: "CI/CD Repo" repositoryBranch: main repositoryUrl: git@github.com:majinghe/jenkins-operator.git # cicd 仓库地址
cicd/jobs/demo_pipeline.groovy
形容了 demo job 的配置内容,信息如下:
#!/usr/bin/env groovypipelineJob('Demo') { # job 名称配置 displayName('Demo') # 构建历史配置 logRotator { numToKeep(10) daysToKeep(30) } # 构建参数,多种类型都反对 parameters { choiceParam('ENV', ['SVT1', 'SVT2']) stringParam('Release', 'v1.0.0', 'Please input your release number!') } # pipeline groovy 脚本的具体信息 definition { cpsScm { scm { git { remote { url('git@github.com:majinghe/jenkins-operator.git') credentials('github-ssh-key') } branches('*/main') } } # pipeline groovy 在库中的地位 scriptPath('cicd/pipelines/demo.groovy') } }}
上述的 job dsl 形容了一个有两个构建参数的 job,cicd/pipelines/demo.groovy 的内容为:
def label = "jnlp-${UUID.randomUUID().toString()}"podTemplate( label: label, serviceAccount: "jenkins", namespace: "jenkins", containers: [ containerTemplate( name: 'jnlp', image: 'gbyukg/docker-jnlp-slave:1.0', args: '${computer.jnlpmac} ${computer.name}' ) ]) { node(label) { container('jnlp'){ stage("Hello World"){ println "This is xiaomage, focus on Cloud Native DevSecOps!!!" } } }}
这个 job 构建会打印This is xiaomage, focus on Cloud Native DevSecOps!!!
而后从新创立 jenkins 资源即可:
$ kubectl -n jenkins apply -f jenkins.yaml
随后即可在 jenkins namespace 上面看到 seed job 的 pod:
$ kubectl -n jenkins get podsNAME READY STATUS RESTARTS AGEjenkins-jenkins 1/1 Running 0 5d # jenkins master podjenkins-operator-548d76f664-hp6pm 1/1 Running 0 5d # jenkins operator podseed-job-agent-jenkins-7ff6d479db-6gqjl 1/1 Running 0 5d # see job pod
从新登陆 jenkins 就能看到两个 job,一个为Seed Job,一个为最终要真正应用的 Job。
尔后,只有 job 有批改,只须要批改 GitHub 上对于job的代码即可,而后从新运行 Seed Job 就能把理论应用 Job 的内容进行更新。构建上述的 demo job 可查看构建日志:
能够看到上述构建输入和 pipeline 中定义的是统一的。这些其实也就做到了所有皆代码。一旦 jenkins 有任何问题,也能够通过重建来疾速拉起相应的 job。相当于多一层备份机制(这个只能备份 job,job 历史会失落,如果须要备份 job 历史,能够给 job 历史目录做长久化或者利用 jenkins-operator 的 backup 和 restore 机制,具体内容能够查看这儿[4])
高阶篇:利用 kustomize + sops(gpg) 来部署 jenkins-operator
下面的流程给大家展现了如何一步步来实现 jenkins-operator 的装置和应用,然而通过 kubectl apply 来一个个创立须要的资源是比拟繁琐的,而且在多套差异化环境下,这种反复的工作量没有任何意义。所以本文应用了 kustomize 来治理差异化环境下泛滥的 yaml 文件,目录构造如下:
.├── base│ ├── config.yaml│ ├── jenkins-rbac.yaml│ ├── jenkins.yaml│ ├── jenkins_crd.yaml│ ├── jenkins_operator.yaml│ ├── kops-secret.yaml│ ├── kustomization.yaml│ └── secret│ └── credentials.secret.yaml└── overlays ├── dev │ ├── ingress.yaml │ ├── jenkins.yaml │ ├── kops-secret.yaml │ ├── kustomization.yaml │ └── secret │ └── secret.tls.yaml ├── prod │ ├── ingress.yaml │ ├── jenkins.yaml │ ├── kops-secret.yaml │ ├── kustomization.yaml │ └── secret │ └── secret.tls.yaml └── svt ├── ingress.yaml ├── jenkins.yaml ├── kops-secret.yaml ├── kustomization.yaml └── secret └── secret.tls.yaml
对于 kustomize 的应用办法,大家能够看这儿[5]。上述整个代码库在这儿[6]。文中应用了 sops[7] 来加密 yaml 文件中的敏感信息,这样真正可能做到将所有代码化,而后托管到 GitHub 上。
依据不同环境的差异性,批改不同的配置文件后,能够应用以下命令来疾速装置应用 Jenkins Operator
$ kustomize build --enable-alpha-plugins . | kubectl -n jenkins apply -f -serviceaccount/jenkins unchangedserviceaccount/jenkins-operator unchangedrole.rbac.authorization.k8s.io/jenkins-operator unchangedrolebinding.rbac.authorization.k8s.io/jenkins-operator unchangedclusterrolebinding.rbac.authorization.k8s.io/jenkins-role-binding unchangedconfigmap/jenkins-config configuredsecret/github-ssh-key configuredsecret/github-token configuredsecret/slack-token configuredsecret/your-container-registry configureddeployment.apps/jenkins-operator configuredjenkins.jenkins.io/jenkins configuredingress.networking.k8s.io/jenkins unchanged
--enable-alpha-plugins
是因为应用了 sops 进行了敏感信息加密。对于 sops 的具体应用,敬请期待后续文章。
参考
[1] https://www.jenkins.io/blog/2...
[2] https://kubernetes.io/docs/co...
[3] https://github.com/jenkinsci/...
[4] https://jenkinsci.github.io/k...
[5] https://kustomize.io/
[6] https://github.com/majinghe/j...
[7] https://github.com/mozilla/sops
起源:DevSecOps SIG
作者:小马哥
5月每周四晚8点,【冬哥有话说】品质与测试专场。公众号留言“品质”可获取地址
- 0506 朱少民 《如何最大化软件测试效力》
- 0513 陈琦 《数据驱动测试》
- 0520 陈霁 《没错,去QA是提高质量最无效的办法!》
- 0527 施慧斌 《DevOps实际之继续测试》