
블루-그린 배포(Blue-Green Deployment)는 애플리케이션의 무중단 배포를 위한 전략 중 하나로, 두 개의 동일한 환경(블루와 그린)을 활용하여 새로운 버전의 소프트웨어를 안전하게 배포하고 롤백할 수 있도록 한다.
두 환경은 동일한 설정과 구성을 가지며, 새로운 버전의 배포 및 테스트를 위해 번갈아 가며 사용된다
카나리 배포(Canary Deployment)는 새로운 소프트웨어 버전을 전체 사용자에게 배포하기 전에, 일부 사용자나 서버에 먼저 배포하여 시스템 안정성과 사용자 경험을 검증하는 점진적 배포 전략이다. 이 방법은 새로운 버전의 문제를 조기에 발견하고 전체 시스템에 미치는 영향을 최소화하는 데 중점을 둔다.
| 구분 | 블루-그린 배포 (Blue-Green) | 카나리 배포 (Canary) |
|---|---|---|
| 배포 방식 | 새로운 버전을 완전히 별도의 환경(그린)에 배포한 후 트래픽을 한 번에 전환 | 기존 환경에서 일부 트래픽만 새 버전으로 보내고 점진적으로 확대 |
| 트래픽 이동 방식 | 100% 단번에 전환 | 점진적으로 전환 |
| 롤백 속도 | 빠름 (트래픽을 원래 환경(블루)으로 즉시 변경) | 점진적 롤백 가능 (문제 발생 시 트래픽을 다시 이전 버전으로 조정) |
| 적용 대상 | 대규모 변경, 전체 시스템 단위 배포 | 작은 변경, 특정 기능 또는 부분적인 배포 |
| 인프라 요구사항 | 두 개의 환경을 유지해야 함 (리소스 소모 큼) | 단일 환경 내에서 운영 가능 (리소스 절약) |
| 배포 위험 | 새 버전의 문제가 있을 경우 모든 사용자가 영향을 받을 가능성이 높음 | 소규모 사용자부터 적용되므로 리스크가 낮음 |
| 테스트 방식 | 배포 후 내부에서 테스트한 뒤 전체 전환 | 실제 사용자 트래픽을 일부만 새로운 버전에 보내며 검증 |
| 데이터베이스 영향 | 새로운 환경(그린)에서 테스트 가능하지만 데이터 동기화가 필요 | 운영 중인 DB를 사용하므로 스키마 변경 시 주의 필요 |
폴더를 만들고 네임스페이스를 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
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
라우터는 위에서 생성한 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
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