Please enable Javascript to view the contents

Jenkins 在 Kubernetes 上的最佳实践

 ·  ☕ 3 分钟

1. 配置较大的 -Xms -Xmx 参数

Jenkins 是由 Java 编写的编排引擎, 在 Full GC 时会 Stop The World(STW)。在大规模构建时, STW 可能会导致 Jenkins 无法处理新的请求。

为了避免频繁的 STW, 同时增大并发量, 建议设置较大的堆, -Xms3g -Xmx6g -XX:MaxRAM=6g。具体数值可以根据监控值来设置, Java Full GC 之后, 内存占用会陡降。

2. request 不要设置太小

request 设置太小, 可能会导致 Jenkins 运行起来之后, 节点资源不足, 引发驱逐, 甚至压垮节点。

request 应该接近真实值, 如果有足够的机器资源, 应该配置亲和性, 让 Jenkins 尽可能运行在单独的机器上。request >= 1.25 * JVM 最大堆内存, limit >= 2 * JVM 最大堆内存。

3. IO 性能不能差

Jenkins 使用磁盘文件存储数据, 每条流水线、每次构建都会占用一个文件目录, 产生大量文件。通常流水线数量有限, 但在构建历史达到 10000+ 级别时, 会感受到 IO 对 Jenkins 的影响。

如果使用本地存储, 推荐使用高性能的 SSD。如果是使用网络存储, 需要高性能的网络支持, 同时加大客户端的缓存池。

4. 较大的 jenkins_home 的磁盘空间

磁盘满时, Jenkins 将不能工作, 在 Jenkins 后台会有错误提示。

建议对 Jenkins 的工作目录进行磁盘使用率监控, 并配置告警规则。如果没有监控告警系统, 那么建议直接设置一个较大的磁盘空间给 /var/jenkins_home 目录。因为有一些 Storage Class 不支持动态扩容, 当磁盘满时, 就只能手动拷贝迁移了。

5. 使用 Kubernetes plugin 在 Kuberntes 上构建

基于物理机、虚拟机的构建, 增加了运维成本、限制了并发的数量。

使用 Kubernetes plugin 插件在 Kubernetes 上进行构建能充分利用云原生易扩展、易维护的优势, 进行大规模的构建。参考:在 Kubernetes 上动态创建 Jenkins Slave 。由于构建比较占用资源, 为了避免对集群的影响, 可以配置亲和性, 将构建 Pod 集中到指定的节点执行。

6. 使用 CasC 管理 Jenkins 的配置

通过 Jenkins 页面进行各种构建、安全等配置, 不仅繁琐、不易维护, 而且不能够复用。

使用 CasC 插件, 允许用户将 Jenkins 的配置, 通过文本的形式进行描述, 还可以放置到 Git 仓库中进行版本管理。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
jenkins:
  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"

7. 使用 Custom WAR Packager 打包 Jenkins

在部署一套新的 Jenkins 环境时, 会需要安装大量插件, 非常影响部署速度, 同时插件是否能正常下载也存在不确定性。

Custom WAR Packager 允许用户将 Jenkins 、配置、插件打包成一个完整的 war 包或者镜像。这样无论是开发测试, 还是线上部署, 都可以很方便的部署, 并且环境一致, 而用户只需要写一个 yaml 文件。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
bundle:
  groupId: com.dev
  artifactId: "jenkins"
  description: "Jenkins Custom With Package"
  vendor: "Jenkins Project"
buildSettings:
  docker:
    base: jenkins/jenkins:2.277.4
    tag: shaowenchen/jenkins:2.277.4
    build: true
war:
  groupId: org.jenkins-ci.main
  artifactId: jenkins-war
  source:
    version: 2.277.4
plugins:
  - groupId: io.jenkins
    artifactId: configuration-as-code
    source:
      version: "1.47"
libPatches:
  - groupId: "org.jenkins-ci.main"
    artifactId: "remoting"
    source:
      git: https://github.com/jenkinsci/remoting.git
systemProperties: {
     jenkins.model.Jenkins.slaveAgentPort: "50000",
     jenkins.model.Jenkins.slaveAgentPortEnforce: "true"}
groovyHooks:
  - type: "init"
    id: "initScripts"
    source: 
      dir: scripts
casc:
  - id: "jcasc-config"
    source:
      dir: jenkins.yml

8. Jenkins Shared Libraries

在使用 Groovy 编写 Pipeline 的过程中, 经常会有大量重复代码。

Jenkins 共享库提供函数级别的共享, 可以在不同流水线之间复用同一套函数逻辑, 对于平台建设、大规模使用场景适用。不仅能加快 Pipeline 编写, 还方便维护、平滑升级。

1
2
3
4
5
@Library('utils') import org.foo.Utilities
def utils = new Utilities(this)
node {
  utils.mvn 'clean package'
}

9. 定期重启 Jenkins Master

虽然你会做很多的优化, 但是最后发现重启依然能解决很多的问题。

每隔一段时间, 大约一个月, 就会 Agent 连不上, 构建并发上不去, 失败率增加等问题。这是重启一下 Jenkins Master 服务, CICD 系统又恢复了正常, 只是整个服务中断了几分钟。

因此, 在没有多个 Jenkins Master 可以切换时, 定期告诉用户, 需要停机短暂维护, 非常有用。

10. 参考


微信公众号
作者
微信公众号