使用 DevStream 部署 Jenkins

    • 有一个可用的 Kubernetes 集群,版本 1.10+
    • 配置好 StorageClass

    可选满足

    • 配置好 Ingress 控制器(如果需要使用 Ingress 暴露服务)

    如果你还没有准备好一个满足上述要求的 Kubernetes 集群,可以参考 minikube 文档 快速创建一个 Kubernetes 测试集群。 在成功执行完 命令后,假如需要启用 Ingress,可以通过 minikube addons enable ingress 命令完成 Ingress 控制器的启用。 因为 minikube 方式部署的 Kubernetes 集群会自带一个名字为 standard 的 default StorageClass,所以当前集群满足上述全部前置要求。

    2、开始部署

    下文将介绍如何配置 jenkins 插件,完成 Jenkins 应用的部署。本文演示环境为一台有通过 minikube 方式部署的单节点 Kubernetes 集群的 Macbook/m1 电脑。

    如果仅是用于开发、测试等目的,希望快速完成 Jenkins 的部署,可以使用如下配置快速开始:

    YAML

    注意:这个配置示例仅是 tool config,完整的 DevStream 配置文件还需要补充 core config 等内容,具体参考。

    在成功执行 dtm apply 命令后,我们可以在 jenkins 命名空间下看到下述主要资源:

    • StatefulSet (kubectl get statefulset -n jenkins)

    Bash

    1. NAME READY AGE
    2. jenkins 1/1 3m10s
    • Service (kubectl get service -n jenkins)

    Bash

    1. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
    2. jenkins NodePort 10.103.31.213 <none> 8080:32000/TCP 3m30s
    3. jenkins-agent ClusterIP 10.100.239.11 <none> 50000/TCP 3m30s
    • PersistentVolumeClaim (kubectl get pvc -n jenkins)

    Bash

    1. NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
    2. jenkins Bound pvc-f474b131-dea8-4ac3-886b-8549da2cad56 8Gi RWO standard 3m50s
    • PersistentVolume (kubectl get pv)

    Bash

    1. NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
    2. pvc-f474b131-dea8-4ac3-886b-8549da2cad56 8Gi RWO Delete Bound jenkins/jenkins standard 4m10s

    前面我们提到过 Kubernetes 集群里需要有一个 StorageClass,当前 Jenkins 所使用的 pv 来自于集群中 default StorageClass:

    Bash

    1. NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
    2. standard (default) k8s.io/minikube-hostpath Delete Immediate false 20h

    到这里,我们就可以通过 NodePort 方式访问 Jenkins 登录页面了。但是由于我们的 Kubernetes 测试集群使用的是 minikube 方式部署, 而不是 kubeadm 这种直接在主机上部署 Kubernetes 相关组件的方式,所以这里还需要一步操作:

    • 服务暴露 (minikube service jenkins -n jenkins)

    Bash

    这时候 minikube 会自动打开浏览器,跳转到 http://127.0.0.1:65398 页面(如果没有自动跳转,可以手动打开浏览器,输入这个 url;注意:根据你的命令行输出内容修改 url 中的端口号):

    • 登录

    Jenkins Dashboard

    最后,记得修改密码哦!

    jenkins 插件的配置项多数都有默认值,具体默认值信息如下表:

    2.3、持久化存储

    前面”快速开始”中我们使用了 default StorageClass 来分配 pv 完成了 Jenkins 数据落到本地磁盘的过程。 因此如果你的环境中有其他 StorageClass 可以支持 pv 数据落到远程存储,就可以通过如下配置来自定义 Jenkins 所使用的 StorageClass:

    YAML

    1. tools:
    2. - name: helm-installer
    3. instanceID: jenkins-001
    4. dependsOn: [ ]
    5. options:
    6. valuesYaml: |
    7. serviceAccount:
    8. create: true
    9. name: jenkins
    10. persistence:
    11. storageClass: nfs
    12. controller:
    13. adminUser: "admin"
    14. adminPassword: "changeme"
    15. serviceType: NodePort
    16. nodePort: 32000

    上述配置以 nfs StorageClass 为例,请记得将 persistence.storageClass 修改成你的环境中真实 StorageClass 的名字。

    在”快速开始”中我们通过 NodePort 方式来暴露 Jenkins 服务。如果你想通过 Ingress 来暴露服务,可以这样配置:

    YAML

    1. tools:
    2. - name: helm-installer
    3. instanceID: jenkins-001
    4. dependsOn: [ ]
    5. options:
    6. valuesYaml: |
    7. serviceAccount:
    8. create: true
    9. name: jenkins
    10. persistence:
    11. storageClass: ""
    12. controller:
    13. adminPassword: "changeme"
    14. ingress:
    15. enabled: true
    16. hostName: jenkins.example.com

    使用当前配置成功执行 dtm apply 命令后,可以看到环境里的 Ingress 资源如下:

    • Ingress (kubectl get ingress -n jenkins)

    Bash

    1. NAMESPACE NAME CLASS HOSTS ADDRESS PORTS AGE
    2. jenkins jenkins nginx jenkins.example.com 192.168.49.2 80 9m13s

    至此,只要 DNS 服务器能够解析到域名 jenkins.example.com,那么你就可以通过这个域名来访问 Jenkins 了。 当然,没有合适的 DNS 服务器的情况下,你也可以通过修改 hosts 记录来完成静态域名解析,将如下这行配置追加到 /etc/hosts 文件中:

    Bash

    1. 192.168.49.2 jenkins.example.com

    2.5、推荐配置

    // TODO(daniel-hutao): 继续细化

    YAML

    1. tools:
    2. instanceID: jenkins-001
    3. dependsOn: [ ]
    4. options:
    5. valuesYaml: |
    6. serviceAccount:
    7. create: true
    8. name: jenkins
    9. persistence:
    10. storageClass: ""
    11. controller:
    12. adminUser: "admin"
    13. adminPassword: "changeme"
    14. ingress:
    15. enabled: true
    16. hostName: jenkins.example.com
    17. installPlugins:
    18. - kubernetes:3600.v144b_cd192ca_a_
    19. - workflow-aggregator:581.v0c46fa_697ffd
    20. - git:4.11.3
    21. - configuration-as-code:1512.vb_79d418d5fc8
    22. additionalPlugins:
    23. # install "GitHub Pull Request Builder" plugin, see https://plugins.jenkins.io/ghprb/ for more details
    24. - ghprb
    25. # install "OWASP Markup Formatter" plugin, see https://plugins.jenkins.io/antisamy-markup-formatter/ for more details
    26. - antisamy-markup-formatter
    27. # Enable HTML parsing using OWASP Markup Formatter Plugin (antisamy-markup-formatter), useful with ghprb plugin.
    28. enableRawHtmlMarkupFormatter: true
    29. # Jenkins Configuraction as Code, refer to https://plugins.jenkins.io/configuration-as-code/ for more details
    30. # notice: All configuration files that are discovered MUST be supplementary. They cannot overwrite each other'sconfiguration values. This creates a conflict and raises a ConfiguratorException.
    31. JCasC:
    32. defaultConfig: true

    3、状态管理

    DevStream 的默认状态文件为 devstream.state,可以通过配置文件中的 state.options 字段来自定义:

    YAML

    其中 resource 部分保存的是资源实例的最新状态,也就是这部分:

    1. outputs:
    2. jenkins_url: http://jenkins.jenkins:8080
    3. valuesYaml: |
    4. serviceAccount:
    5. create: true
    6. name: jenkins
    7. controller:
    8. adminUser: "admin"
    9. ingress:
    10. enabled: true
    11. hostName: jenkins.example.com
    12. workflows: |
    13. statefulsets:
    14. - name: jenkins
    15. ready: true

    换言之,目前 jenkins 插件关注的状态主要是自身 StatefulSet 资源状态和 valuesYaml 的配置,也就是在两种情况下会判定状态漂移,从而触发更新操作:

    1. StatefulSet 状态变更
    2. valuesYaml 部分配置变更

    在上一小节我们看到了 jenkins 插件的状态中保存了一个 outputs 字段,内容是 jenkins_url: http://jenkins.jenkins:8080, 所以其他插件的配置中可以通过${{jenkins.default.outputs.jenkins_url}} 的语法读取到 http://jenkins.jenkins:8080

    更多关于”插件输出”的内容,请阅读。

    5、离线环境部署

    // TODO(daniel-hutao): 本节内容近期将持续补充完善

    如果需要在离线环境部署 Jenkins,你需要下载对应的 helm chart 包:

    Bash

    1. helm repo add jenkins https://charts.jenkins.io
    2. helm repo update
    3. helm search repo jenkins -l
    4. helm pull jenkins/jenkins --version=4.2.5

    这时你会得到一个 jenkins-4.2.5.tgz 文件,你可以将其存放到一个合适的目录,比如 ~/devstream-test/jenkins-4.2.5.tgz,然后在配置文件就可以这样引用这个 chart 包了:

    YAML

    1. - name: helm-installer
    2. instanceID: jenkins-001
    3. dependsOn: [ ]
    4. options:
    5. chart:

    5.2、容器镜像

    jenkins 插件支持使用自定义容器镜像,你需要先在 valuesYaml 部分加上如下配置:

    YAML

    1. valuesYaml: |
    2. controller:
    3. image: [[ imageRepo ]]/devstreamdev/jenkins
    4. tag: 2.361.1-jdk11-dtm-0.1
    5. imagePullPolicy: "IfNotPresent"
    6. sidecars:
    7. configAutoReload:
    8. image: [[ imageRepo ]]/kiwigrid/k8s-sidecar:1.15.0
    9. agent:
    10. image: [[ imageRepo ]]/jenkins/inbound-agent
    11. tag: 4.11.2-4
    12. backup:
    13. image:
    14. repository: [[ imageRepo ]]/maorfr/kube-tasks
    15. tag: 0.2.0

    这段配置中留了一个变量 [[ imageRepo ]],你可以在中定义这个变量,变量值设置成你的镜像仓库地址,例如:

    YAML

    1. imageRepo: harbor.example.com:9000

    当然,你需要保证需要的镜像都在你的镜像仓库中存在。

    你可以下载镜像列表文件, 然后借助工具脚本来准备镜像。

    Bash

    如果你还没有一个私有镜像仓库,可以参考这篇文章快速部署一个 Docker Registry。

    可能你已经注意到前面的镜像列表里有一个 DevStream 自定义镜像 devstreamdev/jenkins:2.361.1-jdk11-dtm-0.1, 在这个镜像里 DevStream 为离线部署场景做了增强,所以对应的配置文件我们也需要做一些调整,如下:

    1. ---
    2. # variable config
    3. imageRepo: harbor.example.com:9000
    4. ---
    5. tools:
    6. - name: helm-installer
    7. instanceID: jenkins-001
    8. dependsOn: [ ]
    9. options:
    10. chart:
    11. chartPath: "~/devstream-test/jenkins-4.2.5.tgz"
    12. # custom configuration. You can refer to [Jenkins values.yaml](https://github.com/jenkinsci/helm-charts/blob/main/charts/jenkins/values.yaml)
    13. valuesYaml: |
    14. serviceAccount:
    15. create: true
    16. name: jenkins
    17. controller:
    18. image: [[ imageRepo ]]/devstreamdev/jenkins
    19. tag: 2.361.1-jdk11-dtm-0.1
    20. imagePullPolicy: "IfNotPresent"
    21. sidecars:
    22. configAutoReload:
    23. image: [[ imageRepo ]]/kiwigrid/k8s-sidecar:1.15.0
    24. adminUser: "admin"
    25. adminPassword: "changeme"
    26. ingress:
    27. enabled: true
    28. hostName: jenkins.example.com
    29. # Enable HTML parsing using OWASP Markup Formatter Plugin (antisamy-markup-formatter), useful with ghprb plugin.
    30. enableRawHtmlMarkupFormatter: true
    31. # Jenkins Configuraction as Code, refer to https://plugins.jenkins.io/configuration-as-code/ for more details
    32. # notice: All configuration files that are discovered MUST be supplementary. They cannot overwrite each other's configuration values. This creates a conflict and raises a ConfiguratorException.
    33. JCasC:
    34. defaultConfig: true
    35. agent:
    36. image: [[ imageRepo ]]/jenkins/inbound-agent
    37. tag: 4.11.2-4
    38. backup:
    39. image:
    40. tag: 0.2.0