背景:

紧跟Kubernetes中spinnaker的使用一。完成了简单的各种Triggers触发器,还有deploy Mainfest部署一个kubernetes的简单流水线。这里根据实际的环境想更深入一下流水线步骤:参数化的构建,webhook的触发,邮件的发送,jenkins流水线的集成等等 首先明确一下pipeline是由多个stage组成的: image.png 关于默认的stage可以参照官网:https://spinnaker.io/docs/reference/pipeline/stages/。环境主要是kubernetes环境这里注重于: image.png

从一条 pipeline开始

创建application

创建应用 pipeline-test,Permissions权限给运维组读写执行权限(其他组权限看个人需求,这里仅用作演示) image.png

创建流水线pipeline

创建pipeline流水线---Parameters-test1 image.png

Parameters-关于参数化构建

准备前提:

参数化的构建是在Configuration步骤的 image.png 按照常用的惯例将Kubernetes中spinnaker的使用一中的流水线拿来做实验!

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    k8s-app: nginxdemo
  name: nginxdemo
  namespace: dev
spec:
  replicas: 1
  selector:
    matchLabels:
      k8s-app: nginxdemo
  template:
    metadata:
      labels:
        k8s-app: nginxdemo
      name: nginxdemo
      namespace: dev
    spec:
      containers:
        - image: 'harbor.xxxx.com/spinnaker/spinnaker-nginx-demo:1.2.4'
          imagePullPolicy: Always
          name: nginxdemo
          ports:
            - containerPort: 80
              name: web
              protocol: TCP
      imagePullSecrets:
        - name: harbor-layame

定义参数Parameters:

定义image参数,设置默认镜像tag为nginx:1.18.0 image.png

deploy Mainfest

这里的stage name是可以自定义名称的,直接设置stage name为发布应用:image.png Manifest Configuration

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    k8s-app: nginxdemo
  name: nginxdemo
  namespace: dev
spec:
  replicas: 1
  selector:
    matchLabels:
      k8s-app: nginxdemo
  template:
    metadata:
      labels:
        k8s-app: nginxdemo
      name: nginxdemo
      namespace: dev
    spec:
      containers:
        - image: '${ parameters.image }'
          imagePullPolicy: Always
          name: nginxdemo
          ports:
            - containerPort: 80
              name: web
              protocol: TCP

增加webhook stage 保存流水线

image.png Payload 如下:当然了 也可以自己更为细节的去完善!

{
  "msgtype": "text",
  "text": {
    "content": "流水线 ${execution['name']}运行中, 运行用户 ${execution['trigger']['user']}"
  }

集群中操作

确保dev namespace存在(这里将存在的deployments删除,方便对比!)

run流水线并验证部署结果

pipelines界面Start Manual Execution 选择Parameters-test1流水线image使用默认的nginx:1.18.0, Run image.png OK 结果如下:流水线状态SUCCEEDED,微信webhook收到通知,dev namespace下deployments部署成功。 image.png

增加parameters replicas参数

为什么选择relicas副本数做例子呢?为了强调参数化部署非字符串的的数值时要将值tolnt image.png

  replicas: '${#toInt(parameters.replicas)}'

image.png

Manifest Configuration如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    k8s-app: nginxdemo
  name: nginxdemo
  namespace: dev
spec:
  replicas: '${#toInt(parameters.replicas)}'
  selector:
    matchLabels:
      k8s-app: nginxdemo
  template:
    metadata:
      labels:
        k8s-app: nginxdemo
      name: nginxdemo
      namespace: dev
    spec:
      containers:
        - image: '${ parameters.image }'
          imagePullPolicy: Always
          name: nginxdemo
          ports:
            - containerPort: 80
              name: web
              protocol: TCP

running 流水线。这里为了跟上次区分replicas我手动输入了2image.png 验证结果如下:

image.png

流水线回滚

临时回滚(忽略没有找到)

泽阳大佬的课程上面有临时回滚的方式: image.png

但是1.26.6版本貌似排版变了我找了一圈没有找到临时回滚还是直接整自动回滚了!

配置回滚

先说一下流水线中的stage

Configuration 默认的是不计算在内的。发布应用是第一个添加的那他的id为0, 部署通知是第二个stage 他的id是1, Manual Judgment是第三个建立的 他的id是2, Undo Rollout是最后添加的他的id是3。 这个地方貌似有点很绕。stage是从0开始的,按照创建stage的顺序来的。 image.png

创建Manual Judgment stage

人工判断stage 。增加rollback done选项。done约定俗成是完成,rollback是回滚。作为下一步Undo Rollout触发的条件! image.png

Manual Judgment 回滚 stage 选择

强调一下Manual Judgment的id是2。所以这里的stages2 ,一下表达式的含义是流水线stages2中judgmentInput 是rollback。

${ execution['stages'][2].context.judgmentInput == "rollback" }

image.png 运行流水线验证: image.png

image.png 已经验证过了.....具体集群中pod的image就不截图了。这里最需要注意的的表达式的使用!

完善一下线上的流水线:

拿jenkins中spinnaker-nginx-demo pipeline 来搞。先说一下自己要实现的: 嗯gitlab触发jenkins打包镜像(这里重新定义镜像tag用时间)。然后将参数传播给spinnaker触发!

git仓库以及jenkins配置:

参照jenkins Trigger 触发器,当然了这里修改了一点参数化构建增加Dynimic Parameter(如何没有自己百度找插件)参数。定义名字data(可以自己定义名称,个人习惯就用data了)! Default Value Script如下:

return new Date().format('yyyyMMddHHmm')

image.png

jenkins的流水线

就将镜像的tag修改为了data其实

//Docker 镜像仓库信息
registryServer = "harbor.xxxxx.com"
projectName = "${JOB_NAME}".split('-')[0]
repoName = "${JOB_NAME}"
imageName = "${registryServer}/${projectName}/${repoName}"

//pipeline
pipeline{
    agent { node { label "build01"}}


  //设置构建触发器
	triggers {
  		GenericTrigger( causeString: 'Generic Cause', 
						genericVariables: [[defaultValue: '', key: 'branchName', regexpFilter: '', value: '$.ref']], 		
						printContributedVariables: true, 
						printPostContent: true, 
						regexpFilterExpression: '', 
						regexpFilterText: '', 
						silentResponse: true, 
						token: 'spinnaker-nginx-demo')
	}


    stages{
        stage("CheckOut"){
            steps{
                script{
          					srcUrl = "https://gitlab.xxxx.com/zhangpeng/spinnaker-nginx-demo.git"
          					branchName = branchName - "refs/heads/"
          					currentBuild.description = "Trigger by ${branchName}"
                    println("${branchName}")
                    checkout([$class: 'GitSCM', 
                              branches: [[name: "${branchName}"]], 
                              doGenerateSubmoduleConfigurations: false, 
                              extensions: [], 
                              submoduleCfg: [], 
                              userRemoteConfigs: [[credentialsId: 'gitlab-admin-user',
                                                   url: "${srcUrl}"]]])
                }
            }
        }

        stage("Push Image "){
            steps{
                script{
                    withCredentials([usernamePassword(credentialsId: 'harbor-admin-user', passwordVariable: 'password', usernameVariable: 'username')]) {

                        sh """
                           sed -i -- "s/VER/${branchName}/g" app/index.html
                           docker login -u ${username} -p ${password} ${registryServer}
                           docker build -t ${imageName}:${data}  .
                           docker push ${imageName}:${data}
                           docker rmi ${imageName}:${data}

                        """
                    }
                }
            }
        }

        stage("Trigger File"){
            steps {
                script{
                    sh """
                        echo IMAGE=${imageName}:${data} >trigger.properties
                        echo ACTION=DEPLOY >> trigger.properties
                        cat trigger.properties
                    """
                    archiveArtifacts allowEmptyArchive: true, artifacts: 'trigger.properties', followSymlinks: false
                }
            }
        }

    }
}

view 一下trigger.properties image.png

spinnaker中的pipeline设置

创建pipeline

pipline-test应用(applications),中创建spinnaker-nginx-demo pipeline,这里我直接copy了Parameters-test1的流水线 image.png

Configuration中Automated Triggers 配置

jenkins 触发器并添加Property File(jenkins中的制品)trigger.properties(注意别多复制了空格)

image.png 注意:Parameters配置下删除了image参数 但是保留了replicas参数。自动触发默认参数仍是2 ,故后面的副本数量是2。

Deploy (Manifest) Configuration(发布应用 stage修改)

image: "${trigger['properties']['IMAGE']}"

image.png

Undo Rollout (Manifest)回滚应用的配置

image.png

git文件修改文件触发 and jenkins联动

image.png jenkins构建版本79 image.png

登陆spinnakerweb验证

先选择一下done image.png 就是下面这样的跳过了回滚的stage image.png 验证镜像 image.png

rollback回滚验证

再触发一次 选择rollback image.png image.png 这里spinnaker显示jenkins构建80略慢....... image.png

流水线webhook的信息

image.png 当然这里也可以把动作,构建参数个性化自定义一下?这里只是抛砖引玉简单的跑通。后续有好玩的可以更输入分享

后记

  1. 流水线stage在管道工具中的的id,这个地方一定要注意一下
  2. 非字符串参数的toInt
  3. 参数中偷懒复制名词的时候的空格
  4. 还一样比较坑的....我重装了一遍spinnaker练手。设置外部redis的时候配置文件携程了redis.yaml所以一直没有生效....找了好久的问题最后才发现,yaml vs yml切记。
  5. 只学习简单实用的功能,复杂的就不去研究了。深入研究请参考泽阳老师大佬的spinnaker课程。特别鸣谢泽阳大佬。jenkins spinnaker课程都是跟大佬的步伐来的!泽阳大佬的devops云学堂