惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

量子位
云风的 BLOG
云风的 BLOG
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
The Hacker News
The Hacker News
Martin Fowler
Martin Fowler
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
U
Unit 42
F
Full Disclosure
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Recorded Future
Recorded Future
Security Archives - TechRepublic
Security Archives - TechRepublic
阮一峰的网络日志
阮一峰的网络日志
T
Threatpost
P
Privacy International News Feed
GbyAI
GbyAI
Stack Overflow Blog
Stack Overflow Blog
MongoDB | Blog
MongoDB | Blog
I
Intezer
Recent Announcements
Recent Announcements
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
P
Privacy & Cybersecurity Law Blog
A
Arctic Wolf
博客园 - 聂微东
博客园 - 叶小钗
Cisco Talos Blog
Cisco Talos Blog
H
Help Net Security
S
Schneier on Security
Y
Y Combinator Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
T
The Exploit Database - CXSecurity.com
T
Tor Project blog
月光博客
月光博客
NISL@THU
NISL@THU
A
About on SuperTechFans
Spread Privacy
Spread Privacy
Blog — PlanetScale
Blog — PlanetScale
D
DataBreaches.Net
雷峰网
雷峰网
C
CXSECURITY Database RSS Feed - CXSecurity.com
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
博客园 - 【当耐特】
G
Google Developers Blog
W
WeLiveSecurity
P
Palo Alto Networks Blog
The Last Watchdog
The Last Watchdog
K
Kaspersky official blog
博客园 - 司徒正美
L
LINUX DO - 热门话题
小众软件
小众软件

陈少文的网站

巨变与机遇的未来十年 Kubernetes 平台管理软件压力测试方案 使用镜像部署 Hexo 静态页面 终于等到你 - GitHub 镜像仓库服务(ghcr.io) 一起来学 Go --(6)Interface 一起来学 Go --(5)Goroutine 和 Channel 什么是函数式编程 如何在 Kubernetes 集群集成 Kata 柯里化与偏函数 使用 PyGithub 自动创建 Label 软件产品是团队能力的输出 Helm 2 、Helm 3 比较 IoT 变现 Kubernetes 中的 DNS 服务 国内的 Helm 镜像源 Harbor 使用自签证书支持 Https 访问 DevOps 工具链之 Prow 如何使用 kfctl 安装 Kubeflow VS Code 无法下载 Go 插件的工具包 工程师更应具有服务精神 你不知道的 Docker 使用技巧 使用 Docker 运行 Tensorflow 论中国 什么是左移 如何清空 Git 仓库全部历史记录 一禅小和尚 有风吹过厨房 时间的玫瑰 如何在 CentOS 安装 GPU 驱动 开发 Tips(19) 使用 Velero 备份 Kubernetes 集群 Kubernetes Cheat Sheet 开发 Tips(18) 如何构建一个 Java 工程 开发 Tips(17) KubeSpray 安装 Kubernetes 报错 ip in ansible_all_ipv4_addresses 基于 Kubernetes 和 Jenkins 搭建自动化测试系统 在 Kubernetes 上动态创建 Jenkins Slave 使用 Jenkins 进行服务拨测 开发 Tips(16) Kubernetes 签发 Ingress 证书及日常故障运维 Kubernetes 中 Deployment 的基本操作 Kubernetes 中的证书 如何使用 KubeBuilder 开发一个 Operator Kubernetes 1.6.0 安装问题汇总 镜像管理工具 -- Harbor 开发 Tips(15) Docker 如何拉取镜像 开发 Tips(14) 使用 Helm 安装 harbor 开发 Tips(13) 使用 S2I 构建云原生应用 在 Kubernetes 中使用 emptyDir、hostPath、localVolume 开发 Tips(12) 开发 Tips(11) 代码质量分析工具 SonarQube 使用 Kubeadm 安装 Kubernetes 集群 一起来学 Go --(4)常用函数 Kubernetes 中的 Ceph Kubernetes 之 Volumes Kubernetes 之 Labels、Selectors 开发 Tips(10) 开源正在重构商业模式 Kubernetes 之网络 Kubernetes 之 API 使用 Helm 和 Operator 快速部署 Prometheus Kubernetes 复杂有状态应用管理框架 -- Operator Kubernetes 的包管理器 -- Helm 一起来学 Go --(3)Go Modules 如何一步一步地优化博客方案 kubectl 实用指南 Kubernetes 中的基本概念 搭建远程 Kubernetes 开发环境 大公司和小公司的 ToB 思路 开发 Tips(9) Go 入门指南 一起来学 Go --(2)数据与逻辑结构 如何预防 Web 富文本中的 XSS 攻击 django-xss-cleaner 云工作时代 一起来学 Go --(1)背景与特点 SaaS 开发团队的不同阶段 你不知道的 Git 使用技巧 输出既服务 微服务设计 继续奔跑 开发 Tips(8) 从账户安全到二次验证 Django 性能之数据库查询优化 Django 性能之分库分表 敏捷开发之研发流程 打造一致性的团队 开发 Tips(7) Pytest 进阶学习之 Mock PaaS 部署之 buildpack Go 开发配置 领域输出才是 PaaS 的核心竞争力 Pytest 入门学习 开发 Tips(6) 如何使用 Jenkins、Docker、GitLab 搭建 Django 自动化部署流程
在 Tekton 中如何实现审批功能
微信公众号 · 2021-06-24 · via 陈少文的网站

