DevOps/CI&CD

๋ฌด์ค‘๋‹จ ๋ฐฐํฌ ์‹ค์Šต - ๋ธ”๋ฃจ๊ทธ๋ฆฐ ์ „๋žต

ํ”„๋กœ๊ทธ๋ž˜๋จธ ์˜ค์›” 2024. 8. 18.

์•ž์„œ ์‹ค์Šต ๋ ˆํฌ์ง€ํ† ๋ฆฌ์™€ ํ™˜๊ฒฝ ์…‹ํŒ…์„ ์ง„ํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค.

๋ชป ๋ณด์‹  ๋ถ„๋“ค์ด ๊ณ„์‹œ๋‹ค๋ฉด ๋จผ์ € ์ด ํฌ์ŠคํŒ…์„ ๋ณด๊ณ , ๋ฌด์ค‘๋‹จ ๋ฐฐํฌ ์‹ค์Šต์„ ์ง„ํ–‰ํ•ด์ฃผ์„ธ์š”.

 

https://programmer-may.tistory.com/213

 

๋ฌด์ค‘๋‹จ ๋ฐฐํฌ ์‹ค์Šต ๊ธฐ๋ณธ ์…‹ํŒ… (Github Actions, Nginx ํ™œ์šฉ)

๋ฌด์ค‘๋‹จ ๋ฐฐํฌ ์ด๋ก ์— ๋Œ€ํ•ด์„œ ํ•™์Šต์„ ํ•˜์˜€๊ณ , ๋ฌด์ค‘๋‹จ ๋ฐฐํฌ๋ฅผ ์ด์   ์‹ค์Šตํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด๋ก ์— ๊ด€ํ•ด์„œ๋Š” ์•„๋ž˜ ํฌ์ŠคํŒ…์„ ์ฐธ๊ณ  ํ•ด์ฃผ์„ธ์š”.https://programmer-may.tistory.com/209 ๋ฌด์ค‘๋‹จ ๋ฐฐํฌ(Zero-downtime Deployment

programmer-may.tistory.com

 

๋ธ”๋ฃจ ๊ทธ๋ฆฐ ์ „๋žต

๋ธ”๋ฃจ ๊ทธ๋ฆฐ ์ „๋žต(Blue-Green Deployment)์€ ๋‘ ๊ฐœ์˜ ๋™์ผํ•œ ํ™˜๊ฒฝ(๋ธ”๋ฃจ ํ™˜๊ฒฝ๊ณผ ๊ทธ๋ฆฐ ํ™˜๊ฒฝ)์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐฐํฌํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ๋ธ”๋ฃจ ํ™˜๊ฒฝ์—์„œ ํ˜„์žฌ ์šด์˜ ์ค‘์ธ ๋ฒ„์ „์„ ์‹คํ–‰ํ•˜๊ณ , ๊ทธ๋ฆฐ ํ™˜๊ฒฝ์—์„œ ์ƒˆ๋กœ์šด ๋ฒ„์ „์„ ๋ฐฐํฌํ•ฉ๋‹ˆ๋‹ค. ์ƒˆ๋กœ์šด ๋ฒ„์ „์ด ์ค€๋น„๋˜๋ฉด ํŠธ๋ž˜ํ”ฝ์„ ๋ธ”๋ฃจ ํ™˜๊ฒฝ์—์„œ ๋ชจ๋‘ ํ•œ๋ฒˆ์— ๊ทธ๋ฆฐ ํ™˜๊ฒฝ์œผ๋กœ ์ „ํ™˜ํ•˜์—ฌ ๋ฐฐํฌ๋ฅผ ์™„๋ฃŒํ•ฉ๋‹ˆ๋‹ค.

๋ฐฐํฌ๊ฐ€ ์™„๋ฃŒ๋œ ํ›„ ๊ธฐ์กด ๊ตฌ ๋ฒ„์ „์ด ์žˆ๋˜ ํ™˜๊ฒฝ์€ ๋‹ค์Œ ๋ฐฐํฌ๋ฅผ ์œ„ํ•ด ์žฌ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

bluegreen_before ๋ธŒ๋žœ์น˜

๋ธ”๋ฃจ๊ทธ๋ฆฐ ๋ฌด์ค‘๋‹จ ๋ฐฐํฌ ์ „๋žต ๋„์ž… ์ „ ํ™˜๊ฒฝ์„ ๊ตฌ์ถ•ํ•ฉ๋‹ˆ๋‹ค. cd-bluegreen.yml ํŒŒ์ผ์„ ํ†ตํ•ด JAR ํŒŒ์ผ์„ ์—…๋กœ๋“œํ•˜๊ณ , ์ด์ „ ํ”„๋กœ์„ธ์Šค๋ฅผ ์ฃฝ์ด๊ณ  JAR ํŒŒ์ผ์„ 8081ํฌํŠธ์—์„œ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ณผ์ •์—์„œ ๋‹ค์šด ํƒ€์ž„์ด ๋ฐœ์ƒํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

