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

신고하기

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

미리보기

커뮤니티

      1,234

      badge 23.06.15

      글 등록

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

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

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

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

      임시저장함

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

      데보션 블로그 게재 요청

      CLOSE
      • *
      • *

      본인인증

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

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

      회원정보 연결

      실제 서비스에 Canary 배포 적용 (feat ArgoCD, Istio, Kustomize)

      주재현 23.05.09
      4,198 13 1

      들어가며

      MSA 서비스를 운영하면 아무래도 신규 개발 및 배포가 자주 발생하게 됩니다.

      이때 전자문서, 국민비서등 정부/행정안전부의 서비스와 연동이 많은 우리 서비스 특성상 개발/스테이징에서 QA가 불가능한 경우가 많다.

      정부의 개인보호 정책 때문에 개발/스테이징에서는 테스트 불가한 제약이 많기 때문이다.

      그래서 운영환경에서 일부 테스트가 진행되어야 하는데, 동시에 배포되는 Web 서비스의 특성상 운영 테스트가 힘든 경우가 많았다.

      이를 해결하기 위해 특정 IP(테스터그룹)만 접근 가능한 Canary 배포를 적용하였고 공유하고자 합니다.

      기본적으로 배포 전략은 지식이 있다는 가정으로 글을 작성하였습니다. 필요하신 분은 아래 블로그 참고하세요

      https://reference-m1.tistory.com/211

      이글은 Istio를 기반으로 구현하였기 때문에, 관련글은 미리 참고하시면 좋습니다.

      Kustomize에 대한 기본 개념이 있어야 합니다. 아래 이전글 참고

      https://devocean.sk.com/search/techBoardDetail.do?ID=163544


      Canary 배포 구현 목표

      1. 최대한 자동으로 진행되고, Manual 작업은 없어야 한다.

      2. 특정 IP만 Canary 배포 서비스(Pod)에 접근할 수 있어야 한다.

      위 두개를 목표로 수립하고 진행하였습니다.

      사실 Canary배포의 전략은 많이 있습니다. 가장 흔히 사용되는건 Traffic에 weight를 주어서 신규 배포 서버로 조금씩 유입시키는 전략입니다.

      하지만 저희 서비스 특성상 신규 기능을 먼저 테스트 그룹이 QA를 진행하고, 나머지 서버에 Rolling 업데이트 하는 방법을 이번에 설명 드릴 예정입니다.


      Test를 위한 환경 준비

      image.png

      시나리오는 위 그림과 같습니다. 20.1.1.1 이라는 IP를 가진 그룹만 Version2(Green Pod)로 network traffic이 흘러가고, 기존 고객들을 Version1(Blue Pod)로 가는 것입니다.

      즉 Istio gateway에서 IP를 filtering 하여 pod version을 보고 routing 하는 방식입니다.


      1. Pod 2개 설치

      아래와 같이 httpbin(기존에 서비스 되고 있는 version1 Blue Pod를 가정)과 httpbin-canary(신규 서비스 진행 예정인 version2 Green Pod를 가정)

      ##################################################################################################
      # httpbin v1 Service & Deployment
      ##################################################################################################
      apiVersion: v1
      kind: ServiceAccount
      metadata:
        name: httpbin
      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: httpbin
        labels:
          app: httpbin
          service: httpbin
      spec:
        ports:
        - name: http
          port: 8000
          targetPort: 80
        selector:
          app: httpbin
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: httpbin-main
        labels:
          app: httpbin
          version: v1
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: httpbin
            version: v1
        template:
          metadata:
            labels:
              app: httpbin
              version: v1
          spec:
            serviceAccountName: httpbin
            containers:
            - image: docker.io/kong/httpbin
              imagePullPolicy: IfNotPresent
              name: httpbin-v1
              ports:
              - containerPort: 80
      ---
      ##################################################################################################
      # httpbin canary Deployment
      ##################################################################################################
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: httpbin-canary
        labels:
          app: httpbin
          version: canary-tag-name
      spec:
        replicas: 1
        selector: # label selector for the Pods
          matchLabels:
            app: httpbin
            version: canary-tag-name
        template: # Pod template
          metadata:
            labels:
              app: httpbin
              version: canary-tag-name
          spec:
            serviceAccountName: httpbin
            containers:
            - image: docker.io/kong/httpbin:0.1.0
              imagePullPolicy: IfNotPresent
              name: httpbin-canary
              ports:
              - containerPort: 80
      ---


      2. Virtual Service 생성 및 DestinationRule 생성

      일단 Istio에서 지원하는 Virtual Service(이하 VS) 생성하겠습니다. 이름은 test-vs 입니다. gateway는 기존 저희 것을 그대로 사용하였습니다.

      그리고 VS에 match 를 이용하여 route rule 을 생성하였습니다.

      아래 sample은 https://domain.com/httpbin 으로 들어오는 traffic 중 X-Forwarded-For 에 특정 IP가 포함되어 있으면 특정 pod로 routing 되게 하였습니다.

      참고로 IP를 filtering 하는 규칙에 CIDR을 지원하지 않습니다.

      그래서 특정 대역폭, 예를 들어 203.236.0.0/16 을 사용하길 원하는 아래와 같이 prefix: "203.236." 으로 사용하시면 됩니다.

      istio에서 사용 가능한 규칙은 공식 문서 https://istio.io/latest/docs/reference/config/networking/virtual-service/#HTTPMatchRequest 를 참고하세요.

      header를 포함하여 다양한 방법 적용이 가능합니다.

      Pod로 유입되는 Request의 Header 정보는 제 이전글을 참고하시면 됩니다.

      ##################################################################################################
      # MWP TEST virtual service
      ##################################################################################################
      apiVersion: networking.istio.io/v1beta1
      kind: VirtualService
      metadata:
        name: test-vs
      spec:
        hosts:
          - "*"
        gateways:
          - mwp-gateway
        http:
        - match:
          - uri:
              prefix: /httpbin/
            headers:
              X-Forwarded-For:
                prefix: "203.236."
          - uri:
              prefix: /httpbin/
            headers:
              X-Forwarded-For:
                prefix: "20.1.1.1"
          rewrite:
            uri: /
          route:
          - destination:
              host: httpbin
              port:
                number: 8000
              subset: canary
        - match:
          - uri:
              prefix: /httpbin/
          - uri:
              prefix: /httpbin
          rewrite:
            uri: /
          route:
          - destination:
              host: httpbin
              port:
                number: 8000
              subset: main
      ---

      아래와 같이 DestinationRule을 설정합니다. 기본적으로 VS에서 route.destination.host에서 지정한 pod로 route 되는데,

      현재 deployment에서 같은 host name인 httpbin 을 사용하기 때문에, version 구분을 위해서 아래와 같이 subsets를 지정하여 관리합니다.


      즉 VS에서 route.destination.subset이 존재하면, 아래 version으로 Routing 됩니다.

      ##################################################################################################
      # httpbin DestinationRule
      ##################################################################################################
      apiVersion: networking.istio.io/v1beta1
      kind: DestinationRule
      metadata:
        name: httpbin
      spec:
        host: httpbin
        subsets:
          - name: main
            labels:
              version: v1
          - name: baseline
            labels:
              version: v1
          - name: canary
            labels:
              version: canary-tag-name
      ---


      3. 최종 형상

      image.png

      만약 모든 배포가 제대로 되었다면, 위 그림과 같이 test-vs(Virtual Service) 아래에 httpbin(Service)가 있고, 그 아래 httpbin(기존 code), httpbin-canary(신규 code)가 존재합니다.


      4. Test Curl 보내기

      지난시간 Istio 방화벽 구축하기에서 배웠던 httpbin 전용 curl을 실행하고, Client IP에 따라 내가 원하는 Pod에 Log가 제대로 찍히는지 확인해 봅니다.

      curl --location 'https://domin.com/httpbin/get?show_env=true'



      실제 운영 서비스에 Canary 배포 적용

      이번 구현의 최종 목표는 아래와 같습니다.

      1. 최대한 자동으로 진행되고, Manual 작업은 없어야 한다.

      2. 특정 IP만 Canary 배포 서비스에 접근할 수 있어야 한다.

      지금까지 설명한 부분은 사실 2번에 대한 내용이었습니다.

      1번 Canary 배포를 최대한 자동으로 배포할 수 있을지에 대한 내용은 각 서비스들의 운영환경마다 다르기에 지금 부터 소개할 방법은 저희 환경에 최적화된 내용입니다.

      image.png

      막간을 이용한 저희 서비스 소개. PASS앱은 본인인증 외 많은 서비스가 있습니다. 그중 전자문서가 저희가 운영중인 지금 설명하고 있는 모바일지갑 서비스입니다.

      해당 버튼을 누르면 이니셜 자격증명, 행정안전부 전자문서지갑, 행정안전부 국민비서 서비스등을 사용할 수 있습니다.

      위 서비스는 PASS앱에서만 접근이 가능하고 테스트 가능합니다. 그렇기 때문에 실제 테스트도 PASS앱 위에서 진행합니다.

      특히 행안부 전자문서는 상용망에서 PASS인증서 기반으로 동작합니다. 그렇기 때문에 많은 테스트가 상용망에서 이루어져야 합니다.

      image.png

      위와 같이 main-front 2개의 Pod는 실제 서비스중인 code이고, main-front-canary1개 pod는 앞서 설명 드린 방법을 이용하여 Deploy한 신규 배포할 code 입니다.


      1. Deployment Sample Code

      image.png


      지난번 소개 드렸지만, 저희는 kustomize를 사용합니다. 기본 배포 code는 Base folder에서 작성하고, 각 환경별로 overlay folder를 이용하여 patch를 적용합니다.

      저희는 local, develop, stging, prd(main) 총 4개의 patch 환경을 가지고 있습니다.


      아래는 Base에 적용된 front-end manifest 입니다.

      ##################################################################################################
      # Main Front
      ##################################################################################################
      apiVersion: v1
      kind: Service
      metadata:
        name: main-front
      spec:
        ports:
        - port: 8080
          targetPort: 80
          protocol: TCP
          name: http
        selector:
          app: main-front
          tier: frontend
      ---
      apiVersion: apps/v1
      kind: Deployment 
      metadata:
        name: main-front
        labels:
          app: main-front
          tier: frontend
      spec:
        selector:
          matchLabels:
            app: main-front
        template: 
          metadata:
            labels:
              app: main-front
              tier: frontend
              version: main-front
          spec:
            containers:
            - name: main-front
              image: mwp/main-front:latest
              env:
                - name: ENV_PROFILE
                  valueFrom:
                    configMapKeyRef:
                      name: platform-config
                      key: env-profile
              ports:
              - containerPort: 80
      ---
      ##################################################################################################
      # Main Front Canary Deployment & Test
      ##################################################################################################
      apiVersion: apps/v1
      kind: Deployment 
      metadata:
        name: main-front-canary
        labels:
          app: main-front-canary
          tier: frontend
      spec:
        selector:
          matchLabels:
            app: main-front
            version: main-front-canary
        template: 
          metadata:
            labels:
              app: main-front
              tier: frontend
              version: main-front-canary
          spec:
            containers:
            - name: main-front
              image: mwp/main-front:latest
              env:
                - name: ENV_PROFILE
                  valueFrom:
                    configMapKeyRef:
                      name: platform-config
                      key: env-profile
              ports:
              - containerPort: 80
      ---


      overlay/staging에 적용된 patch code 입니다. pod 스케쥴링을 위한 affinity 및 container image를 가져오기 위한 AWS ECR 실제 주소가 포함되어 있습니다.

      ##################################################################################################
      # Main Front
      ##################################################################################################
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: main-front
      spec:
        replicas: 2
        template:
          metadata:
            annotations:
              inject.istio.io/templates: sidecar,custom
          spec:
            affinity:
              podAntiAffinity:
                preferredDuringSchedulingIgnoredDuringExecution:
                - weight: 100
                  podAffinityTerm:
                    labelSelector:
                      matchExpressions:
                      - key: app
                        operator: In
                        values:
                        - main-front
                    topologyKey: kubernetes.io/hostname
            containers:
            - name: main-front
              image: xxxxxxxxxx.dkr.ecr.ap-northeast-2.amazonaws.com/mwp/main-front:v1
              readinessProbe:
                httpGet:
                  path: /health
                  port: 80
                initialDelaySeconds: 5
                periodSeconds: 20
              livenessProbe:
                httpGet:
                  path: /health
                  port: 80
                initialDelaySeconds: 10
                periodSeconds: 20
      ---
      ##################################################################################################
      # Main Front Canary Deployment & Test
      ##################################################################################################
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: main-front-canary
      spec:
        replicas: 1
        template:
          metadata:
            annotations:
              inject.istio.io/templates: sidecar,custom
          spec:
            affinity:
              podAntiAffinity:
                preferredDuringSchedulingIgnoredDuringExecution:
                - weight: 100
                  podAffinityTerm:
                    labelSelector:
                      matchExpressions:
                      - key: app
                        operator: In
                        values:
                        - main-front
                    topologyKey: kubernetes.io/hostname
            containers:
            - name: main-front
              image: xxxxxxxxxx.dkr.ecr.ap-northeast-2.amazonaws.com/mwp/main-front:v1
              readinessProbe:
                httpGet:
                  path: /health
                  port: 80
                initialDelaySeconds: 5
                periodSeconds: 20
              livenessProbe:
                httpGet:
                  path: /health
                  port: 80
                initialDelaySeconds: 10
                periodSeconds: 20
      ---

      즉 아래 image 설정을 참고하여 ECR에서 image를 가져오는데....

      image: xxxxxxxxxx.dkr.ecr.ap-northeast-2.amazonaws.com/mwp/main-front:v1

      이때 image의 version(tag)은 kustomize에서 관리하는 file에서 실제로 정보를 가져와서 배포합니다.


      image.png

      images:
      - name: xxxxxxxxxx.dkr.ecr.ap-northeast-2.amazonaws.com/mwp/main-front
        newTag: 7330de851cb66dcf5633e98065c841c884c92a23

      아래 ECR에 나와 있는 것 처럼, kustomization.yaml에는 항상 최신 Image tag가 기록되어 있습니다.

      image.png


      2. Canary Pod 배포하기

      image.png

      모든 준비가 끝났습니다. 실제 서비스를 담당하는 Deployment와 Canary Deployment 둘다 최신 code가 포함된 image를 바라보고 있습니다.

      하지만 아직 배포는 되지 않았습니다. 상용 배포만큼은 운영자에 의해서 수동 배포 방식으로 정책을 정했기 때문입니다.

      위 그림과 같이 ArgoCD GUI에 들어가면 main-front와 main-front-canary가 out-of-sync 상태입니다.


      자!!! 우린 먼저 카나리새를 전장에 투입해야 합니다....canary를 먼저 sync를 하면 Test들만 접근할 수 있는 pod가 생성되고 모든 역량을 다해 카나리에 TC를 쏟아 붓습니다......

      canal.png

      댓글 0

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

      주재현 님의 최신 블로그

      더보기
      동영상 기고하기