본문 바로가기
[DevOps]/CI & CD

로컬에서 젠킨스로 블루/그린 무중단 배포 테스트하기 (2) - 쉘 스크립트 배포 파일 작성

by 황원용 2023. 11. 25.
728x90
💡 이 글은 2편으로 1편인https://suzuworld.tistory.com/419에 이어 쓰는 글이다.

 

🤗 쉘 스크립트 작성 준비

  • 이제 할 일은 먼저 쉘스크립트로 배포 파일을 만드는 것이다.
  • 스프링 부트 프로젝트 상위 폴더에 script라는 디렉터리를 만든 다음에 deploy.sh라는 이름의 파일을 만들자.

 

🤔 들어가기 전에

 

  • 본격적으로 들어가기 전에 위 그림을 한 번 더 보고 시작하면 스크립트 이해에 많은 도움이 될 것이다.
  • 이번에 쉘 스크립트 파일을 처음 만져봐서 상당히 애먹었는데 대부분의 블로그가 각 명령어에 대해 자세히 설명하지 않아 시간이 더 걸렸던 것 같다.
  • 나처럼 쉘 스크립트 작성이 처음인 사람을 위해 최대한 자세히 설명해 보겠다.(설명이 다소 장황하고 틀릴 수도 있음😅)
  • 묶음 단위로 설명하고 맨 아래에는 완성본을 보여주는 방식으로 진행하겠다.
  • 다 이해한다면 스크립트 파일에 대한 응용 동작도 만들어 낼 수 있을 것이다.

 

✍🏻 쉘 스크립트 작성

#!/bin/bash
  • /bin/bash 경로에 있는 Bash 해석기를 해당 스크립트를 실행할 때 사용하겠다고 명시하는 것이다.

 

SWITCH_SCRIPT="./switch.sh"

DEFAULT_SWITCH_SCRIPT="./default_switch.sh"

SERVER_HOME=젠킨스 워크스페이스 내 빌드 테스트 경로
  • SWITCH_SCRIPT와 DEFAULT_SWITCH_SCRIPT는 변수를 선언한 것이다.
  • 이 두 변수는 deploy.sh 파일 내에서 조건문으로 분기하여 실행되는 또 다른 쉘스크립트 파일의 경로를 담고 있다.
  • SWITCH_SCRIPT는 블루, 그린 포트 중 한 곳이 실행중일 때, 다른 곳으로 리버스 프록시를 스위칭하는 데에 사용된다.
  • DEFAULT_SWITCH_SCRIPT의 경우 두 포트 모두 죽어있을 때(스프링 부트 서버가 꺼져있을 때) 디폴트인 블루 포트를 실행시키고 NGINX의 프록시 방향을 블루로 맞춰놓는 데에 사용된다.
  • SERVER_HOME은 프로젝트의 젠킨스에서 빌드한 jar 파일이 있는 경로이다.
    • 나의 경우에는 완전히 로컬 PC 한 곳에서만 테스트했기 때문에 젠킨스의 워크스페이스 폴더 내에 빌드 파일을 저장하고 서버를 실행시킨다는 시나리오로 접근했다.
    • 만약 배포를 위한 외부 서버(AWS 인스턴스 등)에 보낼 것이라면 다른 블로그를 참고하면서 따라하면 될 것 같다.

 

echo "-> 👨🏻‍💼<Jenkins 배포 시작>"
CURRENT_SERVER_PROFILE=$(curl -s http://localhost:28080/profile | head -n 1)
  • echo 출력으로 젠킨스 배포가 시작됨을 알린다.
    • 쉘 스크립트가 예쁘게 출력되면 배포할 때 기분도 좋아지지 않을까 하는 생각에 이모지를 고를 때 신중을 가했다.🤗
  • 정리하면 배포 시작을 알리는 출력문을 내보내고 curl을 이용해 해당 프로젝트의 페이지에서 맨 앞 줄 첫 번째 키워드만을 변수에 넣는다.
    • 여기서 변수에 담기는 내용은 바로 앞선 글에서 설정했던 application.yml의 프로필 이름인 blue, green이다.
    • blue로 서버가 실행되는 8081 포트라면 blue가 담길것이고, green으로 실행되는 8082 포트라면 green이 담길 것이다.
  • 28080은 nginx로 포트포워딩한 것이다.
    • nginx에 대한 설명은 아래에 있다. 
    • if blue) 28080 -> 8081
    • else if green) 28080 -> 8082
  • echo : 주어진 인자를 표준 출력으로 출력하는 명령어이다.
  • curl : 주어진 URL을 통해 데이터를 전송하거나 받아오는 명령어이다.
  •  -s : curl이 실행되는 동안 진행 상황이나 진단 메시지 등의 출력을 표시하지 않음을 의미한다.(silent)
  • head : 텍스트의 앞 부분을 의미한다.
  • -n 1 : 첫번째 줄을 의미한다.

 