bluegreen_after ๋ธŒ๋žœ์น˜

๋ธ”๋ฃจ๊ทธ๋ฆฐ ์ „๋žต ๋„์ž…ํ•˜์—ฌ ๋ฌด์ค‘๋‹จ ๋ฐฐํฌ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. cd-bluegreen.yml ํŒŒ์ผ์„ ํ†ตํ•ด deploy.sh ํŒŒ์ผ์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

 

deploy.sh ์…‹ํŒ…

๋จผ์ € Termius ์ผœ์„œ EC2 ์— ์›๊ฒฉ์ ‘์†์„ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

ํ•ด๋‹น ๋””๋ ‰ํ† ๋ฆฌ์— ๋ฐฐํฌ์šฉ ์‰˜ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๊ฒฝ๋กœ์˜ ๊ธ€์ž๊ฐ€ ํ‹€๋ฆฌ์ง€ ์•Š๊ฒŒ ์กฐ์‹ฌํ•ด์ฃผ์„ธ์š”.

$ sudo nano /home/ubuntu/cicd/bluegreen/deploy.sh

 

ํ•ด๋‹น ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋ณต๋ถ™ํ•ด์„œ ๋„ฃ์–ด์ค๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ๊ฒƒ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๊ณณ์—์„œ zeroDownTimeDeployment ๋Œ€ํ•œ jar ํŒŒ์ผ ๋ช…์„ ๋ณ€๊ฒฝํ•ด์ค˜์•ผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ”„๋กœ์ ํŠธ๋ฅผ ์ง์ ‘ ์ƒ์„ฑํ•ด์„œ ๋”ฐ๋ผํ•˜์‹œ๋Š” ๋ถ„์ด๋‚˜ rootProject.name ์ด ๋‹ค๋ฅธ ์‚ฌ๋žŒ์€ ๋นŒ๋“œํ–ˆ์„ ๋•Œ ๋‹ค๋ฅธ ์ด๋ฆ„์˜ jar ํŒŒ์ผ์ด ์ƒ๊ธฐ๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ถ€๋ถ„์„ ๋งž๊ฒŒ ๋ฐ”๊ฟ”์ค˜์•ผํ•ฉ๋‹ˆ๋‹ค.

 

 

๋ณธ์ธ์˜ ํ”„๋กœ์ ํŠธ์˜ settings.gradle ์˜ rootProject.name ๊ฐ’์„ zeroDownTimeDeployment ๋Œ€์‹  ๋„ฃ์–ด ์ค๋‹ˆ๋‹ค.
๋’ค์— -*.jar ๋Š” ๊ทธ๋Œ€๋กœ ์œ ์ง€ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ๋นŒ๋“œ์‹œ rootProject.name -๋ฒ„์ „-SNAPSHOT.jar ๋กœ jar ํŒŒ์ผ์ด ๋งŒ๋“ค์–ด์ง€๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

 

#!/bin/bash

# ํ˜„์žฌ ์‹คํ–‰ ์ค‘์ธ Spring Boot ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํฌํŠธ ์‹๋ณ„
CURRENT_PORT=$(sudo ss -tulnp | grep java | awk '{print $5}' | grep -o '[0-9]*$')
echo "Current port is: $CURRENT_PORT"

# ๊ธฐ๋ณธ ํฌํŠธ ์„ค์ •
PORT1=8081
PORT2=8082
NEW_PORT=0

# ํ˜„์žฌ ํฌํŠธ์— ๋”ฐ๋ผ ์ƒˆ ํฌํŠธ ๊ฒฐ์ •
if [ -z "$CURRENT_PORT" ]; then
    # ์‹คํ–‰ ์ค‘์ธ ํฌํŠธ๊ฐ€ ์—†์œผ๋ฉด ๊ธฐ๋ณธ ํฌํŠธ ์‚ฌ์šฉ
    NEW_PORT=$PORT1
elif [ "$CURRENT_PORT" -eq "$PORT1" ]; then
    NEW_PORT=$PORT2
else
    NEW_PORT=$PORT1
fi

echo "Deploying new application on port: $NEW_PORT"

# ๊ธฐ์กด์˜ app.jar ํŒŒ์ผ์„ old_build ๋””๋ ‰ํ† ๋ฆฌ๋กœ ์ด๋™
TIMESTAMP=$(date +"%Y%m%d%H%M%S")
if [ -f /home/ubuntu/cicd/app.jar ]; then
    mv /home/ubuntu/cicd/app.jar /home/ubuntu/cicd/old_build/$TIMESTAMP.jar
