ISTIO, Traffic Routing, Blue/Green

Jeonghak Cho·2025년 3월 2일

Istio

목록 보기
5/6

트래픽 라우팅

블루그린

블루-그린 배포(Blue-Green Deployment)는 애플리케이션의 무중단 배포를 위한 전략 중 하나로, 두 개의 동일한 환경(블루와 그린)을 활용하여 새로운 버전의 소프트웨어를 안전하게 배포하고 롤백할 수 있도록 한다.

  • 블루 환경(Blue Environment): 현재 운영 중인 애플리케이션 버전이 배포된 프로덕션 환경
  • 그린 환경(Green Environment): 새로운 버전의 애플리케이션이 배포될 별도의 프로덕션 환경

두 환경은 동일한 설정과 구성을 가지며, 새로운 버전의 배포 및 테스트를 위해 번갈아 가며 사용된다

장점

  • 무중단 배포: 사용자에게 서비스 중단 없이 새로운 버전을 제공
  • 신속한 롤백: 문제 발생 시, 트래픽을 이전 버전으로 즉시 전환하여 빠르게 롤백
  • 실제 환경 테스트: 운영 환경과 동일한 조건에서 새로운 버전을 테스트할 수 있어, 배포 전 문제를 사전에 발견 가능

단점

  • 자원 소모: 동일한 두 개의 프로덕션 환경을 유지해야 하므로, 인프라 자원이 두 배로 필요
  • 데이터 동기화: 상태를 가지는 애플리케이션의 경우, 두 환경 간의 데이터 동기화가 복잡
  • 환경 관리 복잡성: 두 개의 프로덕션 환경을 관리해야 하므로, 운영 및 유지보수의 복잡성이 증가

카나리

카나리 배포(Canary Deployment)는 새로운 소프트웨어 버전을 전체 사용자에게 배포하기 전에, 일부 사용자나 서버에 먼저 배포하여 시스템 안정성과 사용자 경험을 검증하는 점진적 배포 전략이다. 이 방법은 새로운 버전의 문제를 조기에 발견하고 전체 시스템에 미치는 영향을 최소화하는 데 중점을 둔다.

장점

  • 위험 감지: 새로운 버전의 문제를 조기에 발견하여 전체 시스템에 미치는 영향을 최소화
  • A/B 테스트 활용: 특정 사용자 그룹을 대상으로 새로운 기능이나 변경 사항을 테스트 가능
  • 롤백 용이성: 문제 발생 시, 새로운 버전을 배포한 서버나 사용자 그룹만 이전 버전으로 롤백하면 되므로 롤백이 비교적 간단

단점

  • 버전 관리 복잡성: 구 버전과 신 버전이 동시에 존재하므로, 호환성 문제나 버전 관리의 복잡성이 증가
  • 트래픽 제어 부담: 네트워크 트래픽을 신중하게 분배하고 관리해야 하므로, 추가적인 트래픽 제어에 대한 부담

블루그린 카나리 적용

구분블루-그린 배포 (Blue-Green)카나리 배포 (Canary)
배포 방식새로운 버전을 완전히 별도의 환경(그린)에 배포한 후 트래픽을 한 번에 전환기존 환경에서 일부 트래픽만 새 버전으로 보내고 점진적으로 확대
트래픽 이동 방식100% 단번에 전환점진적으로 전환
롤백 속도빠름 (트래픽을 원래 환경(블루)으로 즉시 변경)점진적 롤백 가능 (문제 발생 시 트래픽을 다시 이전 버전으로 조정)
적용 대상대규모 변경, 전체 시스템 단위 배포작은 변경, 특정 기능 또는 부분적인 배포
인프라 요구사항두 개의 환경을 유지해야 함 (리소스 소모 큼)단일 환경 내에서 운영 가능 (리소스 절약)
배포 위험새 버전의 문제가 있을 경우 모든 사용자가 영향을 받을 가능성이 높음소규모 사용자부터 적용되므로 리스크가 낮음
테스트 방식배포 후 내부에서 테스트한 뒤 전체 전환실제 사용자 트래픽을 일부만 새로운 버전에 보내며 검증
데이터베이스 영향새로운 환경(그린)에서 테스트 가능하지만 데이터 동기화가 필요운영 중인 DB를 사용하므로 스키마 변경 시 주의 필요

ISTIO 블루, 카나리 적용

게이트웨이 생성

폴더를 만들고 네임스페이스를 myisto로 생성한다.

mkdir myistio
cd myistio

k create ns myistio
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: mygateway
  labels:
    app: mygateway
spec:
  gatewayClassName: istio
  listeners:
    - protocol: HTTP
      port: 80
      name: http
vagrant@slave1:~/myistio$ k apply -f mygateway.yml -n myistio
gateway.gateway.networking.k8s.io/mygateway created

게이트웨이 리소스 확인

게이트웨이 생성을 하면 POD, SERVIcE, DEPLOYMENT, REPLICASET을 하나씩 생성하며, 이름은 부여한 이름 뒤에 "-istio" 가 자동으로 붙는다. 방금 생성한 게이트웨이 호출은 mygateway가 아니고 mygateway-istio로 호출해야 정상으로 응답한다.

vagrant@slave1:~/myistio$ k get all -n myistio -l app=mygateway
NAME                                  READY   STATUS    RESTARTS   AGE
pod/mygateway-istio-f545b745c-7lsdz   1/1     Running   0          19s

