gitlab和jenkins结合,基于k8s平台实现ci/cd功能简单测试。

1. Jenkins Pipeline节点

系统管理 —> 节点管理 —> 新建节点
关键配置项:

  • Executor数量:可以简单设置为小于等于节点上CPU核心数的整数值;
  • 远程工作目录:在agent节点上授权Jenkins使用的工作目录,建议使用绝对路径;
  • 标签:节点特性标识;
  • 用法:控制Jenkins如何在该agent上安排构建任务;
  • 启动方式:master识别该agent主机并与其建立双向连接的方式,选定后,需要给定该方式下的具体配置;
  • 可用性:master与agent间的连接保持机制;

image.png
添加连接凭据:

  1. 在agent主机上设置工作目录,授权给jenkins用户,并给jenkins用户设定登录口令:

    1. # usermod -s /bin/bash jenkins
    2. # mkdir -p /appdata/jenkins
    3. # chown -R jenkins:jenkins /appdata/jenkins
    4. # passwd jenkins
  2. 如果是通过公钥来认证连接,添加公钥后,将私钥文件导入到jenkins凭据中:

    1. # su - jenkins
    2. # mkdir .ssh
    3. # echo "PUB_CONTENT" > .ssh/authorized_keys
    4. # chmod 700 .ssh
    5. # chmod 640 .ssh/authorized_keys

    image.png
    pipeline中使用agent指令显式指定执行位置:

    1. pipeline {
    2. agent {
    3. label "node1"
    4. }
    5. stages {
    6. stage('ShowAgent'){
    7. steps{
    8. echo "The node:${env.NODE_NAME}."
    9. echo "The node label: ${env.NODE_LABELS}."
    10. }
    11. }
    12. stage('Checkout'){
    13. steps{
    14. echo 'Fetch codes from SCM'
    15. }
    16. }
    17. stage('Build'){
    18. steps{
    19. echo 'Building..'
    20. }
    21. }
    22. }
    23. post {
    24. always{
    25. mail to: 'test@126.com',
    26. subject: "Status of pipeline ${currentBuild.fullDisplayName}",
    27. body: "${env.BUILD_URL} has result ${currentBuild.result}"
    28. }
    29. }
    30. }

    image.png
    agent可接受多种形式的参数:

  • any: 任何可用节点;
  • node: 用于pipeline顶端时表示不定义默认的agent,这就需要为每个stage单独指定;
  • label { label “
  • node { label “
  • docker: 在指定的容器中允许pipeline或stage代码,该容器动态创建并运行于预配置的可运行容器的node上,或能够匹配到指定label的node上,可用参数有:image、label、args、registryUrl和registryCredentialsId;
  • dockerfile:功能上类似于上面docker参数,但容器镜像通过指定的docker进行构建;该参数要求Jenkinsfile必须从Multibrach Pipeline或Pipeline from SCM中加载,可用参数:filename、dir、label、additionalBuildArgs、args、registryUrl和registryCredentialsId;
  • kubernetes: 于Kubernetes集群上指定的Pod中运行stage或pipeline代码,该参数同样要求Jenkinsfile必须从Multibrach Pipeline或Pipeline from SCM中加载;需要在kubernetes参数重指定Pod模版;

参考:https://www.jenkins.io/doc/book/pipeline/syntax/

2.Jenkins Pipeline与docker集成

在计划运行Docker容器的各Jenkins节点上设置:

  • 安装并设定好docker环境;
  • Jenkins安装Docker插件,pipeline插件自2.5版本以后就内置了docker插件;
  • 将jenkins用户加入到docker组,# usermod -aG docker jenkins

  • 重启jenkins服务

  • 重启jenkins服务

    1. pipeline {
    2. agent none
    3. stages{
    4. stage('Back-end'){
    5. agent{
    6. docker {image 'openjdk:18-slim'}
    7. }
    8. steps{
    9. sh 'java --version'
    10. }
    11. }
    12. stage('Front-end'){
    13. agent{
    14. docker {image 'node:alpine'}
    15. }
    16. steps{
    17. sh 'node --version'
    18. }
    19. }
    20. }
    21. }

    以docker {}为agent时,除了image外,还有其他参数:

  • label:默认,docker容器可运行于任何配置了docker环境的主机上,而label选项可基于标签过滤出一组特定的主机来运行docker agent;

  • args:在创建容器的命令上,传递的自定义参数,例如,使用”-v Contain_Path:Host_Path”来使用存储卷;
  • registryUrl: 特定镜像registry服务的URL;
  • registryCredentialsId: 存储有认证到镜像registry上的Credential的ID;

指定凭证认证到死有registry中来获取镜像:

  1. agent {
  2. image 'dockerhub.test.com/test_zky/spring-boot-helloworld'
  3. label 'docker_host'
  4. registryUrl 'https://dockerhub.test.com'
  5. registryCredentialsId 'dockerhub-user'
  6. }

在jenkins上添加镜像库的凭证:

  1. 添加默认的Registry指向,系统管理 —> 系统配置:

image.png
各配置参数简要说明:

  • Docker Label: pipeline中的agent没有指定label选项时,将以此处指定的label为默认值;
  • Docker registry URL: 使用的Docker Registry服务的地址;
  • Registry Credentials: 认证到目标Registry服务的凭证;
  1. 配置Jenkins全局凭证,添加registry的账号密码:

image.png

3.Jenkins Pipeline与kubernetes集成

Jenkins支持以Pod形式运行Slave节点,实现规模可伸缩的Jenkins Cluster

  • 相应的slave的功能由Pod模版通过镜像、存储卷等配置进行定义
  • 需要在Jenkins上安装kubernetes插件

3.1 配置kubernetes集群

系统管理 —> 节点管理 —> Configure Clouds
image.png
注意: Kubernetes地址、jenkins地址和jenkins通道相关的svc信息都需要在kubernetes上通过相关的svc了解;

3.2 配置Pod模版

image.png
该模式默认会使用jenkins\inbound-agent镜像做为slave Pod的基础容器;添加的容器将作为第二、第三容器使用;

3.3 简单测试Pod pipeline

  1. pipeline {
  2. agent {
  3. kubernetes {
  4. inheritFrom 'jenkins-slave'
  5. }
  6. }
  7. stages{
  8. stage('hello'){
  9. steps{
  10. sh 'java -version'
  11. }
  12. }
  13. }
  14. }

image.png

3.4 在Pod中运行maven构建工具

新增一个pod模版,它可以使用maven的镜像,联合默认的jenkins-slave镜像,运行一个多容器Pod
image.png
image.png
注意:需要提前创建好PVC

  1. pipeline {
  2. agent {
  3. kubernetes {
  4. inheritFrom 'maven-3.8'
  5. }
  6. }
  7. stages {
  8. stage('Build') {
  9. steps {
  10. container('maven') {
  11. sh 'mvn -version'
  12. }
  13. }
  14. }
  15. }
  16. }

image.png

3.5 在Pod中提供docker环境

在容器中构建docker镜像,需要以docker in docker的方式进行
image.pngimage.png

  1. pipeline {
  2. agent {
  3. kubernetes {
  4. inheritFrom 'maven-and-docker'
  5. }
  6. }
  7. stages {
  8. stage('maven version') {
  9. steps {
  10. container('maven') {
  11. sh 'mvn -version'
  12. }
  13. }
  14. }
  15. stage('docker info') {
  16. steps {
  17. container('docker') {
  18. sh 'docker info'
  19. }
  20. }
  21. }
  22. }
  23. }

image.png

4.Jenkins Pipeline与Gitlab集成

4.1 Gitlab通知触发自动构建

spring-boot-helloworld示例:
拉取地址:https://github.com/iKubernetes/spring-boot-helloWorld.git (马哥教育)

Gitlab Webhook指pipeline关联的Gitlab Repository上的代码出现变更时,由Gitlab将相关事件通知给Jenkins,从而触发Jenkins执行构建操作;

  • 避免了pollSCM的频繁轮询依然存在滞后可能性的问题;
  • 依赖于Gitlab插件和Git插件;

配置要求:

  • 前提:Gitlab和Jenkins同在本地网络时,需要以管理员权限设置“外发请求”,启用“允许Webhook和服务队本地网络的请求”;
    • 授予Jenkins访问Gitlab上仓库中特定用户的代码权限;
    • Jenkins基于SSH协议获取代码仓库中的内容,因而需要事先配置Jenkins能基于SSH密钥接入GItlab;
  • Gitlab API访问授权
    • 配置Gitlab API访问认证(Access Token)及操作权限;
    • 配置Jenkins启用/project端点认证,配置它能通过配置的Access Token接入Gitlab API;
  • Jenkins pipeline项目的通知授权
    • 创建pipeline任务,选择使用的“Gitlab Connection”,并选定使用”Build when a change is pushed to Gitlab.”触发器;
    • 而且为构建触发器生成Secret token;
    • 配置Gitlab Repository能通过Webhook,基于该Secret Token触发构建;

具体配置相关文档:https://docs.gitlab.com/ce/integration/jenkins.html

  1. 以Gitlab管理员的身份,设置系统在外发请求中,允许Webhook和服务对本地网络的请求;

image.png

  1. 为Gitlab用户添加SSH公钥,复制公钥文件的内容,贴在Gitlab上的用户账号配置属性中:

image.png

  1. 在Jenkins上通过凭证添加SSH私钥以认证到Gitlab

image.png

  1. 在Gitlab上创建Access Token,User Account —> Setting —> Access Tokens

image.png

  1. 将Gitlab Token添加为jenkins Credential

image.png

  1. 在Jenkins上授权启用/project端点以创建Gitlab连接,系统管理 —> 系统配置:

image.png

  1. 配置Jenkins项目可经由Gitlab上的事件触发
  • 在Jenkins的pipeline和freestyle类型的项目上,选择使用的Gitlab connection;
  • 选中”Build when a change is pushed to Gitlab”,并按需勾选允许的触发事件;
  • 还应该配置如何通知给Gitlab;

    • Freestyle项目可以选择通过Post-build Actions指定;
    • Pipeline项目只能通过pipeline代码指定;

      1. pipeline {
      2. agent any
      3. stages {
      4. stage('gitlab') {
      5. steps {
      6. echo 'Notify Gitlab'
      7. updateGitlabCommitStatus name: 'build',state:'pending'
      8. updateGitlabCommitStatus name: 'build',state:'success'
      9. }
      10. }
      11. }
      12. }

      image.png

  • 点击上图的“高级”按钮,在Jenkins项目上生成Secret Token,该Token将被Gitlab用作触发时的认证信息;

image.png

  • 在Gitlab上对应代码仓库的配置菜单上,Setting —> Webhooks
    • 创建一个Webhook,指向前面配置的Jenkins项目及其相应的Secret Token
    • Webhook定义完成后,可手动测试触发机制;选择支持的某类触发事件中的一种,即可触发一次Pipeline的构建操作;
    • 整个出发及构建链路连通后,即可于Jenkins上的相关项目的详情中看到,被Gitlab出发的构建都会标记为”Started by Gitlab by xxx”

image.pngimage.png image.png

  • 测试自动触发,向Gitlab上的代码仓库推送代码变更测试即可

    1. pipeline {
    2. environment {
    3. appName = "dockerhub.test.com/test_zky/spring-boot-helloworld"
    4. appVersion = "0.9.4"
    5. }
    6. agent {
    7. kubernetes {
    8. inheritFrom "maven-and-docker"
    9. }
    10. }
    11. stages {
    12. stage('Source'){
    13. steps {
    14. git branch: 'develop', credentialsId: 'gitlab-ssh-private-key', url:'ssh://git@gitlab.gitlab.svc.cluster.local/zky/spring-boot-helloworld.git'
    15. }
    16. }
    17. stage('Build') {
    18. steps {
    19. container('maven') {
    20. sh 'mvn clean test package'
    21. }
    22. }
    23. }
    24. stage('Building app image') {
    25. steps {
    26. container('docker') {
    27. script {
    28. dockerimage = docker.build appName + ':' + appVersion
    29. }
    30. }
    31. }
    32. }
    33. }
    34. }

    4.2 自动推送Docker镜像入库

    将拥有镜像仓库“写”权限的认证信息保存位Jenkins的凭据,以确保能够在pipeline中推送镜像至仓库中
    image.png

    1. pipeline {
    2. environment {
    3. appName = "dockerhub.test.com/test_zky/spring-boot-helloworld"
    4. appVersion = "0.9.4"
    5. registry = "https://dockerhub.test.com"
    6. registryCredential = "dockerhub-user"
    7. dockerimage = ""
    8. }
    9. agent {
    10. kubernetes {
    11. inheritFrom "maven-and-docker"
    12. }
    13. }
    14. stages {
    15. stage('Build') {
    16. steps {
    17. container('maven') {
    18. sh 'mvn clean test package'
    19. }
    20. }
    21. }
    22. stage('Building app image') {
    23. steps {
    24. container('docker') {
    25. script {
    26. dockerimage = docker.build appName + ':' + appVersion
    27. }
    28. }
    29. }
    30. }
    31. stage('Push app image') {
    32. steps {
    33. container('docker') {
    34. script {
    35. docker.withRegistry(registry,registryCredential) {
    36. dockerimage.push()
    37. }
    38. }
    39. }
    40. }
    41. }
    42. }
    43. }

    4.3 Jenkinsfile入库

  • 将前面示例中的pipeline代码保存于仓库根目录中的Jenkinsfile文件中,即可由Jenkins自行检出并加载;

  • 轻量级检出,可让Jenkins仅检出Jenkinsfile文件,而非整个仓库;

image.png

5.Jenkins CD流水线

  1. 以Jenkins为CD工具:
    1. 原则上:代码仓库与配置仓库分离,CI Server与CD Server分离;
    2. 折衷方案:代码仓库与配置仓库分离,但仍使用同一个Jenkins实例:
      1. 代码仓库:spring-boot-helloworld
      2. 配置仓库:spring-boot-helloworld-deployment
  2. 使用kubectl直接调用清单进行部署,需要事先配置可运行kubectl命令的Pod模版

image.png

  1. 安装 kubernetes CLI 插件
  2. 将具有部署目标资源权限的账户及认证信息添加微Jenkins上的认证凭据
    1. 将”kubectl config view —raw”的结果复制后,保存于本地桌面上的文件;
    2. 修改其Cluster的地址为集群内部的可用地址https://kubernetes.default.svc.cluster.local:443;
    3. 在Jenkins上添加类型为”Secret File”类型的凭据,并加在前面生成的文件;

image.png

  1. 使用如下Pipeline代码

    1. 从指定的仓库获取代码
    2. 而后借助于kubectl基于相应的kubeconfig项目标集群执行应用部署或更新

      1. pipeline {
      2. agent {
      3. kubernetes {
      4. label 'kubectl'
      5. }
      6. }
      7. stages {
      8. stage('Source'){
      9. steps {
      10. git branch: 'master', credentialsId: 'gitlab-ssh-private-key', url:'ssh://git@gitlab.gitlab.svc.cluster.local/zky/spring-boot-helloworld-deployment.git'
      11. }
      12. }
      13. stage('Deploy'){
      14. steps{
      15. container('kubectl'){
      16. withKubeConfig([credentialsId: 'k8s-cluster-admin-kubeconfig']){
      17. sh 'kubectl apply -f deploy/'
      18. }
      19. }
      20. }
      21. }
      22. }
      23. }

      参考:马哥教育 gitops课程