在上一篇介绍的 [如何利用 Helm 在 Kubernetes 上快速部署 Jenkins](https://segmentfault.com/a/11...
) 文章中,我们讲解了如何利用 Helm 官方提供的 Jenkins Chart,来快速部署一个满足我们需求的 Jenkins 实例。

虽然新部署的 Jenkins 实例自动为我们安装了所有所需的插件,并配置好了初始化 Job 等工作,但在开始使用它之前,我们仍需要完成一系列手动工作,如配置 Jenkins 的 “Configure System” 页面:

image.png

如果你是一名 Jenkins 管理员,那么你一定不会对这个页面感到陌生,每次部署完一个新的 Jenkins 实例,在可以使用之前,我们往往都需要在该页面作出一些相应的配置。该页面除了包含 Jenkins 自身的一些基本配置信息外,同时还包括了当前系统中所安装的插件的配置信息。也就是说,当你的 Jenkins 安装的插件越多,该页面的配置项就有可能会越多。

而除此之外,你可能还需要对它进行一些其它的诸如配置 Jenkins 安全相关的配置项、创建 Jenkins Credentials、配置 Jenkins Job 的工作节点(包括物理节点和 Cloud 节点)等手动工作。

而 Jenkins Configuration as Code ,正是这样一款能够帮助我们从这些大量手动配置的工作中解放出来的 Jenkins 插件。本文将简单介绍什么是 Jenkins Configuration as Code 以及如何在 Helm Chart 中使用它来自动配置我们所部署的 Jenkins 实例。

Jenkins Configuration as Code 简介

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 值:jenkinstoolcredentials,分别对应 Jenkins 的基本配置项、全局工具配置项,以及 Jenkins Credentials 相关的配置项。通过为这些根 Key 值所提供的子配置项 Key 设定适当的值,我们分别对 Jenkins 作出了如下配置:

jenkins

  • systemMessage Key 设定了 Jenkins 的 "System Message" 信息。
  • securityRealm Key 设定了 LDAP 相关配置,并将其设定为 Jenkins 的认证方式。
  • nodes Key 创建一个名为 static-agent 的节点,并对其进行了适当对配置。
  • slaveAgentPort Key 设定了 Jenkins 主机与节点之间的通信端口号以及通信协议。
  • agentProtocols Key 设定 Jenkins 主机与节点之间对通信协议。

tool

  • git 为 Jenkins 的全局工具 Git 指定了默认执行路径。

credentials

  • 创建一个 ID 为 ssh_with_passphrase_provided 的系统级的 SSH credential。

JCasC 插件页

JCasC 在 Jenkins 中提供了单独的插件页面,可在安装了该插件的 Jenkins 中可通过 "Manage Jenkins" -> "Configuration as Code" 菜单来打开它:

image.png

该页面包含了一些常用的功能选项,如对当前 Jenkins 实例应用某个给定的配置文件,查看为当前 Jenkins 实例生成的配置文件等等。