fi

# ์ƒˆ๋กœ ๋ฐฐํฌ๋œ .jar ํŒŒ์ผ์„ app.jar๋กœ ์ด๋ฆ„ ๋ณ€๊ฒฝ
NEW_JAR=$(ls /home/ubuntu/cicd/zeroDownTimeDeployment-*.jar | head -n 1)
mv $NEW_JAR /home/ubuntu/cicd/app.jar

# ์ƒˆ๋กœ ๋ฐฐํฌ๋œ app.jar ํŒŒ์ผ ์‹คํ–‰
sudo chmod +x /home/ubuntu/cicd/app.jar
sudo nohup java -jar -Dserver.port=$NEW_PORT /home/ubuntu/cicd/app.jar > /home/ubuntu/console.log 2>&1 &

sleep 10
# ์ƒˆ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ •์ƒ์ ์œผ๋กœ ์‹คํ–‰๋˜์—ˆ๋Š”์ง€ ํ™•์ธ
CHECK_URL=http://localhost:$NEW_PORT/actuator/health
RETRY_COUNT=0
MAX_RETRY=10

until $(curl --output /dev/null --silent --head --fail $CHECK_URL); do
    sleep 5
    if [ ${RETRY_COUNT} -eq ${MAX_RETRY} ]; then
        echo "New application failed to start. Deployment aborted."
        
        # ํ—ฌ์Šค ์ฒดํฌ ์‹คํŒจ ์‹œ $NEW_PORT์—์„œ ์‹คํ–‰ ์ค‘์ธ ํ”„๋กœ์„ธ์Šค๋ฅผ ๊ฐ•์ œ ์ข…๋ฃŒ
        NEW_PID=$(lsof -t -i:$NEW_PORT)
        if [ -n "$NEW_PID" ]; then
            echo "Terminating process on port $NEW_PORT with PID $NEW_PID"
            sudo kill -9 $NEW_PID
        fi

        exit 1
    fi
    RETRY_COUNT=$((RETRY_COUNT+1))
done

# Nginx ์„ค์ • ํŒŒ์ผ์—์„œ proxy_pass ๋™์ ์œผ๋กœ ๋ณ€๊ฒฝ
NGINX_CONFIG="/etc/nginx/sites-available/default"
NEW_PROXY_PASS="proxy_pass http://127.0.0.1:$NEW_PORT;"

# listen 80๋ฒˆ ํฌํŠธ์˜ location / ๋ธ”๋ก ๋‚ด์—์„œ proxy_pass ์ค„๋งŒ ๋ณ€๊ฒฝ
sudo sed -i '/location \/ {/!b;n;s|proxy_pass http://127.0.0.1:.*;|'"$NEW_PROXY_PASS"'|' $NGINX_CONFIG

# sed ๋ช…๋ น์–ด๊ฐ€ ์„ฑ๊ณตํ–ˆ๋Š”์ง€ ํ™•์ธ
if [ $? -ne 0 ]; then
    echo "Error: Failed to update Nginx config."
    exit 1
fi

# Nginx ์„ค์ • ์žฌ๋กœ๋“œ
sudo service nginx reload

# ์ด์ „ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ข…๋ฃŒ
OLD_PID=$(lsof -t -i:$CURRENT_PORT)
if [ -n "$OLD_PID" ]; then
  sudo kill -15 $OLD_PID
  sleep 7
  # ํ”„๋กœ์„ธ์Šค๊ฐ€ ์—ฌ์ „ํžˆ ์ข…๋ฃŒ๋˜์ง€ ์•Š์•˜๋Š”์ง€ ํ™•์ธํ•˜๊ณ , ๊ฐ•์ œ ์ข…๋ฃŒ ์‹œ๋„
  if sudo kill -0 $OLD_PID 2>/dev/null; then
    echo "Process $OLD_PID did not terminate, killing with -9"
    sudo kill -9 $OLD_PID
  fi
fi

echo "Deployment complete. Nginx is routing traffic to port $NEW_PORT."

 

๋ณต๋ถ™์ด ์™„๋ฃŒ ๋๋‹ค๋ฉด, ctrl + o ๋ฅผ ์ž…๋ ฅํ•˜๊ณ  ์—”ํŠธ๋ฅผ ๋ˆŒ๋Ÿฌ์„œ ์ €์žฅํ•ด ์ค๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ctrl + x ๋ฅผ ๋ˆŒ๋Ÿฌ์„œ ํŽธ์ง‘๊ธฐ์—์„œ ๋‚˜๊ฐ‘๋‹ˆ๋‹ค.

 