if [ "$CURRENT_SERVER_PROFILE" == blue ]
then
echo "-> 💡 현재 구동중인 Profile : $CURRENT_SERVER_PROFILE"
CURRENT_SERVER_PORT=8081
SWITCH_SERVER_PROFILE=green
SWITCH_SERVER_PORT=8082
elif [ "$CURRENT_SERVER_PROFILE" == green ]
then
echo "-> 💡 현재 구동중인 Profile : $CURRENT_SERVER_PROFILE"
CURRENT_SERVER_PORT=8082
SWITCH_SERVER_PROFILE=blue
SWITCH_SERVER_PORT=8081
else
echo "-> ⚠️ profile not found : 일치하는 Profile이 없습니다."
echo "-> ⚠️ set default profile : 기본 Profile blue를 할당합니다."
echo "-> ⚠️ 블루, 그린이 모두 동작중이 아니었으므로, blue만 배포하고 스크립트를 종료합니다."
SWITCH_SERVER_PROFILE=blue
SWITCH_SERVER_PORT=8081
fi
  • 현재 실행중인 포트가 8081이라면 green과 8082를 각 switch 변수에 담고, 8082라면 blue와 8081을 각 switch 변수에 담는다.
  • 둘 다 아니라면 디폴트 프로필인 blue와 포트 8081을 각 switch 변수에 담는다.
  •  fi : if문이 종료됨을 뜻한다.

 

echo "-> 🚚 $SWITCH_SERVER_PROFILE 배포"
SWITCH_PORT_PID=$(netstat -anv | grep $SWITCH_SERVER_PORT | head -n 1 | awk '{print $9}')
if [ ! -z "$SWITCH_PORT_PID" ]
then
echo "-> 📦 $SWITCH_SERVER_PROFILE PID : $SWITCH_PORT_PID"
kill $SWITCH_PORT_PID >/dev/null 2>&1
fi
  • swith 변수에 담긴 프로필로 스프링 부트 서버 배포를 시작한다.
  • 만약 switch 포트가 이미 서버에서 실행 중이라면 에러가 발생할 것임으로 먼저 switch 포트를 죽이고 시작한다.
  • 이때 핵심은 운영체제 환경마다 해당 포트를 찾고 그 포트의 pid를 찾는 것이 다를 수 있다는 점인데 위 명령어를 응용하여 출력문을 보고 해당 pid의 위치를 찾게 만들면 된다.
wonyonghwang@Wonyongs-MacBook-Pro jenkins % netstat -anv | grep 8081
tcp46      0      0  *.8081                 *.*                    LISTEN       131072  131072   3953      0 00000 00000006 00000000000057ce 00000000 00000800      2      0 000001
wonyonghwang@Wonyongs-MacBook-Pro jenkins % netstat -anv | grep 8082
tcp46      0      0  *.8082                 *.*                    LISTEN       131072  131072   4392      0 00000 00000006 0000000000008378 00000000 00000800      2      0 000001
  • netstat -anv : 무수히 많은 프로세스 관련 내용이 출력된다.
  • grep : 여기서 grep으로 스위치할 포트 번호를 추려낸다.
  • head -n 1 :  맨 위 줄만 출력하겠다는 의미이다.
  • awk '{print $9}' : 9 번째 문자를 출력하겠다는 의미이다.
    • 위의 출력문을 세어보면 3953, 4392가 9번째에 위치해 있음을 확인할 수 있다.

 

wonyonghwang@Wonyongs-MacBook-Pro jenkins % netstat -anv | grep 8081 | head -n 1 | awk '{print $9}'
3953
wonyonghwang@Wonyongs-MacBook-Pro jenkins % netstat -anv | grep 8082 | head -n 1 | awk '{print $9}'
4392
  • 이렇게 출력하면 PID만 출력이 가능하다.
  • 이를 PID 변수에 넣고 해당 포트의 PID로 포트를 kill 하는 것이다.
  • /dev/null 2>&1 : 명령어 결과를 출력하지 않겠다는 뜻이다.
    • kill 했을 때 출력문이 나오는게 보기 싫어 넣었다.

 

