데보션앱 소개페이지 바로가기
로그인 선택

신고하기

CLOSE
신고사유 (대표 사유 1개)
상세내용 (선택)
0/200
  • 신고한 게시글은 더 이상 보이지 않습니다.
  • 이용약관과 운영정책에 따라 신고사유에 해당하는지 검토 후 조치됩니다.
  • 허위 신고인 경우, 신고자의 서비스 이용이 제한될 수 있으니 유의하시어 신중하게 신고해 주세요.
(이 회원이 작성한 모든 댓글과 커뮤니티 게시물이 보이지 않고, 알림도 오지 않습니다.)

미리보기

커뮤니티

      1,234

      badge 23.06.15

      글 등록

      카테고리를 선택해주세요.

      DEVOTEE를 활성화 시키면
      지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.

      버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.

      임시저장함에 저장되었습니다. 저장일시 : 2022.5.17 14:29:08

      임시저장함

      제목을 선택하시면 이어서 작성이 가능하며,
      최대 20건까지 저장합니다.
      컨텐츠 유형, 제목, 저장일시, 삭제로 이뤄진 임시저장 목록
      컨텐츠 유형 제목 저장일 삭제

      데보션 블로그 게재 요청

      CLOSE
      • *
      • *

      본인인증

      효율적인 데보션 서비스 이용 및
      고객님의 소중한 개인정보보호를 위해
      본인인증을 진행해주세요. 본인인증 미 진행 시 로그인이 제한됩니다.
      본인인증 실패

      본인인증 로그인에 실패하였습니다.
      회원이 아니시거나 본인인증 등록이
      완료되지 않은 사용자입니다.

      회원정보 연결

      yaml 파일을 효율적으로 처리하는 방법

      sungil 23.08.30
      5,879 14 0
      DEVOTEE 요약
      kubernetes를 사용하면서 yaml 파일을 다루는데 어려움이 있었지만, jq와 yq라는 유틸리티를 사용하면 쉽게 값을 변경하고 가져올 수 있다고 생각한다. jq는 json 데이터를 다룰 때 사용되고, yq는 yaml 데이터를 다루는데 유용하다. 이러한 유틸리티를 사용하면 복잡한 배열을 포함한 yaml 파일도 쉽게 다룰 수 있다.

      kubernetes를 사용하다보면 수많은 yaml 파일들을 사용하고 때로는 만들기도 한다. kubernetes는 내부의 자원들을 yaml로 기술하기 때문이다.

      kubernetes 를 활용한 컨테이너 플랫폼을 만들고 있기에 이에 대해 접하는 경우가 많고 또한 자동화를 위해서는 상황에 맞는 자원을 yaml 로 작성하고 수정하고 보관하는 일들을 많이 수행하고 있다.

      환경에 맞는 값을 지정하기 위해서는 yaml 구조에서 정확한 위치의 값을 변경하는 것은 필수적인 일이다.

      이를 위해 이전에는 python의 yaml parser를 활용하는 코드를 부분적으로 배치해서 사용했었다.

      bash 쉘스크립트를 활용하는 것이 효율적인 코드에서 몇몇 부분의 값을 치환하기 위해 값을 변경하기위해 python 코드를 추가하는 것은

      전체적으로 많은 코드를 생성하고 이에 대한 관리나 재활용 측면에서 불리한 측면이 있었다.

      이에따라 bash에서 해결할 수 있는 방법을 고민하였고 알게된 방법을 이글을 통해 공유하고자 한다.


      jq?

      먼저 jq에 대해 알아보면, bash에서 rest api를 호출하는 경우 반환값이 json 형태로 얻어지는 경우가 많은데 전체 반환값에서 필요한 값을 파싱하기 위해 나온 명령이다.

      grep 명령이나 awk 스크립트를 사용하여 해결할 수 있으나 매우 복잡하다. 이때 jq을 활용하면 json 데이터에서 ‘.’ 구분자를 사용하여 구조안에서 원하는 값을 간편하게 다룰수 있게 해준다.

      jq를 직접 활용하지 않더라도 해당 기능을 플러그인 형태로 제공하는 경우가 많은데 kubectl의 경우 jsonpath를 통해 원하는 값을 가져오는 것이 그것이다.

      아래 예는 kubectl의 jsonpath를 사용하여 서비스에서 생성된 로드밸런서의 주소를 가져오는 것이다.

      siim@adm:~$ kubectl get svc -n nexus dev-nexus-repository-manager -o yaml
      apiVersion: v1
      kind: Service
      metadata:
        annotations:
          meta.helm.sh/release-name: dev-nexus-repository-manager
          meta.helm.sh/release-namespace: nexus
        creationTimestamp: "2023-01-09T07:51:58Z"
        finalizers:
        - service.kubernetes.io/load-balancer-cleanup
        labels:
          app.kubernetes.io/instance: dev-nexus-repository-manager
          app.kubernetes.io/managed-by: Helm
          app.kubernetes.io/name: nexus-repository-manager
          app.kubernetes.io/version: 3.45.0
          helm.sh/chart: nexus-repository-manager-45.0.0
        name: dev-nexus-repository-manager
        namespace: nexus
        resourceVersion: "16122549"
        uid: 650ce058-f73a-4ed2-87e1-b8719d775306
      spec:
        allocateLoadBalancerNodePorts: true
        clusterIP: 10.106.112.16
        clusterIPs:
        - 10.106.112.16
        externalTrafficPolicy: Cluster
        internalTrafficPolicy: Cluster
        ipFamilies:
        - IPv4
        ipFamilyPolicy: SingleStack
        ports:
        - name: nexus-ui
          nodePort: 32270
          port: 8081
          protocol: TCP
          targetPort: 8081
        selector:
          app.kubernetes.io/instance: dev-nexus-repository-manager
          app.kubernetes.io/name: nexus-repository-manager
        sessionAffinity: None
        type: LoadBalancer
      status:
        loadBalancer:
          ingress:
          - hostname: a650ce058f73a4ed287e1b8719d77530-11111111111.ap-northeast-2.elb.amazonaws.com
      siim@adm:~$ kubectl get svc -n nexus dev-nexus-repository-manager -o jsonpath='{.status.loadBalancer.ingress[0].hostname}'
      a650ce058f73a4ed287e1b8719d77530-11111111111.ap-northeast-2.elb.amazonaws.com


      yq?

      사람이 판독할 수 있고 기계가 활용할 수 있는 포맷으로 json이 먼저 보편화 되었고 몇몇 활용 사례도 있었으나 kubernetes가 확산되면서 yaml 포맷도 활용되기 시작하였다.

      이에따라 jq와 동일한 기능을 yaml에 대해서도 수행하는 yq라는 유틸리티도 등장하였다.

      kubernetes를 활용하는 TACO를 개발하던 초기에는 사용할 수 없었던 수준의 유틸리티가 현재는 jq에 기능을 거의 따라잡는 수준까지 발전하였다.

      (현재까지도 mikefarah 라는 개인계정에서 개발 및 배포가 진행중 이다.)


      설치하기

      맥의 경우 brew등 패키지 관리자를 통해 설치할 수 도 있으나 일반적으로는 git에서 배포본을 받아서 사용한다.

      siim@adm:~$ wget https://github.com/mikefarah/yq/releases/download/${VERSION}/${BINARY}.tar.gz -O - |\
        tar xz && mv ${BINARY} /usr/bin/yq
      siim@adm:~$ yq
      Usage:
        yq [flags]
        yq [command]
      
      Examples:
      
      # yq defaults to 'eval' command if no command is specified. See "yq eval --help" for more examples.
      
      # read the "stuff" node from "myfile.yml"
      yq '.stuff' < myfile.yml
      
      # update myfile.yml in place
      yq -i '.stuff = "foo"' myfile.yml
      
      # print contents of sample.json as idiomatic YAML
      yq -P sample.json
      
      Available Commands:
        completion       Generate the autocompletion script for the specified shell
        eval             (default) Apply the expression to each document in each yaml file in sequence
        eval-all         Loads _all_ yaml documents of _all_ yaml files and runs expression once
        help             Help about any command
        shell-completion Generate completion script
      
      Flags:
        -C, --colors                        force print with colors
        -e, --exit-status                   set exit status if there are no matches or null or false is returned
            --expression string             forcibly set the expression argument. Useful when yq argument detection thinks your expression is a file.
            --from-file string              Load expression from specified file.
        -f, --front-matter string           (extract|process) first input as yaml front-matter. Extract will pull out the yaml content, process will run the expression against the yaml content, leaving the remaining data intact
            --header-preprocess             Slurp any header comments and separators before processing expression. (default true)
        -h, --help                          help for yq
        -I, --indent int                    sets indent level for output (default 2)
        -i, --inplace                       update the file inplace of first file given.
        -p, --input-format string           [auto|a|yaml|y|props|p|xml|x|tsv|t|csv|c|toml] parse format for input. Note that json is a subset of yaml. (default "auto")
        -M, --no-colors                     force print with no colors
        -N, --no-doc                        Don't print document separators (---)
        -0, --nul-output                    Use NUL char to separate values. If unwrap scalar is also set, fail if unwrapped scalar contains NUL char.
        -n, --null-input                    Don't read input, simply evaluate the expression given. Useful for creating docs from scratch.
        -o, --output-format string          [auto|a|yaml|y|json|j|props|p|xml|x|tsv|t|csv|c] output format type. (default "auto")
        -P, --prettyPrint                   pretty print, shorthand for '... style = ""'
        -s, --split-exp string              print each result (or doc) into a file named (exp). [exp] argument must return a string. You can use $index in the expression as the result counter.
            --split-exp-file string         Use a file to specify the split-exp expression.
        -r, --unwrapScalar                  unwrap scalar, print the value with no quotes, colors or comments. Defaults to true for yaml (default true)
        -v, --verbose                       verbose mode
        -V, --version                       Print version information and quit
            --xml-attribute-prefix string   prefix for xml attributes (default "+@")
            --xml-content-name string       name for xml content (if no attribute name is present). (default "+content")
            --xml-directive-name string     name for xml directives (e.g. <!DOCTYPE thing cat>) (default "+directive")
            --xml-keep-namespace            enables keeping namespace after parsing attributes (default true)
            --xml-proc-inst-prefix string   prefix for xml processing instructions (e.g. <?xml version="1"?>) (default "+p_")
            --xml-raw-token                 enables using RawToken method instead Token. Commonly disables namespace translations. See https://pkg.go.dev/encoding/xml#Decoder.RawToken for details. (default true)
            --xml-skip-directives           skip over directives (e.g. <!DOCTYPE thing cat>)
            --xml-skip-proc-inst            skip over process instructions (e.g. <?xml version="1"?>)
            --xml-strict-mode               enables strict parsing of XML. See https://pkg.go.dev/encoding/xml for more details.
      
      Use "yq [command] --help" for more information about a command.


      질의예시

      ‘.’을 활용하여 구조 내부 특정값을 가져올수 있으며 배열이 존재하는 경우[]를 통해 순번을 지정할 수 있다.

      yq '.a.b[0].c' file.yaml

      ‘-i’ 옵션을 사용하면 해당위치의 값을 변경할 수 있다.

      yq -i '.a.b[0].c = "cool"' file.yaml

      strenv 명령을 사용하면 환경변수를 사용할 수 있다.

      NAME=mike 
      yq -i '.a.b[0].c = strenv(NAME)' file.yaml

      특정 파일들을 병합할 수 있다. 다음의 경우 해당 디렉토리의 yaml 파일들을 파일명을 기준으로 다음 depth로 넣은 하나의 yaml 결과물을 만든다.

      yq ea '. as $item ireduce ({}; . * $item )' path/to/*.yml

      그 외 다양한 적용 아이디어들이 공유되고 있으며 이를 기반으로 신규기능이 추가되기도 한다.

      mikefarah/yq Show And Tell · Discussions


      좀 더 복잡한 배열을 다루는 방법

      TACO에서는 DECAPOD라는 kubernetes 자원들을 효율적으로 관리하고 배포하는 체계를 사용하고 있으며 위 간단한 예시보다는 훨씬 복잡한 구조의 yaml 파일들을 다룬다.

      다음 링크의 파일을 확인하자.

      https://github.com/openinfradev/decapod-site/blob/main/aws-msa-reference/lma/site-values.yaml


      .charts 하단의 값들은 배열로 구성되어 있으며 각각이 필요한 구조 및 내용을 갖고 있다.

      TACO에서는 이러한 값들을 동적으로 변경하면서 플랫폼을 배포하는데 배열들을 다루는 것이 쉽지않아 python 코드들을 삽입하는 실정이었다.

      주문형 서비스(On-demand service)를 구성하는 시점에서 이를 해소하는 방법으로 .global에 변수를 추가해 이를 변경하는 방식을 사용했는데

      이에따라 .global에 정의하는 내역들이 많아졌고 내부에서 이 값들을 참조하는 또다른 복잡한 구조가 만들어 졌다.

      이를 해소하기위해 다시한번 yq를 들여다 봤고 최근 버전의 yq에서는 이를 해결할 수 있는 방법을 제시하고 있었다.


      배열내부의 특정값을 제거하고 싶은 경우 필요한 조건(키 name의 값이 thanos-config)을 갖는 배열의 entry에 특정값(override.objectStorage)을 지정하여 제거(del)한다.

      yq -i e "del(.charts[] | select(.name == \"thanos-config\").override.objectStorage)" /lma/site-values.yaml

      배열내부에 값을 교체하고 싶은 경우 필요한 조건(키 name의 값이 thanos-config)을 갖는 배열의 entry에 특정값(override.objectStorage.rawConfig.signature_version2)을 지정하여

      값을 변경한 것을 맵핑하여(map) 배열을 수정한다.

      yq -i e ".charts |= map(select(.name == \"thanos-config\").override.objectStorage.rawConfig.signature_version2=false)" /lma/site-values.yaml

      더 자세한 내용은 공식 메뉴얼을 통해 확인해 보자.

      Tips, Tricks, Troubleshooting


      마치며

      서두에서 이야기했던 것처럼 yq를 활용하면서 기존 python 사용했던 부분을 쉽게 대체할 수 있다.

      이에따라 부분적으로 python이 포함된 자동화 코드들에서 yaml 처리를 위한 python 부분을 걷어낼수 있었으며 결과적으로 간결하고 읽기쉬운 코드로 변경할 수 있었다.

      yaml 처리를 고민하고 있는 분들에게 도움이 되길 바란다.

      https://heavenly-part-d73.notion.site/yaml-0902bac1872e4f2fbe08b29e9d502610

      댓글 0

      DEVOTEE를 활성화 시키면
      지금 작성한 댓글에 AI가 댓글을 달아줍니다.

      sungil 님의 최신 블로그

      더보기
      동영상 기고하기