Nginx ์„ค์ • ์…‹ํŒ…

์ €๋ฒˆ ํฌ์ŠคํŒ…์—์„œ ์—”์ง„์—‘์Šค์˜ ์„ค์ •์„ ๋ฐ”๊ฟจ๋‹ค๋ฉด ์ƒ๊ด€์ด ์—†๊ฒ ์ง€๋งŒ ๊ทธ๋ž˜๋„ ํ™•์ธํ•ด์ฃผ๊ฒ ์Šต๋‹ˆ๋‹ค.

 

$ sudo nano /etc/nginx/sites-available/default

 

์ž…๋ ฅํ•˜์—ฌ ํŽธ์ง‘๊ธฐ๊ฐ€ ๋‚˜์™”์„ ๋•Œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋‚˜์˜ค๋ฉด ๋ฉ๋‹ˆ๋‹ค.

server {
    listen 80;
    server_name _;

    location / {
        proxy_pass http://127.0.0.1:8081;  # ์ด ๋ถ€๋ถ„์€ deploy.sh์—์„œ ๋™์ ์œผ๋กœ ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค.
        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;
    }
}

 

 

bluegreen_ver1 ์…‹ํŒ…

bluegreen_ver1 ๋ธŒ๋žœ์น˜๋กœ checkout ํ•ด์ค๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ํ„ฐ๋ฏธ๋„์„ ์ผœ์„œ git pull origin bluegreen ์ž…๋ ฅํ•˜์—ฌ ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ํ•ด๋‹น ๋ธŒ๋žœ์น˜์— ๋ฐ˜์˜ํ•ด์ค๋‹ˆ๋‹ค.

๋งŒ์•ฝ ์ œ ๋ ˆํฌ์ง€ํ† ๋ฆฌ๋ฅผ fork ํ•ด์„œ ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋ ˆํฌ์ง€ํ† ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•ด์„œ ๋”ฐ๋ผํ•˜์‹œ๋Š” ๋ถ„์ด๋ฉด, main ๋ธŒ๋žœ์น˜ ๋‚ด์šฉ์„ main ๋ธŒ๋žœ์น˜ ๋ณต๋ถ™ ํ•ด์„œ ํ‘ธ์‹œํ•˜๊ณ , ๊นƒํ—ˆ๋ธŒ์—์„œ main ๋ธŒ๋žœ์น˜๋ฅผ ๋ณธ๋”ฐ bluegreen, rolling, canary ๋ธŒ๋žœ์น˜๋ฅผ ๋งŒ๋“œ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

๋งŒ์•ฝ ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ์—†์–ด์„œ bluegreen_ver1 ๋ธŒ๋žœ์น˜ bluegreen๋ธŒ๋žœ์น˜์— ํ’€๋ฆฌํ€˜๋ฅผ ๋ณด๋‚ผ ์ˆ˜ ์—†์„ ์ˆ˜๋„ ์žˆ๊ธฐ์— ์ˆ˜์ •์‚ฌํ•ญ์„ ๋งŒ๋“ค์–ด ์ค๋‹ˆ๋‹ค.

 

TestController ์—์„œ ๋ณ€ํ™”๋ฅผ ์ฃผ๋Š” ๊ฑธ ์ถ”์ฒœ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

์ „ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„ค์ •ํ•˜์—ฌ ๊ธฐ๋ณธ๊ฐ’์„ ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค. 

@RestController
public class TestController {
    private static final String RESPONSE_BODY_MESSAGE = "๋ฒ„์ „ 1 ์‘๋‹ต๊ฐ’์ž…๋‹ˆ๋‹ค. ๋ฌด์ค‘๋‹จ ๋ฐฐํฌ๋ฅผ ๋„์ž… ์ „์ž…๋‹ˆ๋‹ค.";
    @GetMapping("/hello")
    public ResponseEntity test() {
        return ResponseEntity.ok(RESPONSE_BODY_MESSAGE);
    }
}

 

์ˆ˜์ •์„ ํ• ๋•Œ ๊ตฌ๊ธ€ ์ž๋ฐ” ์ปจ๋ฒค์…˜์„ ci ์ฒดํฌ์Šคํƒ€์ผ ์„ค์ •ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ํ•œ์ค„์— 100๊ธ€์ž๊ฐ€ ๋„˜์–ด๊ฐ€์ง€ ์•Š๋„๋ก ์กฐ์‹ฌํ•ด์ฃผ์„ธ์š”! ํ˜„์žฌ ๊ธฐ๋ณธ ์ƒํƒœ๋„ ๊ฑฐ์˜ 99์ž 98์ž ๋˜๋Š” ๊ฑฐ ๊ฐ™๋„ค์š”. ํฐ์ƒ‰ ์ค„์ด 100๊ธ€์ž ํ‘œ์‹œ ์„ ์ž…๋‹ˆ๋‹ค.

 