Please enable Javascript to view the contents

1. CICD 平台的基本功能

常见的 CICD 引擎并不适合直接提供给业务方使用。主要原因在于用户学习成本高、缺乏必要的鉴权、维护升级难度大。

我们通常会基于流程引擎,针对业务进行适配提高易用性,针对场景进行封装收敛复杂度,那么一个 CICD 平台需要具备哪些基本的功能呢?

  • 流程编排。基本而又核心的功能,借助开源的编排引擎即可。
  • 流程原子。流程原子组装得到流水线,越丰富的流程原子,越能够满足业务方的需求。
  • 流程控制。主要包括条件执行、暂停、继续、审批等,允许控制流水线的行为。
  • 自动触发。通过 API、Webhook 等方式自动触发流水线,会给使用方带来很大便利。
  • 权限控制。作为一个面向用户的平台,权限控制必不可少。

Tekton 作为云原生下的 CICD 引擎,用来构建面向 Kubernetes 基础设施的 CICD 平台,非常适用。本篇主要想和大家分享的是 Tekton 流程控制,特别是审批的功能。

2. Tekton 中的流程控制

2.1 runAfter

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
- name: test-app
  taskRef:
    name: make-test
  resources:
    inputs:
      - name: workspace
        resource: my-repo
- name: build-app
  taskRef:
    name: kaniko-build
  runAfter:
    - test-app
  resources:
    inputs:
      - name: workspace
        resource: my-repo

通过 runAfter 关键字可以控制任务的执行顺序,上面的示例中 build-app 会在 test-app 执行完成之后执行。使用 runAfter 可以实现对流程的编排。

2.2 conditions

这里首先创建一个 Condition 对象,检查代码仓库中是否存在指定文件。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
apiVersion: tekton.dev/v1alpha1
kind: Condition
metadata:
  name: file-exists
spec:
  params:
    - name: "path"
  resources:
    - name: workspace
      type: git
  check:
    image: alpine
    script: "test -f $(resources.workspace.path)/$(params.path)"

在创建 Pipeline 时,只需要在 Task 中引用这个 Condition,提供必要的参数即可。下面这个例子中,仅当代码仓库中存在 README.md 文件时,my-task 任务才会执行。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: conditional-pipeline
spec:
  resources:
    - name: source-repo
      type: git
  params:
    - name: "path"
      default: "README.md"
  tasks:
    - name: if-condition-then-run
      conditions:
        - conditionRef: "file-exists"
          params:
            - name: "path"
              value: "$(params.path)"
          resources:
            - name: workspace
              resource: source-repo
      taskRef:
        name: my-task

2.3 PipelineRunCancelled

当 PipelineRun Spec 中的状态处于 PipelineRunCancelled 时,Reconciler 会提前取消全部 Task 并更新状态。

参考代码: https://github.com/tektoncd/pipeline/blob/c8dc797cf5a6f11f90cb742d014470a444fcdc60/pkg/reconciler/pipelinerun/pipelinerun.go#L147

  • 查看正在运行的 pipelinerun
