일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 호텔 방 배정
- jdbc
- trie
- CleanCode
- 튜플
- Spring Boot
- bulk update
- 크레인 인형뽑기 게임
- 프로그래머스
- Python
- 알고리즘
- pycon
- 불량 사용자
- 티스토리
- 카카오 인턴
- 가사 검색
- 징검다리 건너기
- 트라이
- 트라이 #trie #알고리즘
- 보행자 천국
- 티스토리 open api
- Tistory
- Open API
- Today
- Total
택시짱의 개발 노트
Docker로 Spring Boot Blue, Green 배포 해보기 본문
최근에 면접관으로 참여 하면서 배포 방식에 대한 이야기가 자주 나오고 있어서 그 중 여러 분들이 사용하고 도입 했던 Blue Green 배포를 한번 해보았습니다.
저도 개념만 알고 있지 직접 해당 배포 방식을 구현 및 적용 해본적이 없어 간단하게 해봤습니다.
구성은 아래와 같습니다.
spring boot 의 jar를 docker container로 생성 ( blue, green ) 하고
앞에 nginx를 두어 load balancing 를 해주도록 했습니다.
Dockerfile
# 베이스 이미지로 OpenJDK를 사용합니다.
FROM openjdk:17-ea-17-jdk-slim
# curl 설치
RUN apt-get update && apt-get install -y curl
# 임시 디렉토리 설정
VOLUME /tmp
# 빌드된 JAR 파일을 ARG로 받습니다.
ARG JAR_FILE=practice-server/build/libs/*-SNAPSHOT.jar
# JAR 파일을 이미지에 복사합니다.
COPY ${JAR_FILE} app.jar
# 환경 변수 설정
ENV SPRING_PROFILES_ACTIVE=local
# 애플리케이션을 실행합니다.
ENTRYPOINT ["sh", "-c", "java -jar /app.jar --spring.profiles.active=${SPRING_PROFILES_ACTIVE}"]
docker-compose.yml
version: "3.8"
services:
nginx:
image: nginx:latest
container_name: nginx
ports:
- 80:80
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
depends_on:
- blue
- green
blue:
container_name: blue
build:
context: .
dockerfile: Dockerfile
environment:
- SPRING_PROFILES_ACTIVE=blue
ports:
- "8081:8081"
green:
container_name: green
build:
context: .
dockerfile: Dockerfile
environment:
- SPRING_PROFILES_ACTIVE=green
ports:
- "8082:8082"
Blue, Green 의 env를 가진 서버를 띄우기 위한 application.yaml
- docker-compose.yaml 에서 SPRING_PROFILES_ACTIVE blue, green 설정
server:
port: 8081
spring:
config:
activate:
on-profile: blue
---
server:
port: 8082
spring:
config:
activate:
on-profile: green
이제 docker-compose를 실행하면 nginx, blue, green 가 올라갑니다. ($ docker-compose up)
예를들어 현재 blue가 트래픽을 받고 있는 상황인데 새로운 버전의 배포가 필요할 때
새로운 버전이 반영된 green 을 생성하여 Nginx의 로드밸런서를 이용하여 blue → green 으로 옮겨 줘야 합니다.
- blue가 트래픽 받고 있는 상황
- blue 에서 green 으로 트래픽 변경
위와 같은 트래픽 변경을 하기 위해서는 Nginx 에서 라우팅 blue → green 으로 변경 하도록 해야 하는데
아래는 nginx container를 생성할때 사용 했던 nginx.conf 파일 입니다.
events {
worker_connections 512;
}
http {
upstream blue {
server blue:8081;
}
upstream green {
server green:8082;
}
server {
listen 80;
location / {
proxy_pass <http://$backend>;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
set $backend blue; # <-------- 요기에서 라우팅을 변경 해주도록 함
}
}
Nginx는 항상 동작하고 있기 때문에 동적으로 blue, green 을 변경 해 줘야 합니다.
blue, green 의 배포 과정을 정리 하자면 ( 현재 blue 가 트래픽을 요청 받고 있다고 가정 )
- code 작성 후 새로운 버전 생성
- 새로운 버전이 적용된 green server 구동
- nginx에서 green server 가 정상적으로 동작하는 확인 후 트래픽을 blue → green 으로 변경
- 사용되지 않는 blue server 는 down
위 동작을 shell script 로 작성 해봤습니다.
#!/bin/bash
# spring boot build
echo -e "Spring Boot 빌드 중입니다..."
./gradlew build
# 현재 backend 확인
ACTIVE_SERVER_URL="<http://0.0.0.0/active>"
RESPONSE=$(curl -s $ACTIVE_SERVER_URL)
# 서버 응답에서 <h1>blue</h1> 패턴 찾기
echo -e "서버 응답: $RESPONSE"
if echo "$RESPONSE" | grep -q "blue"; then
NOW_BACKEND="blue"
NEW_BACKEND="green"
echo -e "현재 활성화된 서버는 $NOW_BACKEND 입니다. 새로운 서버는 $NEW_BACKEND 입니다."
elif echo "$RESPONSE" | grep -q "green"; then
NOW_BACKEND="green"
NEW_BACKEND="blue"
echo -e "현재 활성화된 서버는 $NOW_BACKEND 입니다. 새로운 서버는 $NEW_BACKEND 입니다."
else
echo -e "응답을 확인할 수 없습니다."
NEW_BACKEND="blue"
fi
# NEW_BACKEND 빌드
echo -e "${NEW_BACKEND} 서버를 빌드 중입니다..."
docker-compose build --no-cache $NEW_BACKEND
# NEW_BACKEND 시작
echo -e "${NEW_BACKEND} 서버를 시작 중입니다..."
docker-compose up -d $NEW_BACKEND
# 새로운 서버가 안정화되도록 대기 (60초)
echo -e "새로운 서버가 안정화되도록 대기 중입니다 60초..."
for i in {1..60}; do
echo -e "$i/60..."
sleep 1
done
# 새로운 서버의 안정성 확인 (5초 간격으로 3번 시도)
if [ "$NEW_BACKEND" = "blue" ]; then
NEW_BACKEND_URL="<http://0.0.0.0:8081>"
else
NEW_BACKEND_URL="<http://0.0.0.0:8082>"
fi
SUCCESS=0
for i in {1..3}; do
echo -e "${NEW_BACKEND} 서버에 요청 시도 중... ($i/3)"
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" $NEW_BACKEND_URL/healthcheck)
echo -e "$RESPONSE"
if [ "$RESPONSE" -eq 200 ]; then
SUCCESS=1
break
fi
sleep 5
done
if [ "$SUCCESS" -ne 1 ]; then
echo -e "${NEW_BACKEND} 서버가 정상적으로 시작되지 않았습니다."
exit 1
fi
# Nginx 설정 파일 업데이트
NGINX_CONF_TEMPLATE="./nginx/nginx-template.conf"
NGINX_CONF="./nginx/nginx.conf"
sed "s/{{BACKEND}}/$NEW_BACKEND/" $NGINX_CONF_TEMPLATE > $NGINX_CONF
# Nginx 컨테이너 내부로 설정 파일 복사
docker cp $NGINX_CONF nginx:/etc/nginx/nginx.conf
# Nginx 컨테이너에서 Nginx 재시작
docker exec nginx nginx -s reload
echo -e "Nginx 설정이 업데이트되었습니다. 현재 backend는 $NEW_BACKEND 입니다."
# 현재 운용되는 서버 한번 더 확인
echo -e "새롭게 생성된 서버를 확인합니다."
# 서버 응답에서 <h1>blue</h1> 패턴 찾기
RESPONSE=$(curl -s $ACTIVE_SERVER_URL)
echo -e "서버 응답: $RESPONSE"
echo -e "${NOW_BACKEND} 를 종료합니다..."
docker-compose stop $NOW_BACKEND
docker-compose rm -f $NOW_BACKEND
docker container prune -f
docker image prune -f
위 shell script 동작 하면 현재 blue인지 green 인지 확인 한 후 알맞은 서버를 띄우고 트래픽 전환 까지 하게 됩니다.
- blue → green
- green → blue
이렇게 blue, green 배포를 직접 구현 해보니 blue, green 의 단점이 약간 보였는데요
- blue, green 을 하기 위해서 동작 되고 있는 서버와 같은 동일한 자원을 생성 해야 한다는 점
- blue → green or green → blue 로 전환 하면서 기존 서버에 트래픽이 끊어 진다는 점
위 2가지 정도를 단점으로 느끼게 됬습니다.
장점은 빠른 롤백이 가능 해 보였습니다.
저도 개념만 알고 있지 직접 해당 배포 방식을 구현 및 적용 해본적이 없어 간단하게 해봤습니다.
'BackEnd' 카테고리의 다른 글
Read Model을 생성하여 API의 처리량 증가 (Locust) (0) | 2023.08.23 |
---|---|
prometheus, grafana로 django 모니터링하기 - 1 (prometheus, grafana 설치) (0) | 2022.07.16 |
API 처리율 제한 장치 (Rate Limiter) (0) | 2022.02.20 |