설명은 필요없고 결론만 알고 싶은 분들을 위한
$ sed "$(grep -n 'image:' nginx.yaml | grep -Eo '^[^:]+')s/nginx:1.0/nginx:2.0/g" nginx.yaml
본문의 기능이 필요한 상황 예시
위 이미지는 개발자가 코드를 커밋한 후 자동으로 k8s cluster에 배포되기 까지의 과정을 파이프라인으로 도식화한 이미지입니다.
개발자가 운영 중인 서비스에 새로운 기능을 추가하거나 버그를 수정 했다고 가정해봅시다. 그렇게 될 경우 GitOpsRepo의 있는 컨테이너 이미지의 버전 또한 바꿔주어야 합니다.
그렇게 될 경우 젠킨스에서 GitOps Repo에 push를 할 때 새롭게 만든 컨테이너 이미지의 버전으로 수정해줘야 합니다. 그래야 argoCD에서 git Hook을 인지하고 새롭게 만든 컨테이너 이미지를 기반으로 파드를 재배포해줄테니까요.
이럴 때 "파일에서 문자열 검색 한 후 그 문자열의 라인 넘버 가져오기" 가 필요로 됩니다.
# yaml
images: nginx:1.0
# yaml
images: nginx:2.0
#으로 수정해줘야 합니다
처음에는 이렇게 했었습니다. sed 명령어로 "image:"라는 단어를 통째로 찾은 후 그 라인을 아예 새롭게 바꿔주었죠.
즉, 라인 자체를 바꿔줍니다. 뭔가 좋아보이진 않습니다.. 그리고 실제론 버전과 저장소 이름, 컨테이너 이미지까지 동적으로 지정해줘야 하기 때문에 훨씬 코드가 지저분해집니다.
$ sed -i "/image:/c\\ image: nginx:2.0" nginx.yaml
# 실제로 CICD에서 사용한 명령어
$ sed -i "/image:/c\\ image: $(echo $DOCKER_USER_ID)/$(echo $image_name):$(echo $BUILD_NUMBER)" deployment.yaml
그래서 다른 방법을 모색해봤습니다. sed 라는 명령어는 행번호를 주게되면 그 행번호에서만 찾게되는 기능도 있습니다. 따라서 행번호를 주어 그 행번호에서만 문자열 치환이 가능하도록 해보겠습니다.
sed -i "행번호s/기존문자열/새문자열/" 파일명
실습은 아래 nginx.yaml로 진행하겠습니다.
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: nginx
name: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: nginx
spec:
containers:
- image: nginx:1.0 # 여기를 바꾸고 싶습니다.
name: nginx
resources: {}
status: {}
우선 "image:"이라는 단어를 찾아 그 단어가 포함되는 라인의 넘버를 출력해주는 명령어입니다.
$ grep -n "image:" nginx.yaml
하지만 원하던 것은 "21: - image: nginx:1.0"이 아니고 "21" 하나기 때문에 아래와 같은 명령어를 입력해줍니다.
$ grep -n 'image:' nginx.yaml | grep -Eo '^[^:]+'
21만 출력됩니다. 원하던 값을 찾았습니다!!
$ sed -i "행번호s/기존문자열/새문자열/" 파일명
그럼 위 명령어를 활용해서 아래와 같이 명령어를 수정해주었습니다.
$ sed "$(grep -n 'image:' nginx.yaml | grep -Eo '^[^:]+')s/nginx:1.0/nginx:2.0/g" nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: nginx
name: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: nginx
spec:
containers:
- image: nginx:2.0 #잘 바뀌었습니다.
name: nginx
resources: {}
status: {}
사실 위 명령어도 깨끗해보이지 않지만 확실히 맨처음 짠 코드보다는 훨씬 안정성이 있는 느낌입니다. 처음 명령어는 "image:"라는 명령어를 전역에서 찾고, 찾은 단어의 라인을 지워버리고 다시 생성하는 거니깐 띄어쓰기가 중요한 yaml에서는 치환되는 과정에서 에러가 발생할 수도 있습니다.
즉, 딱 버전만 찾아 바꾸게 되니깐 훨씬 안정성이 있어보입니다!!