๊ทธ๋ฆฌ๊ณ  cd-bluegreen.yml ํŒŒ์ผ์„ ํ™•์ธํ•ด์ค๋‹ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด jarํŒŒ์ผ์„ ์—…๋กœ๋“œ ํ•˜๊ณ  ์‹คํ–‰ํ•˜๋Š” ๋ช…๋ น์–ด๋กœ ๋˜์–ด ์žˆ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ๋‚ด์šฉ์ด ๋‹ค๋ฅด๋‹ค๋ฉด ๋ณต๋ถ™์„ ํ•˜์—ฌ์ค๋‹ˆ๋‹ค.

name: Build and Deploy

on:
  push:
    branches:
      - bluegreen

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'temurin'
      - name: application.yml
        run: |
          mkdir -p src/main/resources
          touch ./src/main/resources/application.yml
          echo "${{ secrets.APPLICATION_YML }}" > ./src/main/resources/application.yml
          cat ./src/main/resources/application.yml
      - name: Run chmod to make gradlew executable
        run: chmod +x ./gradlew

      - name: Build with Gradle
        uses: gradle/gradle-build-action@bd5760595778326ba7f1441bcf7e88b49de61a25 # v2.6.0
        with:
          arguments: build

      - name: Upload artifact
        uses: actions/upload-artifact@v2
        with:
          name: build-file
          path: build/libs/*.jar

  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Download artifact
        uses: actions/download-artifact@v2
        with:
          name: build-file

      - name: Setup SSH
        uses: webfactory/ssh-agent@v0.5.4
        with:
          ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}

      - name: Add remote server to known hosts
        run: |
          mkdir -p ~/.ssh
          ssh-keyscan ${{ secrets.SERVER_IP }} >> ~/.ssh/known_hosts
      - name: Rename and transfer artifact
        run: |
          mv *.jar app.jar
          scp app.jar ${{ secrets.SERVER_USERNAME }}@${{ secrets.SERVER_IP }}:~/cicd/
      - name: Execute remote commands
        run: |
          ssh -v ${{ secrets.SERVER_USERNAME }}@${{ secrets.SERVER_IP }} "sudo fuser -k 8081/tcp || true"
          ssh -v ${{ secrets.SERVER_USERNAME }}@${{ secrets.SERVER_IP }} "sudo fuser -k 8082/tcp || true"
          ssh -v ${{ secrets.SERVER_USERNAME }}@${{ secrets.SERVER_IP }} "sudo nohup /usr/bin/java -jar -Dserver.port=8081 ~/cicd/app.jar > ~/cicd/nohup.log 2>&1 &"

 

์ˆ˜์ • ํ›„ ์ปค๋ฐ‹ํ•˜๊ณ  ํ‘ธ์‹œ ํ•ด์ค๋‹ˆ๋‹ค.

 

Pull request ์ƒ์„ฑ

๊นƒํ—ˆ๋ธŒ์— ํ’€๋ฆฌํ€˜๋ฅผ ๋ณด๋ƒ…๋‹ˆ๋‹ค.

base ๋Š” bluegreen์ด๊ณ  compare ์€ bluegreen_ver1 ์ด์—ฌ์•ผ ํ•˜๋Š” ๊ฑธ ๊ผญ ํ™•์ธํ•ด์ฃผ์„ธ์š”. ๋””ํดํŠธ ๋ธŒ๋žœ์น˜๊ฐ€ main ์œผ๋กœ ๋˜์–ด ์žˆ์–ด์„œ base๊ฐ€ main์œผ๋กœ ๋˜์–ด ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ผญ ์ˆ˜์ •ํ•ด์ค˜์•ผํ•ฉ๋‹ˆ๋‹ค. bluegreen ์— ํ‘ธ์‹œ ๋˜์–ด์•ผ ๊นƒํ—ˆ๋ธŒ ์•ก์…˜์Šค๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

์ฒดํฌ ์Šคํƒ€์ผ ํ…Œ์ŠคํŠธ์™€ ๋นŒ๋“œ ํ…Œ์ŠคํŠธ๋ฅผ ํ†ต๊ณผํ•˜๊ฒŒ ๋˜๋ฉด merge pull reqeust ํ•ด์ค๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋ฉด Actions ์— ๋“ค์–ด๊ฐ€๋ฉด ๋ฐฐํฌ๊ฐ€ ์ง„ํ–‰๋˜๊ณ  ์žˆ๋Š” ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

์ด๋ ‡๊ฒŒ ๋˜๋ฉด ๋ฐฐํฌ๊ฐ€ ์™„๋ฃŒ๋œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. 

ํฌ์ŠคํŠธ๋งจ์„ ํ†ตํ•ด์„œ {http://EC2 ํผ๋ธ”๋ฆญ IP/hello} ์š”์ฒญ์„ ๋ณด๋‚ด๋ฉด ๋ฌด์ค‘๋‹จ ๋ฐฐํฌ ์ „์ด๋ผ๋Š” ๋ง๊ณผ 8081 ํฌํŠธ์—์„œ ์‹คํ–‰ ์ค‘์ธ ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

bluegreen_ver2 ์…‹ํŒ…

blueegreen_ver2 ๋ธŒ๋žœ์น˜๋กœ checkout ํ•ด์ค๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  git pull origin bluegreen ํ•˜์—ฌ ๋ณ€๊ฒฝ์ ์„ ์ตœ์‹ ํ™” ํ•ด์ค๋‹ˆ๋‹ค. 

ver2 ๋Š” ๋ฌด์ค‘๋‹จ ๋ฐฐํฌ ๋„์ž… ๋ฒ„์ „์ด๋‹ˆ๊น, ๊ทธ์— ๋งž๊ฒŒ ์ˆ˜์ •์„ ํ•ด์ค„ ๊ฒ๋‹ˆ๋‹ค.

๋จผ์ € ์‘๋‹ต๊ฐ’์„ ์ˆ˜์ •ํ•ด์ฃผ๊ฒ ์Šต๋‹ˆ๋‹ค.

 

์ด๋ ‡๊ฒŒ ๋ฒ„์ „2์ด๋ผ๋Š” ๊ฑธ ํ™•์‹คํ•˜๊ฒŒ ๋ช…์‹œํ•ด์คฌ์Šต๋‹ˆ๋‹ค.

 

๊ทธ๋ฆฌ๊ณ  ์ œ์ผ ์ค‘์š”ํ•œ cd-bluegreen.yml ์„ ์ˆ˜์ •ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

jar ํŒŒ์ผ์„ ์—…๋กœ๋“œํ•˜๊ณ  ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ, cicd/bluegreen/ ๋””๋ ‰ํ† ๋ฆฌ์— ์žˆ๋Š” deploy.sh ์‰˜ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰์‹œ์ผœ์ค„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

 

name: Build and Deploy

on:
  push:
    branches:
      - bluegreen

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'temurin'
      - name: application.yml
        run: |
          mkdir -p src/main/resources
          touch ./src/main/resources/application.yml
          echo "${{ secrets.APPLICATION_YML }}" > ./src/main/resources/application.yml
          cat ./src/main/resources/application.yml
      - name: Run chmod to make gradlew executable
        run: chmod +x ./gradlew

      - name: Build with Gradle
        uses: gradle/gradle-build-action@bd5760595778326ba7f1441bcf7e88b49de61a25 # v2.6.0
        with:
          arguments: build

      - name: Upload artifact
        uses: actions/upload-artifact@v2
        with:
          name: build-file
          path: build/libs/*.jar

  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Download artifact
        uses: actions/download-artifact@v2
        with:
          name: build-file

      - name: Setup SSH
        uses: webfactory/ssh-agent@v0.5.4
        with:
          ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}

      - name: Add remote server to known hosts
        run: |
          mkdir -p ~/.ssh
          ssh-keyscan ${{ secrets.SERVER_IP }} >> ~/.ssh/known_hosts

      - name: SCP transfer
        run: scp *.jar ${{ secrets.SERVER_USERNAME }}@${{ secrets.SERVER_IP }}:~/cicd

      - name: Execute remote command
        run: |
          ssh -v ${{ secrets.SERVER_USERNAME }}@${{ secrets.SERVER_IP }} "sudo chmod +x ~/cicd/bluegreen/deploy.sh"
          ssh -v ${{ secrets.SERVER_USERNAME }}@${{ secrets.SERVER_IP }} "sudo ~/cicd/bluegreen/deploy.sh"

 

 

์•„ํŒŒ์น˜ ์ œ์ด๋ฏธํ„ฐ ํ…Œ์ŠคํŠธ ์…‹ํŒ…

ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜์—ฌ ๋ชจ๋‹ˆํ„ฐ๋ง ํ•˜๊ณ  ์‹ถ์œผ์‹  ๋ถ„๋“ค์—๊ฒŒ ์ถ”์ฒœ๋“œ๋ฆฝ๋‹ˆ๋‹ค. 

๋งค ๊ฐ„๊ฒฉ๋งˆ๋‹ค HTTP ์š”์ฒญ์„ ๋ณด๋‚ด์„œ ์ •๋ง ๋‹ค์šด ํƒ€์ž„ ์—†์ด ๋ฐฐํฌ๊ฐ€ ์ง„ํ–‰๋˜๋Š”์ง€ ์‹ค์ œ๋กœ ๋ณด๊ธฐ ์œ„ํ•จ์ผ ๋ฟ์ž…๋‹ˆ๋‹ค.

 

๋จผ์ € Simple HTTP rquest ํ…œํ”Œ๋ฆฟ์„ ์ƒ์„ฑํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

 

 

HTTP ๋ฉ”์†Œ๋“œ์™€ URL ์„ ์ž…๋ ฅํ•ด์ค๋‹ˆ๋‹ค. URL์€ HTTP ํ”„๋กœํ† ์ฝœ๊ณผ ์ž์‹ ์˜ EC2 ํผ๋ธ”๋ฆญ IP ๋ฅผ ๋„ฃ์–ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 

์•„ํŒŒ์น˜ ์ œ์ด๋ฏธํ„ฐ์˜ ํ•ต์‹ฌ์€ ์“ฐ๋ ˆ๋“œ ๊ทธ๋ฃน ์„ค์ •์ž…๋‹ˆ๋‹ค. ๊ทผ๋ฐ ์ €ํฐ ์„ฑ๋Šฅ ํ…Œ์ŠคํŠธ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์‹ ๊ฒฝ์“ธ ๊ฑด ์•„๋‹ˆ๋ผ์„œ, ๋Œ€๋žต 7๋ถ„์„ ๊ธฐ์ค€์œผ๋กœ ์ ๋‹นํ•œ ์š”์ฒญ ๊ฐ„๊ฒฉ์„ ๋ณด๋‚ด๊ธฐ ์œ„ํ•ด Ramp-up ์‹œ๊ฐ„์€ 420 ์— ์‚ฌ์šฉ์ž ์ˆ˜๋ฅผ 200 ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

 

๊ทธ๋ฆฌ๊ณ  ๊ฒฐ๊ณผ๋ฅผ ๋ณด๊ธฐ ์œ„ํ•ด์„œ ๊ฒฐ๊ณผ ํŠธ๋ฆฌ ๋ณด๊ธฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ํ…Œ์ŠคํŠธ์—์„œ ์šฐํด๋ฆญํ•˜๋ฉด ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

์‹คํ–‰ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ํ…Œ์ŠคํŠธ๋ฅผ ํŒŒ์ผ๋กœ ์ €์žฅํ•˜๋ผ๋Š” ๋ง์ด ๋‚˜์˜ค๋Š”๋ฐ, ์ ๋‹นํ•œ ๊ฒฝ๋กœ์— ์›ํ•˜๋Š” ์ด๋ฆ„์œผ๋กœ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

pull request๋ฅผ ๋จธ์ง€ํ•˜๊ณ  ๋‚˜์„œ ํ…Œ์ŠคํŠธ๋ฅผ ์‹œ์ž‘ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. 

 

Pull request ์ƒ์„ฑ

๊นƒํ—ˆ๋ธŒ์— ํ’€๋ฆฌํ€˜๋ฅผ ๋ณด๋ƒ…๋‹ˆ๋‹ค.

base ๋Š” bluegreen์ด๊ณ  compare ์€ bluegreen_ver2 ์ด์—ฌ์•ผ ํ•˜๋Š” ๊ฑธ ๊ผญ ํ™•์ธํ•ด์ฃผ์„ธ์š”. ver1 ๋•Œ์™€ ๋˜‘๊ฐ™์Šต๋‹ˆ๋‹ค.

์ฒดํฌ์Šคํƒ€์ผ ํ…Œ์ŠคํŠธ ํ†ต๊ณผ์™€ ๋นŒ๋“œ ํ…Œ์ŠคํŠธ ํ†ต๊ณผ๋ฅผ ํ•˜๋ฉด merge pull request ํ•ด์ค๋‹ˆ๋‹ค. 

ํ‘ธ์‹œ ๋˜๊ณ  ๋‚˜์„œ ์•ก์…˜์Šค๊ฐ€ ๋Œ์•„๊ฐ€๋ฉด ์•„ํŒŒ์น˜ ์ œ์ด๋ฏธํ„ฐ์—์„œ ์ดˆ๋ก์ƒ‰ ์žฌ์ƒ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ์ค๋‹ˆ๋‹ค.

 

์•„ํŒŒ์น˜ ์ œ์ด๋ฏธํ„ฐ์—์„œ ๊ฒฐ๊ณผ๋ฅผ ํŠธ๋ฆฌ๋ณด๊ธฐ๋ฅผ ๋ˆŒ๋Ÿฌ๋ณด๋ฉด ๊ธฐ์กด์— ๋ฐฐํฌ๋œ ๋ฒ„์ „1๊ณผ 8081ํฌํŠธ์—์„œ ์‹คํ–‰๋˜๊ณ  ์žˆ๋Š” ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

 

๋ฐฐํฌ๊ฐ€ ์™„๋ฃŒ๋˜๊ณ  ๋‚˜์„ , ๋ฒ„์ „ 2 ์‘๋‹ต๊ฐ’๊ณผ ๋ฌด์ค‘๋‹จ ๋ฐฐํฌ๊ฐ€ ์ž˜ ๋„์ž… ๋œ ๊ฑธ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ‘œ๋ณธ ์ถ”์ถœ๊ธฐ ์˜†์— ์‘๋‹ต ๋ฐ์ดํ„ฐ ํƒญ์—์„œ ์‘๋‹ต body ์—์„œ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

 

8081 ์—์„œ ์‹คํ–‰๋˜๋Š” ๋ธ”๋ฃจ ์„œ๋ฒ„๊ฐ€ 8082 ์—์„œ ๊ทธ๋ฆฐ ์„œ๋ฒ„๋กœ ๋Œ€์ฒด๋˜๊ณ  ๊ตฌ๋ฒ„์ „์—์„œ ์‹ ๋ฒ„์ „์œผ๋กœ ๋‹ค์šดํƒ€์ž„ ์—†์ด ์ž˜ ๋ฐฐํฌ๋˜๋Š” ๊ฑธ ์‹ค์Šตํ•ด ๋ณผ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๋ธ”๋ฃจ๊ทธ๋ฆฐ ๋ฐฐํฌ ์ „๋žต์€ ์ƒˆ๋กœ์šด ๋ฒ„์ „์„ ๋ณ„๋„์˜ ํ™˜๊ฒฝ์— ๋ฐฐํฌํ•œ ํ›„, ํŠธ๋ž˜ํ”ฝ์„ ์ „ํ™˜ํ•˜์—ฌ ๋‹ค์šดํƒ€์ž„ ์—†์ด ๋ฐฐํฌ๋ฅผ ์™„๋ฃŒํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ์ด ์ „๋žต์˜ ์žฅ์ ์€ ๋ฐฐํฌ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ ๊ฐ„ํŽธํ•˜๊ฒŒ ์ด์ „ ๋ฒ„์ „์œผ๋กœ ๋กค๋ฐฑํ•  ์ˆ˜ ์žˆ์–ด ์•ˆ์ •์„ฑ์ด ๋†’๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋˜ํ•œ, ํŠธ๋ž˜ํ”ฝ ์ „ํ™˜์ด ๋น ๋ฅด๊ฒŒ ์ด๋ฃจ์–ด์ ธ ์„œ๋น„์Šค์˜ ์ค‘๋‹จ์ด ์—†๋‹ค๋Š” ์ ๋„ ๊ฐ•์ ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‹จ์ ์œผ๋กœ๋Š” ๋‘ ๊ฐœ์˜ ์™„์ „ํ•œ ์ธํ”„๋ผ๋ฅผ ์œ ์ง€ํ•ด์•ผ ํ•˜๋ฏ€๋กœ, ๋น„์šฉ์ด ์ฆ๊ฐ€ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋ณต์žกํ•œ ํ™˜๊ฒฝ ์„ค์ •์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ง€๊ธˆ ์‹ค์Šต์—์„  ์‹  ๋ฒ„์ „์ด ์ž˜ ๋ฐฐํฌ๋˜๋ฉด ๊ตฌ ๋ฒ„์ „์˜ ํ”„๋กœ์„ธ์Šค๋Š” ์•ˆ์ „ํ•˜๊ฒŒ kill ํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค. ์„ค์ •์ด ๋ณต์žกํ•˜๊ธด ํ•˜์ง€๋งŒ, ๋กค๋ง๊ณผ ์นด๋‚˜๋ฆฌ ์ „๋žต๋ณด๋‹ค๋Š” ๋ณต์žกํ•˜์ง€ ์•Š์€ ๊ฒƒ๋„ ์žฅ์ ์ด ๋  ์ˆ˜ ์žˆ์„ ๊ฑฐ ๊ฐ™์Šต๋‹ˆ๋‹ค.

ํฌ์ŠคํŠธ๋งจ์œผ๋กœ ๊ตฌ ๋ฒ„์ „์ด ๋Œ์•„๊ฐ€๋Š” ํฌํŠธ๋ฒˆํ˜ธ๋กœ ํ—ฌ์Šค ์š”์ฒญ์„ ๋ณด๋‚ด๋ฉด ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ž˜ ๋‚ด๋ ค๊ฐ„ ๊ฑธ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋Œ“๊ธ€