23.06.15
DEVOTEE를 활성화 시키면
지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.
버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.
| 컨텐츠 유형 | 제목 | 저장일 | 삭제 |
|---|
본인인증 로그인에 실패하였습니다.
회원이 아니시거나 본인인증 등록이
완료되지 않은 사용자입니다.
MSA 서비스를 운영하면 아무래도 신규 개발 및 배포가 자주 발생하게 됩니다.
이때 전자문서, 국민비서등 정부/행정안전부의 서비스와 연동이 많은 우리 서비스 특성상 개발/스테이징에서 QA가 불가능한 경우가 많다.
정부의 개인보호 정책 때문에 개발/스테이징에서는 테스트 불가한 제약이 많기 때문이다.
그래서 운영환경에서 일부 테스트가 진행되어야 하는데, 동시에 배포되는 Web 서비스의 특성상 운영 테스트가 힘든 경우가 많았다.
이를 해결하기 위해 특정 IP(테스터그룹)만 접근 가능한 Canary 배포를 적용하였고 공유하고자 합니다.
기본적으로 배포 전략은 지식이 있다는 가정으로 글을 작성하였습니다. 필요하신 분은 아래 블로그 참고하세요
이글은 Istio를 기반으로 구현하였기 때문에, 관련글은 미리 참고하시면 좋습니다.
Kustomize에 대한 기본 개념이 있어야 합니다. 아래 이전글 참고
최대한 자동으로 진행되고, Manual 작업은 없어야 한다.
특정 IP만 Canary 배포 서비스(Pod)에 접근할 수 있어야 한다.
위 두개를 목표로 수립하고 진행하였습니다.
사실 Canary배포의 전략은 많이 있습니다. 가장 흔히 사용되는건 Traffic에 weight를 주어서 신규 배포 서버로 조금씩 유입시키는 전략입니다.
하지만 저희 서비스 특성상 신규 기능을 먼저 테스트 그룹이 QA를 진행하고, 나머지 서버에 Rolling 업데이트 하는 방법을 이번에 설명 드릴 예정입니다.
시나리오는 위 그림과 같습니다. 20.1.1.1 이라는 IP를 가진 그룹만 Version2(Green Pod)로 network traffic이 흘러가고, 기존 고객들을 Version1(Blue Pod)로 가는 것입니다.
즉 Istio gateway에서 IP를 filtering 하여 pod version을 보고 routing 하는 방식입니다.
아래와 같이 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
---일단 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
---만약 모든 배포가 제대로 되었다면, 위 그림과 같이 test-vs(Virtual Service) 아래에 httpbin(Service)가 있고, 그 아래 httpbin(기존 code), httpbin-canary(신규 code)가 존재합니다.
지난시간 Istio 방화벽 구축하기에서 배웠던 httpbin 전용 curl을 실행하고, Client IP에 따라 내가 원하는 Pod에 Log가 제대로 찍히는지 확인해 봅니다.
curl --location 'https://domin.com/httpbin/get?show_env=true'이번 구현의 최종 목표는 아래와 같습니다.
최대한 자동으로 진행되고, Manual 작업은 없어야 한다.
특정 IP만 Canary 배포 서비스에 접근할 수 있어야 한다.
지금까지 설명한 부분은 사실 2번에 대한 내용이었습니다.
1번 Canary 배포를 최대한 자동으로 배포할 수 있을지에 대한 내용은 각 서비스들의 운영환경마다 다르기에 지금 부터 소개할 방법은 저희 환경에 최적화된 내용입니다.
막간을 이용한 저희 서비스 소개. PASS앱은 본인인증 외 많은 서비스가 있습니다. 그중 전자문서가 저희가 운영중인 지금 설명하고 있는 모바일지갑 서비스입니다.
해당 버튼을 누르면 이니셜 자격증명, 행정안전부 전자문서지갑, 행정안전부 국민비서 서비스등을 사용할 수 있습니다.
위 서비스는 PASS앱에서만 접근이 가능하고 테스트 가능합니다. 그렇기 때문에 실제 테스트도 PASS앱 위에서 진행합니다.
특히 행안부 전자문서는 상용망에서 PASS인증서 기반으로 동작합니다. 그렇기 때문에 많은 테스트가 상용망에서 이루어져야 합니다.
위와 같이 main-front 2개의 Pod는 실제 서비스중인 code이고, main-front-canary1개 pod는 앞서 설명 드린 방법을 이용하여 Deploy한 신규 배포할 code 입니다.
지난번 소개 드렸지만, 저희는 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에서 실제로 정보를 가져와서 배포합니다.
images:
- name: xxxxxxxxxx.dkr.ecr.ap-northeast-2.amazonaws.com/mwp/main-front
newTag: 7330de851cb66dcf5633e98065c841c884c92a23아래 ECR에 나와 있는 것 처럼, kustomization.yaml에는 항상 최신 Image tag가 기록되어 있습니다.
모든 준비가 끝났습니다. 실제 서비스를 담당하는 Deployment와 Canary Deployment 둘다 최신 code가 포함된 image를 바라보고 있습니다.
하지만 아직 배포는 되지 않았습니다. 상용 배포만큼은 운영자에 의해서 수동 배포 방식으로 정책을 정했기 때문입니다.
위 그림과 같이 ArgoCD GUI에 들어가면 main-front와 main-front-canary가 out-of-sync 상태입니다.
자!!! 우린 먼저 카나리새를 전장에 투입해야 합니다....canary를 먼저 sync를 하면 Test들만 접근할 수 있는 pod가 생성되고 모든 역량을 다해 카나리에 TC를 쏟아 붓습니다......
DEVOTEE를 활성화 시키면
지금 작성한 댓글에 AI가 댓글을 달아줍니다.