1
2
3
4
kubectl get pipelineruns.tekton.dev

NAME                                     SUCCEEDED   REASON               STARTTIME   COMPLETIONTIME
cancel-pipelinerun-r-67qsr               Unknown     Running              51m
  • 修改 pipelineruns 的 status 为 PipelineRunCancelled
1
kubectl patch PipelineRun cancel-pipelinerun-r-67qsr --type=merge -p '{"spec":{"status":"PipelineRunCancelled"}}'
  • 查看取消的 pipelinerun
1
2
3
4
kubectl get pipelineruns.tekton.dev

NAME                                     SUCCEEDED   REASON                 STARTTIME   COMPLETIONTIME
cancel-pipelinerun-r-67qsr               False       PipelineRunCancelled   52m         3s

2.4 PipelineRunPending

除了上面的 PipelineRunCancelled 状态,pipelinerun 还有一个状态,PipelineRunPending。PipelineRunPending 实现的效果是,创建 PipelineRun 但不立即运行

  • 创建一条 PipelineRunPending 状态的流水线
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
---
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
  name: pending-pipelinerun
spec:
  params:
    - name: pl-param-x
      value: "100"
    - name: pl-param-y
      value: "500"
  pipelineRef:
    name: pending-pipeline
  status: "PipelineRunPending"
  • 查看流水线状态
1
2
3
4
kubectl get pipelineruns.tekton.dev

NAME                                     SUCCEEDED   REASON                 STARTTIME   COMPLETIONTIME
pending-pipelinerun                      Unknown     PipelineRunPending

这条流水线没有执行时间,因为它一直处于等待状态。

  • 移除 PipelineRunPending 状态
1
kubectl patch PipelineRun pending-pipelinerun --type=merge -p '{"spec":{"status":""}}'

这条流水线开始执行。

  • 查看流水线状态
1
2
3
4
kubectl get pipelineruns.tekton.dev

NAME                                     SUCCEEDED   REASON                 STARTTIME   COMPLETIONTIME
pending-pipelinerun                      Unknown     Running                4s
  • 无法将正在运行的流水线修改为 PipelineRunPending 状态

在 Tekton v0.24.1 中无法修改状态为 PipelineRunPending,如果运行将可以实现暂停的效果。

1
2
3
4
kubectl get pipelineruns.tekton.dev

NAME                                     SUCCEEDED   REASON               STARTTIME   COMPLETIONTIME
cancel-pipelinerun                       Unknown     Running              9s
1
2
3
kubectl patch PipelineRun cancel-pipelinerun --type=merge -p '{"spec":{"status":"PipelineRunPending"}}'

Error from server (BadRequest): admission webhook "validation.webhook.pipeline.tekton.dev" denied the request: validation failed: invalid value: PipelineRun cannot be Pending after it is started: spec.status

validation 限制了这次修改操作。

3. 如何实现审批功能

上面提到了 Tekton 中的几个流程控制方法,但是社区并没有提供、也不准备提供审批的功能。因此,在对 Tekton 进行二次开发时,需要 CICD 平台自行实现审批和权限的控制。下面是两种实现方案,以供参考:

3.1 方案一,使用 Trigger

如上图,可以将用户的一条流水线拆解为两条流水线,pipeline-1/2 和 pipeline-2/2。两条流水线之间引入一个 trigger。

  1. 当流水线 pipeline-1/2 执行完成时,通知审批者。
  2. 审批者审批通过后,触发 pipeline-2/2 执行。
  3. pipeline-2/2 执行结束,完成整条流水线。

Tekton 社区提供了一个 triggers 组件,用来自动化触发流水线。如下图:

  1. 审批之后,推送一个触发事件 Event
  2. EventController 收到这个事件之后,从 TriggerBinding 提取出事件内的参数 Parameters
  3. TriggerTemplate 利用传递过来的参数 Parameters,创建流水线 pipeline-2/2 。

3.2 方案二,开发一个审批 Task

开发 Task 是 Tekton 的主要扩展方式,同时开发 Task 只需要掌握基本的 Shell 和 Yaml 知识即可。这里提供另外一个思路就是开发一个审批 Task。

