如何在 Shell 脚本/Yaml 中使用 YQ 查找和替换?

How to Find and Replace using YQ in Shell script / Yaml?

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

尝试的解决方案:

使用工具 yq v4:

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: /
        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

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

一定要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 更改为相同的单个值都不感兴趣。

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

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