echo "-> 🚚 nohup java -jar $SERVER_HOME/forJenkins.jar --spring.profiles.active=$SWITCH_SERVER_PROFILE > /dev/null &"
nohup java -jar $SERVER_HOME/forJenkins.jar --spring.profiles.active=$SWITCH_SERVER_PROFILE > /dev/null &

echo "-> 🚑 $SWITCH_SERVER_PROFILE : 10초 후 Health Check Start"
echo "-> 🚑 curl -s http://localhost:$SWITCH_SERVER_PORT/actuator/health"
sleep 10
  • 스위칭할 프로필 스프링부트 서버를 백그라운드로 실행을 한다.(nohup)
  • SERVER_HOME은 위의 jar 파일이 저장될 위치이며, PROFILE은 switch 할 프로필이다.
  • 서버가 실행되면 sleep으로 10초 후 health check가 시작된다.
    • 스프링부트 실행 완료 시간을 넉넉하게 잡아 설정한 것이다.
  • echo는 지금 이 출력문이 실행된다는 것을 알리기 위한 출력문일 뿐이니 큰 의미을 강조한다. 자유롭게 변경하자.

 

for retry_count in {1..10}
do
response=$(curl -s http://localhost:$SWITCH_SERVER_PORT/actuator/health)
count=$(echo $response | grep "UP" | wc -l)

if [ $count -ge 1 ]
then
echo "-> 🚨 [$retry_count 번째 Health Check]"
echo "-> Health Check 성공!!!"
break
else
echo "-> Health Check 실패, 서버로부터 응답을 받지 못했습니다."
echo "-> 📣 서버로부터 받은 응답 : $response"
fi

if [ $retry_count -eq 10 ]
then
echo "-> 😵‍💫 Health Check $retry_count 회 시도 모두 실패..."
echo "-> 🫠 배포 종료"
exit 1
fi

echo "-> 🤔 Health Check 실패, 5초 후 재시도..."
sleep 5
done
  • wc -l : 입력된 텍스트의 줄 수를 세는 역할을 한다.
  • -ge : "Greater than or equal to"라는 의미로, 여기서는 저장된 값이 1보다 크거나 같은지를 확인한다.
  • -eq : "Equal to"라는 의미로, 주어진 값이 다른 값과 같은지를 비교하는 역할을 한다.
  • exit 1 : 0 이외의 값은 오류임을 명시하고 프로그램을 종료하며, 0일 경우 정상 종료를 의미한다. 
  • 총 10 번을 체크한다. do done 안에는 반복문 내용이 들어간다.

 

if [ -z "$CURRENT_SERVER_PORT" ]
then
echo "-> 🔄 NGINX : Default Port로 프록시 설정"
if [ ! -x "$DEFAULT_SWITCH_SCRIPT" ]
then
chmod +x "$DEFAULT_SWITCH_SCRIPT"
fi
"$DEFAULT_SWITCH_SCRIPT"
echo "->👨🏻‍💼<Jenkins 배포 성공> 스크립트를 종료합니다."
exit 0
fi
  • -z : 변수가 비어있을 경우를 의미한다.
  • -x : 파일 실행 권한이 없는 경우를 의미한다.
  • chmod +x : .sh 파일 실행 권한을 추가한다.
  • exit 0 : 정상 종료임을 명시한다.
  • 여기서 위에서 언급한 분기가 시작된다.
  • 현재 포트가 비어있다면 blue, green 모두 실행되고 있지 않다는 의미이므로 DEFAULT_SWITCH_SCRIPT를 실행시키고 배포 스크립트를 종료한다.

 

echo "-> 🤼 NGINX 포트 스위칭 스크립트 시작"
if [ ! -x "$SWITCH_SCRIPT" ]
then
chmod +x "$SWITCH_SCRIPT"
# .sh 파일 실행 권한을 확인하고 없으면 추가
fi
"$SWITCH_SCRIPT"

echo "-> 🔫 기존 포트인 $CURRENT_SERVER_PROFILE 포트 : $CURRENT_SERVER_PORT KILL"
CURRENT_PORT_PID=$(netstat -anv | grep $CURRENT_SERVER_PORT | head -n 1 | awk '{print $9}')
echo "-> 📦 $CURRENT_SERVER_PROFILE PID : $CURRENT_PORT_PID"
kill $CURRENT_PORT_PID >/dev/null 2>&1
echo "->👨🏻‍💼<Jenkins 배포 성공> 스크립트를 종료합니다."
  • 만약 위의 if 문에서 해당이 안 된다면(blue or green 중 하나가 살아있음) 포트 스위칭을 위해 이 if 문으로 내려온다.
  • SWITCH_ SCRIPT를 실행하여 nginx의 프록시 방향을 변경하고 기존에 실행되고 있던 프로필의 포트를 죽인다.
  • 마지막으로 스크립트 종료를 알리는 출력문을 출력하고 배포 스크립트 파일은 최종적으로 종료된다.

 

📌 deploy.sh 스크립트 완성본

#!/bin/bash

SWITCH_SCRIPT="./switch.sh"

DEFAULT_SWITCH_SCRIPT="./default_switch.sh"

SERVER_HOME=젠킨스 워크스페이스 내 빌드 테스트 경로

echo "-> 👨🏻‍💼<Jenkins 배포 시작>"
CURRENT_SERVER_PROFILE=$(curl -s http://localhost:28080/profile | head -n 1)

if [ "$CURRENT_SERVER_PROFILE" == blue ]
then
echo "-> 💡 현재 구동중인 Profile : $CURRENT_SERVER_PROFILE"
CURRENT_SERVER_PORT=8081
SWITCH_SERVER_PROFILE=green
SWITCH_SERVER_PORT=8082
elif [ "$CURRENT_SERVER_PROFILE" == green ]
then
echo "-> 💡 현재 구동중인 Profile : $CURRENT_SERVER_PROFILE"
CURRENT_SERVER_PORT=8082
SWITCH_SERVER_PROFILE=blue
SWITCH_SERVER_PORT=8081
else
echo "-> ⚠️ profile not found : 일치하는 Profile이 없습니다."
echo "-> ⚠️ set default profile : 기본 Profile인 blue를 할당합니다."
echo "-> ⚠️ 블루, 그린이 모두 동작중이 아니었으므로, blue만 배포하고 스크립트를 종료합니다."
SWITCH_SERVER_PROFILE=blue
SWITCH_SERVER_PORT=8081
fi

echo "-> 🚚 $SWITCH_SERVER_PROFILE 배포"
SWITCH_PORT_PID=$(netstat -anv | grep $SWITCH_SERVER_PORT | head -n 1 | awk '{print $9}')
if [ ! -z "$SWITCH_PORT_PID" ]
then
echo "-> 📦 $SWITCH_SERVER_PROFILE 의 PID : $SWITCH_PORT_PID"
kill $SWITCH_PORT_PID >/dev/null 2>&1
fi

echo "-> 🚚 nohup java -jar $SERVER_HOME/forJenkins.jar --spring.profiles.active=$SWITCH_SERVER_PROFILE > /dev/null &"
nohup java -jar $SERVER_HOME/forJenkins.jar --spring.profiles.active=$SWITCH_SERVER_PROFILE > /dev/null &

echo "-> 🚑 $SWITCH_SERVER_PROFILE : 10초 후 Health Check Start"
echo "-> 🚑 curl -s http://localhost:$SWITCH_SERVER_PORT/actuator/health"
sleep 10

for retry_count in {1..10}
do
response=$(curl -s http://localhost:$SWITCH_SERVER_PORT/actuator/health)
count=$(echo $response | grep "UP" | wc -l)

if [ $count -ge 1 ]
then
echo "-> 🚨 [$retry_count 번째 Health Check]"
echo "-> ✅ Health Check 성공!!!"
break
else
echo "-> ❌ Health Check 실패, 서버로부터 응답을 받지 못했습니다."
echo "-> 📣 서버로부터 받은 응답 : $response"
fi

if [ $retry_count -eq 10 ]
then
echo "-> 😵‍💫 Health Check $retry_count 회 시도 모두 실패..."
echo "-> 🫠 배포 종료"
exit 1
fi

echo "-> 🤔 Health Check 실패, 5초 후 재시도..."
sleep 5
done

if [ -z "$CURRENT_SERVER_PORT" ]
then
echo "-> 🔄 NGINX : Default Port로 프록시 설정"
if [ ! -x "$DEFAULT_SWITCH_SCRIPT" ]
then
chmod +x "$DEFAULT_SWITCH_SCRIPT"
fi
"$DEFAULT_SWITCH_SCRIPT"
echo "->👨🏻‍💼<Jenkins 배포 성공> 스크립트를 종료합니다."
exit 0
fi

echo "-> 🤼 NGINX 포트 스위칭 스크립트 시작"
if [ ! -x "$SWITCH_SCRIPT" ]
then
chmod +x "$SWITCH_SCRIPT"
fi
"$SWITCH_SCRIPT"

echo "-> 🔫 기존 포트인 $CURRENT_SERVER_PROFILE 포트 : $CURRENT_SERVER_PORT KILL"
CURRENT_PORT_PID=$(netstat -anv | grep $CURRENT_SERVER_PORT | head -n 1 | awk '{print $9}')
echo "-> 📦 $CURRENT_SERVER_PROFILE 의 PID : $CURRENT_PORT_PID"
kill $CURRENT_PORT_PID >/dev/null 2>&1
echo "->👨🏻‍💼<Jenkins 배포 성공> 스크립트를 종료합니다."

🛠️ NGINX 설정

server {
        listen       28080;
        server_name  localhost;

        include /usr/local/etc/nginx/conf.d/service-url.inc;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            proxy_pass $service_url;
            proxy_redirect     off;
            proxy_http_version 1.1;
            proxy_set_header   Host $http_host;
            proxy_set_header   Connection "";
            proxy_set_header   X-Real-IP $remote_addr;
            proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header   X-Forwarded-Host $server_name;
    }
  • nginx를 다운로드하여 설치한다.
  • 보통 nginx 폴더의 경로는 두 가지인 것 같다.
    • /usr/local/etc/nginx
    • /opt/homebrew/etc/nginx
  • nginx.conf에 들어가 보면 기본적으로 적힌 내용이 있을 텐데 전부 무시하고 http {} 안에 위와 같이 적는다.
  • 여기서 핵심은 아래와 같다.

💡 listen

  • 포트포워딩할 포트이다.
  • nginx에 위와 같이 28080이라 적는다면 포트 포워딩되어 nginx 포트로 접속할 때 28080 -> 8081 or 28080 -> 8082로 스프링부트 서버와 연결될 것이다.

💡 include /usr/local/etc/nginx/conf.d/service-url.inc;

  • include로 해당 경로의 service-url.inc를 nginx.conf에 가져온다는 뜻이다.
  • nginx 폴더에 conf.d가 없다면 만들어도 무방하다. 이 폴더 안에 vi service-url.inc 명령어로 파일을 만들어둔다.
  • 초기값으로 set \$service_url http://127.0.0.1:8081과 같이 블루 or 그린 포트 하나를 지정해 놓는다.(테스트를 위해 blue로 해놓자.)

💡 location / {proxy_pass $service_url}

  • 위의 service-url.inc의 service_url 변숫값을 가져와 사용한다.

 

⌨️ NGINX 테스트

  • 로컬에서 스프링부트 서버를 blue로 실행시켜 놓고 localhost:28080으로 접속하면 280280 -> 8081로 연결되어 스프링부트의 출력문이 화면에 나올 것이다.

 

📌 DEFAULT_SWITCH_SCRIPT

#!/bin/bash

SWITCH_PROXY_PORT=8081
echo "-> ⚡️ set default port : 기본 포트인 $SWITCH_PROXY_PORT 를 할당합니다."

echo "-> 🔄 NGINX 내의 프록시 방향 설정"
echo "-> 🥳 set \$service_url http://127.0.0.1:${SWITCH_PROXY_PORT};"
echo "set \$service_url http://127.0.0.1:${SWITCH_PROXY_PORT};"| tee /usr/local/etc/nginx/conf.d/service-url.inc >/dev/null 2>&1

echo "-> 🔄 NGINX 재시작"
/usr/local/bin/nginx -s reload
  • set a b : a 변수에 b를 할당한다.
  • tee : 앞에서 출력한 문자열을 해당 경로에 덮어쓴다.
  • nginx 설정을 완료했다면 이제 이 스크립트가 이해가 될 것이다.
  • 만약 blue, green이 모두 실행 중이 아니라면 디폴트 프로필인 blue가 실행하도록 하는 것이다.
  • SWITCH 할 포트를 8081로 설정하여 nginx.conf의 proxy_pass에 연결할 포트를 8081로 설정하는 것이다.
  • 마지막에는 nginx 폴더로 경로를 설정하고 reload를 실행한다.
    • 이렇게 해주는 이유는 젠킨스가 로컬 서버에 스크립트 파일을 실행시킬 때 nginx 폴더를 찾지 못하기 때문이다.

 

📌 SWITCH_SCRIPT

#!/bin/bash

CURRENT_PROFILE=$(curl -s http://localhost:28080/profile)
echo "-> 💡 현재 구동중인 Spring Boot Port : $CURRENT_PROFILE"

if [ $CURRENT_PROFILE == blue ]
then
CURRENT_PROXY_PORT=8081
SWITCH_PROXY_PORT=8082
elif [ $CURRENT_PROFILE == green ]
then
CURRENT_PROXY_PORT=8082
SWITCH_PROXY_PORT=8081
else
echo "-> ⚠️ profile not found : $CURRENT_PROFILE -> 일치하는 Profile이 없습니다."
echo "-> ⚠️ set default port : 기본 포트인 8081을 할당합니다."
SWITCH_PROXY_PORT=8081
fi

echo "-> ⚡️ 현재 NGINX 프록시 포트 : $CURRENT_PROXY_PORT"
echo "-> ⚡️ 변경할 NGINX 프록시 포트 : $SWITCH_PROXY_PORT"

echo "-> 🔄 NGINX 내의 프록시 방향 변경"
echo "-> 🥳 set \$service_url http://127.0.0.1:${SWITCH_PROXY_PORT};"
echo "set \$service_url http://127.0.0.1:${SWITCH_PROXY_PORT};"| tee /usr/local/etc/nginx/conf.d/service-url.inc >/dev/null 2>&1

echo "->  NGINX 재시작"
/usr/local/bin/nginx -s reload
  • SWITCH 스크립트의 경우 별도의 스크립트 파일이기 때문에 다시 한번 현재 포트의 프로필을 확인한다.
  • 이후 blue라면 green으로, green이라면 blue로 스위칭할 SWITCH 포트 변수에 값을 채워준다.
  • 프록시 방향을 변경하고 나서는 위와 마찬가지로 nginx를 reload 한다.

 

🤔 nginx reload 테스트

  • 이 그림을 다시 보자.

 

  • 위의 SWITCH_SCRIPT는 이 부분에 해당되는 것인데 문득 의문이 들었다.
  • 지금 내가 하는 배포 방식은 과연 100% 무중단 배포라고 할 수 있을까?
    • blue에서 green으로, green에서 blue로 nginx 프록시 방향을 변경하고 nginx reload 하는 순간 nginx는 찰나의 순간이지만 분명 중단될 것이다.
    • 즉, reload 되는 순간 요청이 들어온다면 그 요청은 처리 못하는 게 아닐까?
  • 그래서 실험해 봤다.

 

  • 스프링부트 프로젝트 내에 nginx_test.sh와 count_line이라는 파일을 생성했다.

 

📌 nginx_test.sh

count = 0

while true
do
count=$((count+1))
profile=$(curl -s http://localhost:28080/profile | head -n 1)
current_time=$(date "+%Y-%m-%d %H:%M:%S")
echo "Profile : $profile | Count: $count | Time: $current_time"
done
  • 위와 같이 작성한다.
  • 테스트 방식은 간단하다.
    • 매 반복마다 현재 Nginx가 바라보고 있는 스프링부트 서버의 프로필이 출력하고, nginx가 reload 되고 blue로 바뀌는 순간 얼마나 중단이 지속되는지를 테스트하는 것이다.
    • 반복문 조건을 true로 설정하여 무한 반복한다.
    • 반복문은 curl 명령어로 담신 profile을 가지고 있다가 "프로필 | 반복문 횟수 | 초단위 현재시간을 매번 출력할 것이다.
    • deploy.sh 파일을 로컬에서 실행한다.
    • nginx 배포 스크립트가 종료되어 프록시 방향이 변경되면 ctrl + c로 nginx_test.sh를 종료시킨다.
    • 이후 출력된 내용에서 1초 안에 보내진 요청을 잘라 count_line.txt에 붙여 넣고 1초 안에 몇 번 중단되는지를 확인한다.

 

실험 결과

Profile : blue | Count: 442 | Time: 2023-11-22 21:39:30
Profile : blue | Count: 443 | Time: 2023-11-22 21:39:30
Profile : blue | Count: 444 | Time: 2023-11-22 21:39:30
Profile : blue | Count: 445 | Time: 2023-11-22 21:39:30
Profile : blue | Count: 446 | Time: 2023-11-22 21:39:30
Profile : blue | Count: 447 | Time: 2023-11-22 21:39:30
Profile : blue | Count: 448 | Time: 2023-11-22 21:39:30
Profile : blue | Count: 449 | Time: 2023-11-22 21:39:30
Profile : blue | Count: 450 | Time: 2023-11-22 21:39:30
Profile : blue | Count: 451 | Time: 2023-11-22 21:39:30
Profile : blue | Count: 452 | Time: 2023-11-22 21:39:30
Profile : blue | Count: 453 | Time: 2023-11-22 21:39:30
Profile : blue | Count: 454 | Time: 2023-11-22 21:39:30
Profile : blue | Count: 455 | Time: 2023-11-22 21:39:30
Profile : blue | Count: 456 | Time: 2023-11-22 21:39:30
Profile : blue | Count: 457 | Time: 2023-11-22 21:39:30
Profile : blue | Count: 458 | Time: 2023-11-22 21:39:30
Profile : blue | Count: 459 | Time: 2023-11-22 21:39:30
Profile : <!DOCTYPE html> | Count: 460 | Time: 2023-11-22 21:39:30
Profile : green | Count: 461 | Time: 2023-11-22 21:39:30
Profile : green | Count: 462 | Time: 2023-11-22 21:39:30
Profile : green | Count: 463 | Time: 2023-11-22 21:39:30
Profile : green | Count: 464 | Time: 2023-11-22 21:39:30
Profile : green | Count: 465 | Time: 2023-11-22 21:39:30
Profile : green | Count: 466 | Time: 2023-11-22 21:39:30
Profile : green | Count: 467 | Time: 2023-11-22 21:39:30
Profile : green | Count: 468 | Time: 2023-11-22 21:39:30
Profile : green | Count: 469 | Time: 2023-11-22 21:39:30
Profile : green | Count: 470 | Time: 2023-11-22 21:39:30
Profile : green | Count: 471 | Time: 2023-11-22 21:39:30
Profile : green | Count: 472 | Time: 2023-11-22 21:39:30
Profile : green | Count: 473 | Time: 2023-11-22 21:39:30
Profile : green | Count: 474 | Time: 2023-11-22 21:39:30
Profile : green | Count: 475 | Time: 2023-11-22 21:39:30
Profile : green | Count: 476 | Time: 2023-11-22 21:39:30
Profile : green | Count: 477 | Time: 2023-11-22 21:39:30
Profile : green | Count: 478 | Time: 2023-11-22 21:39:30
Profile : green | Count: 479 | Time: 2023-11-22 21:39:30
Profile : green | Count: 480 | Time: 2023-11-22 21:39:30
Profile : green | Count: 481 | Time: 2023-11-22 21:39:30
Profile : green | Count: 482 | Time: 2023-11-22 21:39:30
Profile : green | Count: 483 | Time: 2023-11-22 21:39:30
Profile : green | Count: 484 | Time: 2023-11-22 21:39:30
Profile : green | Count: 485 | Time: 2023-11-22 21:39:30
Profile : green | Count: 486 | Time: 2023-11-22 21:39:30
Profile : green | Count: 487 | Time: 2023-11-22 21:39:30
Profile : green | Count: 488 | Time: 2023-11-22 21:39:30
Profile : green | Count: 489 | Time: 2023-11-22 21:39:30
Profile : green | Count: 490 | Time: 2023-11-22 21:39:30
Profile : green | Count: 491 | Time: 2023-11-22 21:39:30
Profile : green | Count: 492 | Time: 2023-11-22 21:39:30
Profile : green | Count: 493 | Time: 2023-11-22 21:39:30
Profile : green | Count: 494 | Time: 2023-11-22 21:39:30
Profile : green | Count: 495 | Time: 2023-11-22 21:39:30
Profile : green | Count: 496 | Time: 2023-11-22 21:39:30
Profile : green | Count: 497 | Time: 2023-11-22 21:39:30
Profile : green | Count: 498 | Time: 2023-11-22 21:39:30
Profile : green | Count: 499 | Time: 2023-11-22 21:39:30
Profile : green | Count: 500 | Time: 2023-11-22 21:39:30
Profile : green | Count: 501 | Time: 2023-11-22 21:39:30
Profile : green | Count: 502 | Time: 2023-11-22 21:39:30
Profile : green | Count: 503 | Time: 2023-11-22 21:39:30
Profile : green | Count: 504 | Time: 2023-11-22 21:39:30
Profile : green | Count: 505 | Time: 2023-11-22 21:39:30
Profile : green | Count: 506 | Time: 2023-11-22 21:39:30
Profile : green | Count: 507 | Time: 2023-11-22 21:39:30
Profile : green | Count: 508 | Time: 2023-11-22 21:39:30
Profile : green | Count: 509 | Time: 2023-11-22 21:39:30
Profile : green | Count: 510 | Time: 2023-11-22 21:39:30
Profile : green | Count: 511 | Time: 2023-11-22 21:39:30
Profile : green | Count: 512 | Time: 2023-11-22 21:39:30
Profile : green | Count: 513 | Time: 2023-11-22 21:39:30
Profile : green | Count: 514 | Time: 2023-11-22 21:39:30
Profile : green | Count: 515 | Time: 2023-11-22 21:39:30
Profile : green | Count: 516 | Time: 2023-11-22 21:39:30
Profile : green | Count: 517 | Time: 2023-11-22 21:39:30
Profile : green | Count: 518 | Time: 2023-11-22 21:39:30
Profile : green | Count: 519 | Time: 2023-11-22 21:39:30
Profile : green | Count: 520 | Time: 2023-11-22 21:39:30
Profile : green | Count: 521 | Time: 2023-11-22 21:39:30
Profile : green | Count: 522 | Time: 2023-11-22 21:39:30
Profile : green | Count: 523 | Time: 2023-11-22 21:39:30
Profile : green | Count: 524 | Time: 2023-11-22 21:39:30
Profile : green | Count: 525 | Time: 2023-11-22 21:39:30
Profile : green | Count: 526 | Time: 2023-11-22 21:39:30
Profile : green | Count: 527 | Time: 2023-11-22 21:39:30
Profile : green | Count: 528 | Time: 2023-11-22 21:39:30
Profile : green | Count: 529 | Time: 2023-11-22 21:39:30
Profile : green | Count: 530 | Time: 2023-11-22 21:39:30
Profile : green | Count: 531 | Time: 2023-11-22 21:39:30
Profile : green | Count: 532 | Time: 2023-11-22 21:39:30
Profile : green | Count: 533 | Time: 2023-11-22 21:39:30
Profile : green | Count: 534 | Time: 2023-11-22 21:39:30
Profile : green | Count: 535 | Time: 2023-11-22 21:39:30
Profile : green | Count: 536 | Time: 2023-11-22 21:39:30
Profile : green | Count: 537 | Time: 2023-11-22 21:39:30
Profile : green | Count: 538 | Time: 2023-11-22 21:39:30
Profile : green | Count: 539 | Time: 2023-11-22 21:39:30
Profile : green | Count: 540 | Time: 2023-11-22 21:39:30
Profile : green | Count: 541 | Time: 2023-11-22 21:39:30
Profile : green | Count: 542 | Time: 2023-11-22 21:39:30
Profile : green | Count: 543 | Time: 2023-11-22 21:39:30
Profile : green | Count: 544 | Time: 2023-11-22 21:39:30
Profile : green | Count: 545 | Time: 2023-11-22 21:39:30
Profile : green | Count: 546 | Time: 2023-11-22 21:39:30
Profile : green | Count: 547 | Time: 2023-11-22 21:39:30
Profile : green | Count: 548 | Time: 2023-11-22 21:39:30
Profile : green | Count: 549 | Time: 2023-11-22 21:39:30
Profile : green | Count: 550 | Time: 2023-11-22 21:39:30
Profile : green | Count: 551 | Time: 2023-11-22 21:39:30
Profile : green | Count: 552 | Time: 2023-11-22 21:39:30
Profile : green | Count: 553 | Time: 2023-11-22 21:39:30
Profile : green | Count: 554 | Time: 2023-11-22 21:39:30
Profile : green | Count: 555 | Time: 2023-11-22 21:39:30
  • 21시 39분 30초 00에서 31초가 되기 전까지 총 114번의 curl 명령어를 실행을 했고 그중에 딱 한 번 중단이 되었다.
  • 중단되는 순간은 0.01초도 안 되는 것 같다. 
    • 100% 무중단은 아니지만 거의 무중단이라고 볼 수 있지 않을까?
    • 이마저도 완벽히 하고 싶다면 nginx가 중단될 때 요청을 가지고 있다가 연결되면 보낸다는 설정을 nginx에 추가하는 기능이 있지 않을까 생각한다. 이건 나중에 nginx를 제대로 공부할 때 알아봐야겠다.

 

📜 정리

  • 배포 스크립트 파일이 작성이 끝났다.
  • 스크립트 파일을 작성하며 들었던 "서비스가 중단되는 순간이 어느 정도일까?"에 대한 의문도 간단한 테스트로 어느정도 해결되었다.
  • 이제 가장 생소한 작업이었던 Groovy를 사용하여 젠킨스 파일을 작성하는 단계만 남았다.
  • 다음 글에 계속된다.

 

 

 

참고

뤼튼

https://hudi.blog/zero-downtime-deployment-with-jenkins-and-nginx/

https://hyunminh.github.io/nonstop-deploy/

https://iizz.tistory.com/341

 

 

 

 

728x90