Reputation: 125
I have around 200-300 yaml files lying around and What I am trying to achieve is to change only the image: option in few of my yaml files, I have a shell script which can get the required yaml files, and I just want to achieve changing the image: key only.
Solution Tried:
Used a tool 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
What this command does is it achieves the desired result of changing the image, but it also appends the changes on the all the parts of deployment file which is for example at the end of every spec in the file:
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
How to achieve the desired result without appending the image on every part of the deployment file?
Upvotes: 1
Views: 3750
Reputation: 26537
This should get you the expected result :
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
Upvotes: 3
Reputation: 11098
Does it have to be yq ?
I would do it with a fairly simple bash
one-liner, using sed
:
for i in {1..3}; do sed -i "s/image.*/image: mysql:latest/" deployment-$i.yaml; done
The above command searches for the string "image"
followed by any other characters till the very end of the line (so it takes the whole string image: "my-fancy-image-name"
) and replaces it with completely new string - in the above example the new string is image: mysql:latest
.
The option -i
or --in-place
is used for editing files in place i.e. the original file is edited and saved with a new content.
The only asssumption is that you have a fixed naming convention for your deployment files i.e. the correct names for the above example are: deployment-1.yaml
, deployment-2.yaml
etc.
If you want to put your image name in double quotes as in your example, you can do it this way:
for i in {1..3}; do sed -i "s/image.*/image: \"gcr.io\/myrepo\/mynginx:1.2.3\"/" deployment-$i.yaml; done
As you can see, certain characters that have a special meaning for sed
command like "
or /
have to be escaped with \
character so they can be used in your replacement string.
Actually there is one more assumption when using the above script, namely that the "image"
string occurs exactly once in your Deployment
. If this is the case, you don't need to worry about adding g
option for global replacement (every occurance of the searched string). The above examples will perform the replacement only on the first occurence of the "image"
string, which should satisfy your requirements. If you have deployments with more than one container e.g. an init container or sidecar, most likely you wouldn't be interested in changing every image
in such deployment to the same single value anyway.
Upvotes: 2