【问题标题】:How to Find and Replace using YQ in Shell script / Yaml?如何在 Shell 脚本/Yaml 中使用 YQ 查找和替换?
【发布时间】:2021-05-07 11:28:59
【问题描述】:

我有大约 200-300 个 yaml 文件,我想要实现的是仅更改图像:我的几个 yaml 文件中的选项,我有一个 shell 脚本可以获取所需的 yaml 文件,我只想实现换图:key only。

已尝试的解决方案:

使用了一个工具yqv4:

for i in ${deployment[@]}
 do
 yq eval '( select(.spec.template.spec.containers[0].image |= "gcr.io/myrepo/mynginx:1.2.3"'  deployment-$i.yaml
done

此命令的作用是实现更改映像的预期结果,但它还将更改附加到部署文件的所有部分,例如在文件中每个规范的末尾:

        apiVersion: apps/v1
        kind: Deployment
        metadata:
          name: portal-1
        spec:
          selector:
            matchLabels:
              component: portal-1
              role: ui
          replicas: 1
          template:
            metadata:
              labels:
                component: reactportal
                role: ui
            spec:
              containers:
                - name: portal
                  image: gcr.io/myrepo/mynginx:4.52 <<< Desired CHange Happens Here >>>
        ---
        
        apiVersion: extensions/v1beta1
        kind: Ingress
        metadata:
      annotations:
        nginx.ingress.kubernetes.io/rewrite-target: /$1
        nginx.ingress.kubernetes.io/enable-cors: "false"
        nginx.ingress.kubernetes.io/cors-allow-origin: "https://example.com"
      name: portal-ingress
    spec:
      rules:
        - host: mydomain.com
          http:
            paths:
              - backend:
                  serviceName: portal-svc
                  servicePort: 80
                path: /(.*)
 template:                                                  <<<< THIS IS ALSO GETTING APPENDED >>>
        spec:
          containers:
            - image: gcr.io/myrepo/mynginx:1.2.3

如何在不将图像附加到部署文件的每个部分的情况下达到预期的效果?

【问题讨论】:

  • 请提供minmal, reproducible example。在这种情况下,您不显示输入 YAML,而且如果每个 YAML 文件都出现问题,您处理多个 YAML 文件似乎也没有关系,因此最好只显示一个精简的 YAML 输入文件问题发生的地方,实际和期望的输出。关于这个问题,关闭两个左括号可能会有所帮助。

标签: bash shell kubernetes yaml yq


【解决方案1】:

必须是yq 吗?

我会用一个相当简单的bash 单线来做到这一点,使用sed

for i in {1..3}; do sed -i "s/image.*/image: mysql:latest/" deployment-$i.yaml; done

上述命令搜索字符串"image",后跟任何其他字符,直到行尾(因此它采用整个字符串image: "my-fancy-image-name")并将其替换为全新的字符串 - 在上面的示例中,新的字符串是image: mysql:latest

-i--in-place 选项用于就地编辑文件,即编辑原始文件并使用新内容保存。

唯一的假设是您的部署文件有一个固定的命名约定,即上述示例的正确名称是:deployment-1.yamldeployment-2.yaml 等。

如果您想像示例中那样将图像名称放在双引号中,您可以这样做:

for i in {1..3}; do sed -i "s/image.*/image: \"gcr.io\/myrepo\/mynginx:1.2.3\"/" deployment-$i.yaml; done

如您所见,对于 sed 命令具有特殊含义的某些字符(例如 "/)必须使用 \ 字符进行转义,以便它们可以在您的替换字符串中使用。

实际上在使用上述脚本时还有一个假设,即"image" 字符串在您的Deployment 中只出现一次。如果是这种情况,您无需担心添加 g 选项以进行全局替换(搜索字符串的每次出现)。上面的示例将仅在"image" 字符串的第一次出现时执行替换,这应该满足您的要求。如果您的部署包含多个容器,例如一个 init 容器或 sidecar,很可能您不会有兴趣将此类部署中的每个 image 更改为相同的单个值。

【讨论】:

  • 谢谢马里奥,这是完成这项工作的最简单方法。我不确定我是否可以把它做得更小
【解决方案2】:

这应该会给您带来预期的结果:

for i in ${deployment[@]}; do
  yq eval '.spec|=select(.selector.matchLabels.component=="portal-1")
                 .template.spec.containers[0].image =
                    "gcr.io/myrepo/mynginx:1.2.3"' deployment-$i.yaml
done

【讨论】:

    猜你喜欢
    • 2012-06-07
    • 2016-03-18
    • 2012-09-13
    • 2022-12-14
    • 2021-12-29
    • 2011-01-04
    • 1970-01-01
    • 2018-02-01
    • 1970-01-01
    相关资源
    最近更新 更多