使用 CODING 持续部署的强大表达式

简介

管道表达式是一种动态的表达式,可以在阶段内引用系统内已存在的任意值。即只要存在此变量,就能够被阶段引用。

目前,管道表达式可以使用在两个地方:

  • 阶段内执行选项条件表达式表单,用来判断当前阶段满足表达式才能执行。
  • 部署的 manifest 内,可以使用表达式。

语法

由美元符号 ${} 组成,即 ${},括号内书写在部署阶段内置的变量名,但不能被嵌套使用。例如这样是不合法的:${ expression1 ${expression2} }

高级用法

管道表达式内允许用户执行 JAVA 代码,可以定义更加复杂的逻辑,出于安全考虑,只有以下 JAVA 类可以被调用:

  • Boolean
  • Byte
  • ChronoUnit
  • Date
  • DayOfWeek
  • Double
  • Instant
  • Integer
  • LocalDate
  • LocalDateTime
  • Long
  • Math
  • Random
  • SimpleDateFormat
  • String
  • URLEncoder
  • UUID

例如,你希望在条件表达式内获取到当前日期,可以这样写:

${new java.text.SimpleDateFormat("MM-dd-yyyy").format(new java.util.Date())}

表达式比较

可以用关系运算符来做比较,例如:

${instance["size"] > 400}
${parameters["runCanary"] == "true"}

特别注意,比较的时候需要两者数据结构一致才可以,例如 ${parameters["runCanary"] 可能为 String ,那么必须将其转换为 Boolean 类型,否则比较不生效。可以用内置的辅助函数来做数据转换:

${#toBoolean(parameters["runCanary"]) == true}。

除此之外,还有以下内置数据转换辅助函数:

  • #toBoolean(String)
  • #toFloat(String)
  • #toInt(String)

其他辅助函数

常用
  • #fromUrl(String)

    • 请求 URL 返回字符串,用来获取网页信息。
  • #jsonFromUrl(String)

    • 请求 URL 的内容,并将 JSON 转换为 map 或 list。
  • #yamlFromUrl(String)

    • 请求 URL 的内容,并将 yaml 转换为 map。
  • #judgment(String)

    • 获取“人工确认”阶段用户选择的值。
  • #stage(String)

    • 通过名称获取 stage ,区分大小写,可以获取到该 stage 的配置信息。
  • #triggerResolvedArtifact(String)

    • 在触发器中查找已解析的制品,如果有多个,只返回一个。例如:

      ${#triggerResolvedArtifact("my-image")["reference"]}

      可能会返回

      gcr.io/spinnaker-marketplace/orca@sha256:b48dbe7d7cb580db8512e4687d31f3710185b08afcf3cb53c0203025f93f9091

  • #triggerResolvedArtifactByType(String)

    • 在执行触发器中按其类型查找制品,如果有多个,只返回 1 个。例如,

      ${#triggerResolvedArtifactByType("docker/image")["reference"]}

      可能会返回

      gcr.io/spinnaker-marketplace/orca@sha256:b48dbe7d7cb580db8512e4687d31f3710185b08afcf3cb53c0203025f93f9091

不常用

  • #alphanumerical(String)

    • 返回传入字符串的字母数字值。也就是说,去除了除 AZ 和 0-9 之外的所有字符的输入字符串。
  • #deployedServerGroups(String)

    • 将部署阶段的名称作为参数,并返回由指定阶段创建的服务器组。
  • #readJson(String)

    • 将 JSON 字符串转换为 Map,然后可以进一步处理。
  • #readYaml(String)

    • 将 YAML 字符串转换为 Map,然后可以对其进行进一步处理。
  • #deployedServerGroups(String)

    • 将部署阶段的名称作为参数,并返回由指定阶段创建的服务器组。
  • #manifestLabelValue(stageName, manifestKind, labelKey)

    • 返回带有类型 labelKey 的 Kubernetes 部署或 ReplicaSet 清单中的键的标签的值,该清单 manifestKind 通过类型 deployManifest 和名称的阶段进行部署 stageName。
  • #propertiesFromUrl(String)

    • 在给定的 URL 上检索 Java 属性文件的内容,并将其转换为映射。
  • #stageByRefId(String)

    • 通过 refId 获取 stage ,区分大小写,可以获取到该 stage 的配置信息。
  • #currentStage(String)

    • 返回当前阶段。
  • #stageExists(String)

    • 检查给定阶段是否存在,可以用名称或者 ID。
  • #pipelineId(String)

    • 返回管道 ID ,例如

      ${#pipelineId("Deploy to prod")}

      可能会返回

      9b2395dc-7a2b-4845-b623-838bd74d059b

  • #toJson(String)

    • 将任意 JSON 对象转换为 JSON 字符串。

获取任意的变量

通过查看已执行完成的部署流程 “Source”,可以看到部署流程使用的所有变量:

这些变量,都可以通过辅助函数来获取。

也可以用过滤符号 .? 来做数据筛选,例如:

${execution["stages"].?[type == "bake"][0]}

将返回管道中第一个 bake 阶段。

数学运算

可以在管道表达式中使用数学运算符号,例如 ${trigger["buildInfo"]["number"] * 2} ,需要注意的是,变量需要使用辅助函数转化为 IntFloat 之后,才能进行数学运算。

常用示例

部署的 manifest 使用条件表达式

例如指定 Pod 部署权重为上一个人工确认阶段输入的值,另外一个 Pod 权重则由数学表达式计算,两者权重合计 100。

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: k8s-flask-pro
  namespace: pro
spec:
  entryPoints:
    - web
  routes:
    - kind: Rule
      match: Host(`pro.coding`)
      services:
        - name: k8s-flask
          namespace: pro
          port: 8080
          weight: '${100 - #toInt(#judgment("生产环境 - 灰度比例"))}'
        - name: k8s-flask-canary
          namespace: pro
          port: 8080
          weight: '${#toInt(#judgment("生产环境 - 灰度比例"))}'

动态跳过阶段

如果希望实现这种动态交叉的阶段,根据人工确认阶段输入的值动态选择部署路径:

可以在 A/B 测试阶段的 条件表达式 表单内输入:

${♯judgment("是否灰度并进行 A/B 测试") == '是,进行 A/B 测试'}

意味着是否灰度并进行 A/B 测试的人工确认阶段选择了是,进行 A/B 测试后,A/B 测试阶段会被执行。如果选择了其他的值,则会进入到 是否进入自动化灰度阶段。

限制 latest 版本制品的部署,防止提单误操作

例如,要限制部署 latest 版本的 docker 镜像部署,可以取当前阶段所需制品的已绑定制品版本是否为 latest:

${trigger["expectedArtifacts"][2]["boundArtifact"]["version"]  != 'latest'}

意味着第三个制品是我们配置的 docker 类型的启动所需制品,注意索引从第 0 个开始。

上一篇CODING CD 主机组部署实践
最近更新
感谢反馈有用
感谢反馈没用

在阅读中是否遇到以下问题?

您希望我们如何改进?