如上图,在一条流水线中,插入一个用于审批控制的 Task-Approve。

  1. 在使用审批原子时,需要同步创建一个 ConfigMap,用于保存审批的状态 Status=init
  2. 当流水线执行完成 Task-beforeApprove 任务时,启动 Task-Approve 任务,修改状态 Status=notifying。Task-Approve 任务一直处于等待状态。
  3. 发送通知给 Approver,修改状态 Status=notified
  4. 审批者审批流水线,允许执行,修改状态 Status=success
  5. Task-Approve 检测到 Status=success,立即结束等待状态,完成当前 Task
  6. 流水线继续执行审批后的任务 Task-afterApprove,直至结束

下面是一个示例:

首先创建一个 ConfigMap 用于保存审批状态。

1
2
3
4
5
6
apiVersion: v1
kind: ConfigMap
metadata:
  name: approve-cm
data:
  status: init

编写一个审批的 Task,默认等待 24 小时审批,否则超时。如果将状态修改为 success 则审批通过,如果将状态修改为 refused 则表示拒绝。

 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
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: approve-task
spec:
  workspaces:
    - name: data
  params:
    - name: timeout
      description: The max seconds to approve
      type: string
      default: "86400"
  steps:
    - name: sleep-a-while
      image: bash:latest
      script: |
        #!/usr/bin/env bash

        end=$((SECONDS+$(params.timeout)))
        while [ $SECONDS -lt $end ]; do
          name=$(cat "$(workspaces.data.path)"/status)
          if [ "$name" = "success" ]
          then
            echo "approved!"
            exit 0
          elif [ "$name" = "refused" ]
          then
            echo "refused!"
            exit 1
          fi
          sleep 2
          echo "waiting"
        done
        echo "too long not to approve"
        exit 1        

然后,创建一个测试用例

 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
38
39
40
41
42
43
44
45
46
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: something
  annotations:
    description: |
            A simple task that do something
spec:
  steps:
    - name: do-something
      image: bash:latest
      script: |
        #!/usr/bin/env bash
        uname -a        
---
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: approve-pipeline
spec:
  workspaces:
    - name: workspace
  tasks:
    - name: wait-for-approve
      workspaces:
        - name: data
          workspace: workspace
      taskRef:
        name: approve-task
    - name: do-something
      taskRef:
        name: something
      runAfter:
        - wait-for-approve
---
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
  name: approve-pipelinerun
spec:
  workspaces:
    - name: workspace
      configmap:
        name: approve-cm
  pipelineRef:
    name: approve-pipeline
  • 创建之后查看流水线

日志中会一直输出 waiting。

  • 审批通过
1
kubectl patch ConfigMap approve-cm --type=merge -p '{"data":{"status":"success"}}'
  • 查看流水线状态

4. 总结

在进行 Tekton 二次开发时,审批是很难绕开的功能,但社区并没有提供相关的特性。本文首先介绍了 Tekton 中流程控制方法,然后提供了两种实现审批功能的方案。下面对方案进行简单的对比和总结:

4.1 使用 Trigger 审批

优点

  • 灵活,审批之后的执行,完全由开发者控制,自由度更大。同时也可以使用后台任务替换 Trigger,使用 Tekton Client 创建流水线。
  • 可靠,即使重启也不会影响审批。

缺点

  • 拆分之后可能不止两条流水线。
  • 需要跨流水线传递参数、产物,增加了维护的成本。
  • 架构复杂度增加,引入了新的组件、后台处理逻辑

4.2 开发一个审批 Task

优点

  • 使用简单。一条 Pipeline 只有一个 DAG,容易理解。
  • 更加符合 Tekton 的扩展方式。

缺点

  • 审批 Task 因为节点故障失败时,无法恢复
  • 占用集群资源,审批 Task 常驻集群等待。
  • ConfigMap 状态更新不及时,会有一个延时(默认在分钟级),大约值为 kubelet 的同步周期加上 ConfigMap 在 kubelet 中缓存的 TTL 时间。可以参考文档 如何修改 Kubelet 的启动参数 修改。

5. 参考


微信公众号