NAME                      TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)                        AGE
service/mygateway-istio   LoadBalancer   10.96.212.157   192.168.56.103   15021:30752/TCP,80:31849/TCP   19s

NAME                              READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/mygateway-istio   1/1     1            1           19s

NAME                                        DESIRED   CURRENT   READY   AGE
replicaset.apps/mygateway-istio-f545b745c   1         1         1       19s

게이트웨이가 라우트할 서비스를 버전 v1, 버전 v2 로 나눈다.
backend.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: backend-v1
spec:
  selector:
    matchLabels:
      app: backend
      version: v1
  replicas: 1
  template:
    metadata:
      labels:
        app: backend
        version: v1
    spec:
      containers:
      - name: backend-v1
        image: chojeonghak/backend:0.2
        ports:
        - containerPort: 5000
---
apiVersion: v1
kind: Service
metadata:
  name: backend-v1
  labels:
    app: backend
    version: v1
spec:
  ports:
  - port: 5000
    protocol: TCP
  selector:
    app: backend
    version: v1
  type: ClusterIP
  ---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: backend-v2
spec:
  selector:
    matchLabels:
      app: backend
      version: v2
  replicas: 1
  template:
    metadata:
      labels:
        app: backend
        version: v2
    spec:
      containers:
      - name: backend-v2
        image: chojeonghak/backend:0.2
        ports:
        - containerPort: 5000
---
apiVersion: v1
kind: Service
metadata:
  name: backend-v2
  labels:
    app: backend
    version: v2
spec:
  ports:
  - port: 5000
    protocol: TCP
  selector:
    app: backend
    version: v2
  type: ClusterIP
  • 적용
k apply -f backend.yml -n myistio

버전 별 deployment, service 생성 확인

vagrant@slave1:~/myistio$ k get all -n myistio -l app=backend
NAME                              READY   STATUS    RESTARTS   AGE
pod/backend-v1-7c8567cb4d-txdrv   2/2     Running   0          20m
pod/backend-v2-59c67444c4-jrp7h   2/2     Running   0          20m

NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
service/backend-v1   ClusterIP   10.99.245.136   <none>        5000/TCP   20m
service/backend-v2   ClusterIP   10.98.127.55    <none>        5000/TCP   20m

NAME                                    DESIRED   CURRENT   READY   AGE
replicaset.apps/backend-v1-7c8567cb4d   1         1         1       20m
replicaset.apps/backend-v2-59c67444c4   1         1         1       20m

HTTPROUTE 생성

라우터는 위에서 생성한 mygateway를 참조하고, 라우트 대상인 서비스 명과 포트, 그리고 가중치를 부여한다.
myroute.yml

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: myroute
spec:
  parentRefs:
    - name: mygateway
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: "/"
      backendRefs:
        - name: backend-v1
          port: 5000
          weight: 50
        - name: backend-v2
          port: 5000
          weight: 50

생성한 HTTPROUTE 확인

vagrant@slave1:~/myistio$ kubectl get httproute -n myistio
NAME      HOSTNAMES   AGE
myroute               46m
vagrant@slave1:~/myistio$ k describe httproute myroute -n myistio
Name:         myroute
Namespace:    myistio
Labels:       <none>
Annotations:  <none>
API Version:  gateway.networking.k8s.io/v1
Kind:         HTTPRoute
Metadata:
  Creation Timestamp:  2025-03-02T07:57:20Z
  Generation:          1
  Resource Version:    516533
  UID:                 f6321d91-aa54-4a60-84d1-1dcf8310a2a6
Spec:
  Parent Refs:
    Group:  gateway.networking.k8s.io
    Kind:   Gateway
    Name:   mygateway
  Rules:
    Backend Refs:
      Group:
      Kind:    Service
      Name:    backend-v1
      Port:    5000
      Weight:  100
      Group:
      Kind:    Service
      Name:    backend-v2
      Port:    5000
      Weight:  0
    Matches:
      Path:
        Type:   PathPrefix
        Value:  /
Status:
  Parents:
    Conditions:
      Last Transition Time:  2025-03-02T08:29:55Z
      Message:               Route was valid
      Observed Generation:   1
      Reason:                Accepted
      Status:                True
      Type:                  Accepted
      Last Transition Time:  2025-03-02T08:29:55Z
      Message:               All references resolved
      Observed Generation:   1
      Reason:                ResolvedRefs
      Status:                True
      Type:                  ResolvedRefs
    Controller Name:         istio.io/gateway-controller
    Parent Ref:
      Group:  gateway.networking.k8s.io
      Kind:   Gateway
      Name:   mygateway
Events:       <none>

트래픽 생성

while true; do curl "http://mygateway-istio.myistio.svc.cluster.local/";sleep 1s; done

가중치 변경

myroute.yml

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: myroute
spec:
  parentRefs:
    - name: mygateway
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: "/"
      backendRefs:
        - name: backend-v1
          port: 5000
          weight: 100
        - name: backend-v2
          port: 5000
          weight: 0
  • 적용
k apply -f myroute.yml -n myistio
vagrant@slave1:~/myistio$ k rollout restart deploy mygateway-istio -n myistio
deployment.apps/mygateway-istio restarted

0개의 댓글