在《Centos7下安装配置最新版本Jenkins(2.452.3)》这篇博文中讲解了如何安装Jenkins,虽然在安装Jenkins时安装了一些必备的推荐插件,但在企业环境中使用Jenkins之前,我们仍需完成一系列手动配置工作,如配置 System Configuration、Security。
示例 1 配置 System Configuration——System(配置系统)页面:
如果你是一名 Jenkins 管理员,那么你一定不会对上面这个页面感到陌生,每次部署完一个新的Jenkins实例,在可以使用之前,往往都需要在上面页面作出一些相应的配置(主目录、执行器数量、Jenkins URL、系统管理员邮件地址、Resource Root URL等)。 该页面除了包含 Jenkins 自身的一些基本配置信息外,同时还包括了当前系统中所安装的插件的配置信息。也就是说,当你的 Jenkins 安装的插件越多,该页面的配置项就有可能会越多。
示例 2 配置 Security——Security(配置全局安全性)页面:
Jenkins 管理员在这里可以配置认证、授权、代理、跨域等内容。
而 Jenkins 配置即代码(Configuration as Code) ,正是这样一款能够帮助我们从这些大量手动配置的工作中解放出来的 Jenkins 插件。Jenkins Configuration as Code Plugin 允许用户将System Configuration、Security等 Jenkins 的配置信息写入到一个 YAML 文件中。这样,可以将 Jenkins 的配置标准化,便于在团队内部复用,易于传播、便于快速搭建开箱即用的 Jenkins 服务。借助这个插件,我们几乎不再需要通过人工在 UI 界面上点击的方式来配置 Jenkins 服务。而且,绝大部分其他插件几乎(甚至)不需要做任何调整,就可以与该插件兼容。本文将详细解决如何在Jenkins使用 Jenkins Configuration as Code。
注意 1:Configuration as Code 插件的主要作用是减少 Jenkins 管理员通过 UI 界面进行手动配置的工作。然而,并不能通过CasC管理的配置文件安装 Jenkins 插件。因此,在使用 Configuration as Code 插件之前,需要确保 Jenkins 实例已经安装了配置文件中涉及到的所有插件。
Jenkins Configuration as Code,又名 JCasC,它允许我们将所有关于 Jenkins 的配置以 YAML 的格式写入到配置文件中去,并通过对装有该插件的 Jenkins 实例应用这些配置文件,来实现一键式自动化配置 Jenkins 的目的。
JCasC 为编写 YAML 文件提供一系列特定的 Key 值,这些 Key 值分别对应 Jenkins 中不同的配置项。通过为这些 Key 值赋值的方式来达到配置 Jenkins 的目的,下面是官方提供的一个示例配置文件:
jenkins: systemMessage: "Jenkins configured automatically by Jenkins Configuration as Code plugin\n\n" securityRealm: ldap: configurations: - groupMembershipStrategy: fromUserRecord: attributeName: "memberOf" inhibitInferRootDN: false rootDN: "dc=acme,dc=org" server: "ldaps://ldap.acme.org:1636" nodes: - permanent: name: "static-agent" remoteFS: "/home/jenkins" launcher: jnlp: workDirSettings: disabled: true failIfWorkDirIsMissing: false internalDir: "remoting" workDirPath: "/tmp" slaveAgentPort: 50000 agentProtocols: - "jnlp2" tool: git: installations: - name: git home: /usr/local/bin/git credentials: system: domainCredentials: - credentials: - basicSSHUserPrivateKey: scope: SYSTEM id: ssh_with_passphrase_provided username: ssh_root passphrase: ${SSH_KEY_PASSWORD} description: "SSH passphrase with private key file. Private key provided" privateKeySource: directEntry: privateKey: ${SSH_PRIVATE_KEY}
该配置文件中使用了 JCasC 提供的三个根配置元素 Key 值:jenkins、tool 和 credentials,分别对应 Jenkins 的基本配置项、全局工具配置项,以及 Jenkins Credentials 相关的配置项。通过为这些根 Key 值所提供的子配置项 Key 设定适当的值,我们分别对 Jenkins 作出了如下配置:
除了上面示例中所使用到的三个根配置元素外, unclassified 是另一个非常常见的根配置元素,大部分针对于插件的配置都被包含在了该根元素下。
而除了这几个根配置元素自身外,每个根配置元素下又提供了大量子配置 Key 值,并且根据安装的插件的不同,每个 Jenkins 实例所支持的这些子 Key 值也不尽相同。JCasC 提供的Documentation 页面(Dashboard -> Manage Jenkins -> Configuration as Code -> 页面最下面参考 -> 文档)列出了当前 Jenkins 实例中所支持的所有 Key 值信息。
Jenkins插件中心安装Configuration as Code Plugin插件,安装完成后需要重启Jenkins。
安装成功后,可以看到System Configuration功能模块下多了Configuration as Code功能选项。
鼠标点击Configuration as Code功能选项进入Configuration as Code功能页面。功能比较简单,这里不再多说。这里有2个快速编写jenkins.yaml文件的小技巧:
示例,当前的Jenkins环境仅安装了一些插件,并进行了基本的系统配置和安全配置。通过图形化界面查看和导出配置可以生成一个 jenkins.yaml 文件。下次安装新的Jenkins时,只需简单调整这个 jenkins.yaml 文件即可,无需再次在图形化界面手动配置这些参数。
除了可以在 UI 界面上操作 CasC 的相关功能,CLI 也有对应的支持。
$ jcli casc Configuration as Code Usage: jcli casc [command] Available Commands: apply 从应用已有的配置 export 导出配置及代码的配置 open 在浏览器中打开配置及代码的页面 reload 重新加载配置及代码的配置 schema 获取配置及代码的结构
也可以通过Restful接口操作 CasC 的相关功能。
导出配置 curl -X POST -u admin:112e74ac1ded9b9af4854e594405819df9 http://localhost:8080/configuration-as-code/export 查看 Schema curl -X POST -u admin:112e74ac1ded9b9af4854e594405819df9 http://localhost:8080/configuration-as-code/schema 重新加载配置 curl -X POST -u admin:112e74ac1ded9b9af4854e594405819df9 http://localhost:8080/configuration-as-code/reload 从请求中应用配置 curl -X POST -u admin:112e74ac1ded9b9af4854e594405819df9 http://localhost:8080/configuration-as-code/apply
另外,CasC只是配置支持同时加载多个配置文件。如果我们将 Jenkins 的不同部分拆分成多个文件,维护起来会很方便。
支持的策略:
策略名称的配置方式有两种:
jenkins: mode: EXCLUSIVE numExecutors: 0 scmCheckoutRetryCount: 2 disableRememberMe: true clouds: - kubernetes: name: "kubernetes" serverUrl: "https://kubernetes.default" skipTlsVerify: true namespace: "devops-system" credentialsId: "k8s-service-account" jenkinsUrl: "http://devops-jenkins.devops-system:80" jenkinsTunnel: "devops-jenkins-agent.devops-system:50000" containerCapStr: "10" connectTimeout: "60" readTimeout: "60" maxRequestsPerHostStr: "32" templates: - name: "base" namespace: "devops-system" label: "base" nodeUsageMode: "NORMAL" idleMinutes: 0 containers: - name: "base" image: "builder-base:v3.2.2" command: "cat" args: "" ttyEnabled: true privileged: false resourceRequestCpu: "100m" resourceLimitCpu: "4000m" resourceRequestMemory: "100Mi" resourceLimitMemory: "8192Mi" - name: "jnlp" image: "jenkins/inbound-agent:4.10-2" args: "^${computer.jnlpmac} ^${computer.name}" resourceRequestCpu: "50m" resourceLimitCpu: "500m" resourceRequestMemory: "400Mi" resourceLimitMemory: "1536Mi" workspaceVolume: emptyDirWorkspaceVolume: memory: false volumes: - hostPathVolume: hostPath: "/var/run/docker.sock" mountPath: "/var/run/docker.sock" - hostPathVolume: hostPath: "/var/data/jenkins_sonar_cache" mountPath: "/root/.sonar/cache" yaml: | spec: affinity: nodeAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 1 preference: matchExpressions: - key: node-role.kubernetes.io/worker operator: In values: - ci tolerations: - key: "node.kubernetes.io/ci" operator: "Exists" effect: "NoSchedule" - key: "node.kubernetes.io/ci" operator: "Exists" effect: "PreferNoSchedule" containers: - name: "base" resources: requests: ephemeral-storage: "1Gi" limits: ephemeral-storage: "10Gi" securityContext: fsGroup: 1000 - name: "nodejs" namespace: "devops-system" label: "nodejs" nodeUsageMode: "EXCLUSIVE" idleMinutes: 0 containers: - name: "nodejs" image: "builder-nodejs:v3.2.0" command: "cat" args: "" ttyEnabled: true privileged: false resourceRequestCpu: "100m" resourceLimitCpu: "4000m" resourceRequestMemory: "100Mi" resourceLimitMemory: "8192Mi" - name: "jnlp" image: "jenkins/inbound-agent:4.10-2" args: "^${computer.jnlpmac} ^${computer.name}" resourceRequestCpu: "50m" resourceLimitCpu: "500m" resourceRequestMemory: "400Mi" resourceLimitMemory: "1536Mi" workspaceVolume: emptyDirWorkspaceVolume: memory: false volumes: - hostPathVolume: hostPath: "/var/run/docker.sock" mountPath: "/var/run/docker.sock" - hostPathVolume: hostPath: "/var/data/jenkins_nodejs_yarn_cache" mountPath: "/root/.yarn" - hostPathVolume: hostPath: "/var/data/jenkins_nodejs_npm_cache" mountPath: "/root/.npm" - hostPathVolume: hostPath: "/var/data/jenkins_sonar_cache" mountPath: "/root/.sonar/cache" yaml: | spec: affinity: nodeAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 1 preference: matchExpressions: - key: node-role.kubernetes.io/worker operator: In values: - ci tolerations: - key: "node.kubernetes.io/ci" operator: "Exists" effect: "NoSchedule" - key: "node.kubernetes.io/ci" operator: "Exists" effect: "PreferNoSchedule" containers: - name: "nodejs" resources: requests: ephemeral-storage: "1Gi" limits: ephemeral-storage: "10Gi" securityContext: fsGroup: 1000 securityRealm: ldap: configurations: - displayNameAttributeName: "uid" mailAddressAttributeName: "mail" inhibitInferRootDN: false managerDN: "cn=admin,dc=zmc,dc=io" managerPasswordSecret: "admin" rootDN: "dc=zmc,dc=io" userSearchBase: "ou=Users" userSearch: "(&(objectClass=inetOrgPerson)(|(uid={0})(mail={0})))" groupSearchBase: "ou=Groups" groupSearchFilter: "(&(objectClass=posixGroup)(cn={0}))" server: "ldap://openldap.kubernetes-system.svc:389" disableMailAddressResolver: false disableRolePrefixing: true unclassified: gitLabServers: servers: - name: "https://gitlab.com" serverUrl: "https://gitlab.com"
以上jenkins.yaml配置文件是基于CASC插件的,用于在Jenkins实例启动时自动加载配置。它配置了Jenkins的各个方面,包括执行模式、Kubernetes集群的连接和Pod模板、安全设置等。以下是对每个部分的解释:
jenkins: mode: EXCLUSIVE numExecutors: 0 scmCheckoutRetryCount: 2 disableRememberMe: true
clouds: - kubernetes: name: "kubernetes" serverUrl: "https://kubernetes.default" skipTlsVerify: true namespace: "devops-system" credentialsId: "k8s-service-account" jenkinsUrl: "http://devops-jenkins.devops-system:80" jenkinsTunnel: "devops-jenkins-agent.devops-system:50000" containerCapStr: "10" connectTimeout: "60" readTimeout: "60" maxRequestsPerHostStr: "32"
配置了多个Pod模板,用于不同的构建环境。每个模板都包含具体的容器配置、资源请求和限制、存储卷以及亲和性等。示例中配置了base、nodejs,如需其他容器模板的话,按需添加即可。
templates: - name: "base" namespace: "devops-system" label: "base" nodeUsageMode: "NORMAL" idleMinutes: 0 ...... securityContext: fsGroup: 1000
securityRealm: ldap: configurations: - displayNameAttributeName: "uid" mailAddressAttributeName: "mail" inhibitInferRootDN: false managerDN: "cn=admin,dc=zmc,dc=io" managerPasswordSecret: "admin" rootDN: "dc=zmc,dc=io" userSearchBase: "ou=Users" userSearch: "(&(objectClass=inetOrgPerson)(|(uid={0})(mail={0})))" groupSearchBase: "ou=Groups" groupSearchFilter: "(&(objectClass=posixGroup)(cn={0}))" server: "ldap://openldap.kubernetes-system.svc:389" disableMailAddressResolver: false disableRolePrefixing: true
unclassified: gitLabServers: servers: - name: "https://gitlab.com" serverUrl: "https://gitlab.com"
Jenkins 配置即代码(Configuration as Code) 能够帮助我们从大量手动配置Jenkins的工作中解放出来。Jenkins Configuration as Code Plugin 允许用户将System Configuration、Security等 Jenkins 的配置信息写入到一个 YAML 文件中。这样,可以将 Jenkins 的配置标准化,便于在团队内部复用,易于传播、便于快速搭建开箱即用的 Jenkins 服务。借助这个插件,我们几乎不再需要通过人工在 UI 界面上点击的方式来配置 Jenkins 服务(实现Jenkins零配置)。而且,绝大部分其他插件几乎(甚至)不需要做任何调整,就可以与该插件兼容。
对于CASC管理的配置文件,除了这几个根配置元素自身外,每个根配置元素下又提供了大量子配置 Key 值,并且根据安装的插件的不同,每个 Jenkins 实例所支持的这些子 Key 值也不尽相同。JCasC 提供的Documentation 页面(Dashboard -> Manage Jenkins -> Configuration as Code -> 页面最下面参考 -> 文档)列出了当前 Jenkins 实例中所支持的所有 Key 值信息(如果不清楚配置放到哪个配置元素下,一定要看当前Jenkins实例的Documentation 页面)。
Jenkins 的插件成千上万,Jenkins 的配置也同样千变万化,关于更多如何编写 JCasC 配置文件,请参考官方示例
主要参考:https://github.com/jenkinsci/configuration-as-code-plugin
主要参考:https://www.jenkins-zh.cn/tutorial/management/plugin/configuration-as-code/