JCasC 插件提供了大量的配置示例(https://github.com/jenkinsci/...),这其中包含了几乎所有关于 Jenkins 的配置以及大部分的插件配置,参考这些配置示例可帮助我们快速编写出自己的配置文件来。

另一种编写 YAML 配置文件的小技巧是,首先通过手动的方式对 Jenkin 做好所有配置,在通过该插件页的 “View Configuration” 获取 JCasC 为我们自动生成出来的配置文件作为参考,来编写我们自己的配置文件。

Documentation 页面

除了上面示例中所使用到的三个根配置元素外, unclassified 是另一个非常常见的根配置元素,大部分针对于插件的配置都被包含在了该根元素下。

而除了这几个根配置元素自身外,每个根配置元素下又提供了大量子配置 Key 值,并且根据安装的插件的不同,每个 Jenkins 实例所支持的这些子 Key 值也不尽相同。JCasC 提供的 Documentation 页面列出了该插件在当前 Jenkins 实例中所支持的所有 Key 值信息,该页面可通过插件页下方的 “Documentation” 链接打开:

image.png

需要注意的是,该页面的内容是动态创建出来的,根据当前 Jenkins 中所安装的插件的不同,所展示出来的 Key 值也可能会有稍微的不同。

在 Jenkins Helm Chart 中使用 JCasC 插件

Jenkins Helm Chart 实现了对 JCasC 插件对集成。它允许我们将 JCasC 的配置信息存储在自定义的 values 文件中,并在部署好 Jenkins 后自动应用这些配置信息。下面是一个包含了简单配置的 values.yaml 文件:

master:
  JCasC:
    enabled: true
    configScripts:
      welcome-message: |
        jenkins:
          systemMessage: Welcome to our CI\CD server.  This Jenkins is configured and managed 'as code'.

在该 values 文件中首先将 JCasC.enabled 设置为 true,表示在部署的过程中自动安装 JCasC 插件,并使用它来配置部署的 Jenkins 实例。

JCasC.configScripts 用于保存所有 JCasC 的配置信息,我们可通过定义全局唯一的 Key 的方式,将这些配置文件分成不同的配置块,每个配置块下包含的就是 JCasC 原生的 YAML 格式的配置信息,如 welcome-message 配置下使用了根配置元素 jenkins 下的 systemMessage Key 来为我们部署的 Jenkins 实例设置 “Configure System” 信息。

在了解了如何在 Helm Chart 的自定义 values 文件中编写 JCasC 配置信息后,接下来就让我们看一下常见的 Jenkins 配置都是如何在 JCasC 中的实现。

Jenkins 基本配置

Jenkins 包含了许多基本配置项,首先让我们看一下 Jenkins 的基本配置项:

master:
  JCasC:
    enabled: true
    configScripts:
      basic-configuration: |
        jenkins:
          systemMessage: Welcome to our CI\CD server.  This Jenkins is configured and managed 'as code'.
          markupFormatter:
             rawHtml:
               disableSyntaxHighlighting: false
        unclassified:
          location:
            adminAddress: "you@example.com"
            url: "https://ci.example.com/"
          mailer:
            replyToAddress: do-not-reply@acme.org
            smtpHost: smtp.acme.org
            smtpPort: 4441
      approval-scripts: |
         security:
           scriptApproval:
             approvedSignatures:
             - "method groovy.json.JsonSlurperClassic parseText java.lang.String"
             - "new groovy.json.JsonSlurperClassic"
      global-libraries: |
        unclassified:
          globalLibraries:
            libraries:
              - name: "awesome-lib"
                defaultVersion: "master"
                implicit: false
                allowVersionOverride: true
                includeInChangesets: true
                retriever:
                  modernSCM:
                    scm:
                      git:
                        remote: "git@github.com:gbyukg/jenkins-libirary.git"
                        credentialsId: "SSHKEY4Github"

在上面的 values.yaml 文件中,我们为 configScripts 定义了三个配置脚本:

basic-configuration:

  • 为 Jenkins 设定 “System Message”。
  • 将 Jenkins “Global Security” 页面的 “Markup Formatter” 值设置为 “Saft HTML”
  • 为 Jenkins 配置页面的 “Jenkins URL” 和 “System Admin e-mail address” 设定值。
  • 设定 Jenkins 的 “E-mail Notification”。

approval-scripts

  • 为 Jenkins 设定可信任的 Groovy 方法。

global-libraries

  • 为 Jenkins 添加一个名为 awesome-lib 的 “Global Pipeline Libraries”,并用给定的 Credential 从远程 Git 仓库的 master 分之下载该共享库。

其中所使用的 SSHKEY4Github Credentials 为我们接下来要创建的。

再次提示:你可以在官方提供的 配置示例 中找到绝大多数你需要的配置。

创建 Credentials

JCasC 插件提供了专门的根配置元素 credentials,用于自动创建 Jenkins Credentials:

configScripts:
      credentials-config: |
        credentials:
          system:
            domainCredentials:
            - credentials:
              - usernamePassword:
                  description: "Password:  GitHub Token"
                  id: DevOpsToken4EEGithubAsPWD
                  username: "devops@email.com"
                  password: "DEVOPS-TOKEN-FOR-GITHUB"
                  scope: GLOBAL
              - string:
                  description: "Secret: GitHub Token"
                  id: "DevOpsToken4EEGithubAsSecret"
                  secret: "DEVOPS-TOKEN-FOR-GITHUB"
                  scope: GLOBAL
              - basicSSHUserPrivateKey:
                  description: "SSH-KEY: SSH Key for GitHub"
                  scope: GLOBAL
                  id: "SSHKEY4Github"
                  username: "devops@email.com"
                  privateKeySource:
                    directEntry:
                      privateKey: |
                        -----BEGIN OPENSSH PRIVATE KEY-----
                        ...
                        ...
                        ...
                        -----END OPENSSH PRIVATE KEY-----

在上面定义的 credentials-config 配置脚本中,分别创建了三个系统级别的 credentials:

  • Username and password 类型的 DevOpsToken4EEGithubAsPWD
  • Secret text 类型的 DevOpsToken4EEGithubAsSecret
  • SSH Username with private key 类型的 SSHKEY4Github

除了这三种类型的 Credentials 外,该插件还支持许多其它类型的 Credentials,更多细节请查看文档中关于 domainCredentials key 的说明。

配置 LDAP 认证及设置权限管理

我们通常会使用企业所提供的 LDAP 服务,来代替 Jenkins 系统默认的认证方式,下面展示了如何为 Jenkins 配置 LDAP 并使用它作为 Jenkins 的认证方式:

ldap-configuration: |
          jenkins:
            securityRealm:
              ldap:
                configurations:
                - groupSearchBase: "ou=memberlist,ou=ibmgroups"
                  inhibitInferRootDN: false
                  managerPasswordSecret: "XXXXXXXXXXXXXXXXXX"
                  rootDN: "o=ibm.com"
                  server: "ldaps://ldapserver.com:636"
                  userSearch: "mail={0}"
                  userSearchBase: "ou=bluepages"
                disableMailAddressResolver: false
                disableRolePrefixing: true
                groupIdStrategy: "caseInsensitive"
                userIdStrategy: "caseInsensitive"
      matrix-config: |
        jenkins:
          authorizationStrategy:
            projectMatrix:
              grantedPermissions:
                - "Agent/Build:sdp-devops-admins"
                - "Agent/Configure:sdp-devops-admins"
                ... more content

将 Jenkins 的认证方式设定为 LDAP,并设定为 “Project-based Matrix Authorization Strategy”:

image.png

其它常用插件设置

configScripts:
      git-config: |
        unclassified:
          gitscm:
            globalConfigName: jenkins
            globalConfigEmail: jenkins@email.com
            createAccountBasedOnEmail: false
      github-config: |
        gitHubConfiguration:
          apiRateLimitChecker: ThrottleForNormalize
          endpoints:
          - apiUri: "https://github.example.com/api/v3"
            name: "GitHub EE"
      github-ee: |
        unclassified:
          githubpluginconfig:
            configs:
            - credentialsId: "DevOpsToken4GithubAsSecret"
              manageHooks: false
              name: "GitHub"
            - name: "GitHub EE"
              apiUrl: "https://github.example.com/api/v3/"
              credentialsId: "DevOpsToken4EEthubAsSecret"
              manageHooks: false
      slack-config: |
        unclassified:
          slackNotifier:
            botUser: false
            room: "#slack-channel"
            sendAsText: false
            teamDomain: "luke"
            tokenCredentialId: "Token4SlackSecret"
  • git-config 为 Git 插件设定了 “Global Config user.name Value” 和 “Global Config user.name Value”;
  • github-config 为 Jenkins 添加 GitHub Enterprise Servers 项;
  • github-ee 为 Jenkins 设定了两个 GitHub Servers,一个是官方 Github,一个是 企业版Github,并分别为他们设定了对应的 Credentials;
  • slack-config 配置 Slack 插件,可用于向 Slack 发送消息;

启用 Sidecars 自动加载 JCasC

默认情况下,当我们对 values 文件中关于 JCasC 部分改动后,并使用 helm upgrade 对部署的 Jenkins 升级时,Helm Chart 会通过重新创建 Pod 对方式使这些更改生效,这会导致我们的 Jenkins 服务短暂离线。

Helm Chart 提供了另一种通过 sidecars 的方式将改动的 JCasC 配置信息实时应用到我们的 Jenkins 实例上,而无需重启 Pod。

采用该种方式部署 Jenkins 时,会将 JCasC.configScripts 下的每个配置块中的配置信息分别存储到与该配置块 Key 同名的 ConfigMap 中。同时会在 Jenkin Pod 中创建另一个名为 jenkins-sc-config 的容器,用于监控这些 ConfigMap 的改动。当我们使用 helm upgrade 升级部署时,这些 ConfigMap 的变更会被 jenkins-sc-config 容器捕获到,并将这些改动实施应用到 Jenkins 上。

开启 sidecars 非常简单,只需将 master.sidecars.configAutoReload.enabled 值设为 true 即可:

master:
  sidecars:
    configAutoReload:
      enabled: true

当部署完成后,会看到每个配置块都对应地生成了一个 ConfigMap:

$ kubectl -n jenkins get configmap
NAME                                         DATA   AGE
jenkins-jenkins-config-approval-scripts      1      2m45s
jenkins-jenkins-config-basic-configuration   1      2m45s
jenkins-jenkins-config-credentials-config    1      2m45s
jenkins-jenkins-config-global-libraries      1      2m45s
jenkins-jenkins-config-node-config           1      2m45s
... more output

并且此时 Jenkins Pod 中包含了 2 个运行中的容器:

$ kubectl -n jenkins get pods
NAME                       READY   STATUS    RESTARTS   AGE
jenkins-64c7cf4fc6-pjbps   2/2     Running   0          3m6s

通过这种方式部署的 Jenkins 实例,当我们对 JCasC.configScripts 下的配置信息进行更新,并通过 helm upgrade 方式升级 Jenkins 实例后,这些改动就将会被立刻应用到 Jenkins 实例中去了。

结束语

通过本小节的学习,我们已经了解了如何在 Jenkins Helm Chart 自定的 values 文件中,通过为 JCasC.configScripts Key 值设定 JCasC 配置项的方式,来帮助我们自动配置通过该 Chart 部署的新的 Jenkins 实例,实现真正的零配置。

Jenkins 的插件成千上万,Jenkins 的配置也同样千变万化,关于更多如何编写 JCasC 配置文件,请参考官方示例 https://github.com/jenkinsci/...

来源:DevSecOps SIG
作者:张泽亮
声明:文章获得作者授权在IDCF社区公众号(devopshub)转发。优质内容共享给思否平台的技术同伴,如原作者有其他考虑请联系小编删除,致谢。

7月每周四晚8点,【冬哥有话说】研发效能工具专场,公众号留言“效能”可获取地址

  • 7月8日,LEANSOFT-周文洋《微软DevOps工具链的 "爱恨情仇"(Azure DevOps)》
  • 7月15日,阿里云智能高级产品专家-陈逊《复杂型研发协作模式下的效能提升实践》
  • 7月22日,极狐(GitLab)解决⽅案架构师-张扬分享《基础设施即代码的⾃动化测试探索》
  • 7月29日,字节跳动产品经理-胡贤彬分享《自动化测试,如何做到「攻防兼备」?》
  • 8月5日,声网 AgoraCICD System负责人-王志分享《从0到1打造软件交付质量保证的闭环》

用户bPcN1SC
149 声望55 粉丝