๋ค์ด๊ฐ๋ฉฐ
์ค๋ฌด์ ์ ์ฉํ๋ ํ๋ก์ ํธ๊ฐ ์๋ ๊ฐ๋จํ ์ฌ์ด๋ ํ๋ก์ ํธ๋ฅผ ๋ฐฐํฌํ๋ ๊ฒฝ์ฐ์๋ ๋ค์ํ ๋ฐฉ์์ ์ฌ์ฉํ ์ ์๋ค.
๊ฐ์ฅ ๊ฐ๋จํ ๋ฐฐํฌ ๋ฐฉ์์ Github Action์ ์ด์ฉํด ๋ธ๋์น๊ฐ ํธ์๋๋ฉด ๊ธฐ์กด ํ๋ก๊ทธ๋จ์ ์ข ๋ฃํ๊ณ ์๋ก์ด ํ๋ก๊ทธ๋จ์ ๋ค์ ๋์ฐ๋ ๋ฐฉ์์ผ ๊ฒ์ด๋ค. ํ์ง๋ง ๊ธฐ์กด ํ๋ก๊ทธ๋จ์ด ์ข ๋ฃ๋๊ณ ์๋ก์ด ํ๋ก๊ทธ๋จ์ ๋์ฐ๋ ์ฌ์ด์ ์๋น์ค๊ฐ ์ค๋จ๋๊ธฐ ๋๋ฌธ์, ์ด๋ฌํ ์ค๋จ ์์ด ๋ฐฐํฌํ ์ ์๋ ๋ฌด์ค๋จ ๋ฐฐํฌ ๋ฅผ ํ๊ณ ์ ํ๋ค.
๋ฌด์ค๋จ ๋ฐฐํฌ๋ฅผ ์งํํ๊ธฐ ์ํด Blue/Green ๋ฐฐํฌ ๋ฐฉ์์ ์ฌ์ฉํ๊ณ ์ ํ๋ค. Blue/Green ๋ฐฐํฌ ๋ฐฉ์์ ์๋ ๋ฒ์ ์ผ๋ก ์คํ์ค์ธ WAS๊ฐ ์กด์ฌํ๋ค๋ฉด ํด๋น WAS๋ฅผ ์ข ๋ฃ์ํค์ง ์์ ์ฑ ์๋ก์ด ๋ฒ์ ์ WAS๋ฅผ ๊ตฌ๋์ํจ๋ค. ์ฑ๊ณต์ ์ผ๋ก ๊ตฌ๋๋์๋ค๋ฉด Nginx๊ฐ ์๋ก์ด ๋ฒ์ ์ WAS๋ฅผ ๋ฐ๋ผ๋ณด๊ฒ ๋ฆฌ๋ก๋ํ๋ค. ๋ฆฌ๋ก๋ฉ์ด ์ฑ๊ณตํ๋ฉด ๋ชจ๋ ํธ๋ํฝ์ด ์๋ก์ด ๋ฒ์ ์ WAS๋ก ๋ค์ด๊ฐ๊ฒ ๋๋ฏ๋ก, ์์ ๋ฒ์ ์ WAS๋ฅผ ์ข ๋ฃ์ํค๋ฉด ๋๋ค.
์ฒ์์๋ ํ์ฌ์์๋ ๊ฒฝํํด๋ณธ ์ ์๋ Jenkins๋ฅผ ์ฌ์ฉํ๋ ค ํ์ผ๋ jar ํ์ผ์ ๋น๋ํ๋ ๊ณผ์ ์์ ์ฌ์ ๋ฌธ์ (ํ๋ฆฌ ํฐ์ด ํ๊ฒฝ)๋ก ์ธํด ec2๊ฐ ์ฃฝ์ด๋ฒ๋ฆฌ๋ ๋ถ์์ฌ๊ฐ ๋ฐ์ํด.. github action์ ์ฌ์ฉํ๊ธฐ๋ก ํ๋ค. ๐ฅฒ
๊ฐ๋จํ ๋ฐฐํฌ ์์๋ฅผ ์์ฝํ๋ฉด ์๋์ ๊ฐ๋ค. ์๋์์ ํ๋ํ๋๊ฐ ์ด๋ค ๋์์ ํ๋์ง ์ฝ๋์ ํจ๊ป ์ดํด๋ณผ ๊ฒ์ด๋ค.
- ec2(ubuntu) ์ธ์คํด์ค๋ฅผ ์์ฑํ๋ค.
- github action workflow๋ฅผ ์์ฑํ๋ค.
- ec2 ์ธ์คํด์ค์ Nginx, Github self-hosted runner๋ฅผ ์ค์นํ๋ค.
- ec2 ์ธ์คํด์ค์ deploy ์คํฌ๋ฆฝํธ๋ฅผ ์์ฑํ๋ค.
EC2 ์ธ์คํด์ค ์์ฑํ๊ธฐ
๋๋ Ubuntu ํ๊ฒฝ์ด ์ต์ํ๊ธฐ ๋๋ฌธ์ ํ๋ฆฌํฐ์ด ์ฌ์ฉ์ด ๊ฐ๋ฅํ Ubuntu AMI๋ฅผ ์ฌ์ฉํ๋ค.
๊ทธ๋ฆฌ๊ณ ์๋์ ๊ฐ์ด ์คํ ๋ฆฌ์ง๋ฅผ ์ต๋ 30GiB ์ฌ์ฉํ ์ ์์ผ๋ฏ๋ก ์ต๋๋ก ์ค์ ํด๋์๋ค.
8GiB๋ก ์ค์ ํ๋ฉด github runner ํ์ผ์ด ์๊ทผ ์ปค์ ๊ฝ์ฐจ๋ฒ๋ ค ๊ท์ฐฎ๊ฒ ๋๋ ค์ฃผ์ด์ผ ํ๋ ๋ถ์์ฌ๊ฐ ๋ฐ์ํ ์ ์๋ค.
์ค์ ์ ์ด์ ๋๋ก ๋ง๋ฌด๋ฆฌํ๊ณ ์ธ์คํด์ค๋ฅผ ์์ํ๋ค.
์ดํ, ๋ณด์ ๊ทธ๋ฃน์ ์ธ๋ฐ์ด๋ ๊ท์น์ ์ค์ ํ์ฌ ์ฌ์ฉํ๋ ค๋ ํฌํธ๋ฅผ ์ถ๊ฐํด์ฃผ์ด์ผ ํ๋ค. 80 ํฌํธ๋ Nginx์์ ์ฌ์ฉํ๋ฏ๋ก ์ถ๊ฐํด์ฃผ์๋ค.
Github Action ํ์ผ ์์ฑํ๊ธฐ
ec2์ ๋ฆฌ์์ค ์ฌ์ฉ๋์ ์ค์ฌ์ค Github Action์ ์์ฑํด๋ณด๊ฒ ๋ค.
๋จผ์ build-and-upload์ deploy๋ผ๋ ๋ ๊ฐ์ job์ผ๋ก ๋๋์ด์ง๋ค.
build-and-upload job์ github์์ ์์์ ์ํํด์ฃผ๋ ๊ฒ์ด๊ณ , deploy job์ ec2์์ ์ํํ๋๋ก ๊ตฌ์ฑํ๋ค.
- build-and-upload job์์๋ gradle์ผ๋ก jarํ์ผ์ ๋ง๋ค์ด github artifact์ ์ ๋ก๋ํ๋ ์์ ์ ์ํํ๋ค.
- deploy job์์๋ ec2์์ github artifact๋ก๋ถํฐ jar ํ์ผ์ ๋ค์ด๋ฐ์ ํ deploy ์คํฌ๋ฆฝํธ๋ฅผ ์คํ์ํด์ผ๋ก์จ ๋ด๋ถ์ ์ผ๋ก ๋ฌด์ค๋จ๋ฐฐํฌ๊ฐ ์งํ๋๋๋ก ํ๋ค. ๊ทธ๋ฆฌ๊ณ ๋ฐฐํฌ๊ฐ ์ฑ๊ณตํ๋ฉด ์ฌ๋์ผ๋ก ๋ฉ์์ง๋ฅผ ๋ณด๋ด๊ฒ ๋๋ค.
name: Backend develop CI/CD
on:
push:
branches:
- develop
permissions:
contents: read
jobs:
build-and-upload:
runs-on: ubuntu-22.04
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up JDK 19
uses: actions/setup-java@v4
with:
distribution: 'corretto'
java-version: '19'
- name: Give permission for Gradle
run: chmod +x gradlew
- name: Cache Gradle
id: cache-gradle
uses: actions/cache@v4
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Build with Gradle
run: ./gradlew :perfume-core:clean :perfume-api:clean :perfume-api:bootJar
- name: Upload jar file to artifact
uses: actions/upload-artifact@v3
with:
name: BackendApplication
path: perfume-api/build/libs/perfume-api-0.0.1.jar
deploy:
runs-on: [ self-hosted, dev ]
needs: build-and-upload
steps:
- name: Delete old jar file
run: rm -rf /home/ubuntu/backend/build/*.jar
- name: Download jar file from artifact
uses: actions/download-artifact@v3
with:
name: BackendApplication
path: /home/ubuntu/backend/build/
- name: Deploy Application
run: sh /home/ubuntu/backend/deploy.sh
- name: Send Slack Message
uses: 8398a7/action-slack@v3
with:
mention: 'here'
if_mention: always
status: ${{ job.status }}
fields: workflow,job,commit,message,ref,author,took
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
if: always()
Github self-hosted runner ๋ฑ๋กํ๊ธฐ
ํ๋ก์ ํธ์ Settings ํญ์ ๋ค์ด๊ฐ Actions-Runners์์ ์๋ก์ด Runner๋ฅผ ๋ง๋ ๋ค. ec2๋ Linux ํ๊ฒฝ์ด๋ฏ๋ก Runner image๋ฅผ Linux๋ก ์ ํํด์ฃผ์๋ค.
๊ทธ๋ฆฌ๊ณ ์๋์ ์ ๊ณต๋๋ ๋ช ๋ น์ด๋ค์ ์์ฐจ์ ์ผ๋ก ec2์์ ์คํํ๋ฉด ๋๋ค.
./run.sh ๋ฅผ ์คํํ ๋ nohup ./run.sh & ๋ช ๋ น์ด๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฐฑ๊ทธ๋ผ์ด๋์์ ์ํํ๋๋ก ํ ์ ์๋ค.
Nginx ์ค์นํ๊ธฐ
sudo apt-get install nginx ๋ช ๋ น์ด๋ก nginx๋ฅผ ์ค์นํ๋ค.
vi /etc/nginx/sites-enabled/default ๋ฅผ ํตํด ์๋์ ๊ฐ์ ๋ด์ฉ์ ์ถ๊ฐํ๋ค.
client_max_body_size 100M;
include conf.d/service-url.inc;
proxy_pass $service_url;
๋ค ์์ฑ๋๋ฉด ์๋์ ๊ฐ์ ๋ชจ์์ด ๋ ๊ฒ์ด๋ค.
server {
listen 80 default_server;
listen [::]:80 default_server;
client_max_body_size 100M;
include conf.d/service-url.inc;
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
server_name _;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
proxy_pass $service_url;
}
}
vi /etc/nginx/conf.d/service-url.inc ๋ฅผ ํตํด service url์ ์ค์ ํด์ค๋ค. ์ด url์ ๋ฐฐํฌ ์คํฌ๋ฆฝํธ์ ์ํด ์ ๋์ ์ผ๋ก ๋ณ๊ฒฝ๋ ๊ฒ์ด๋ค.
set $service_url http://127.0.0.1:8089;
์ดํ sudo systemctl start nginx ๋ฅผ ํตํด nginx๋ฅผ ์คํ์ํจ๋ค.
deploy ์คํฌ๋ฆฝํธ ์์ฑํ๊ธฐ
์ฌ์ค ์ ์ด๋ฒ ๊ธ์์ ๊ฐ์ฅ ์ค์ํ deploy.sh ์ ๋ํด ์๊ฐํ๋ค.
ํ ์ด ํ๋ก์ ํธ์ธ ๋งํผ ์์ ์ฑ์ด ๋ฐ์ด๋์ง๋ ์์ง๋ง ๊ฐ์ฅ ์ง๊ด์ ์ธ ๋ฐฉ๋ฒ์ด๋ค.
์คํฌ๋ฆฝํธ์์ ์ํ๋๋ ์์ ์ ๋ค์๊ณผ ๊ฐ๋ค.
1. ์ผ๋จ ๋ค์ํ ์คํ๋ง ํ๊ฒฝ ๋ณ์๋ฅผ ์๋ง๊ฒ ์ค์ ํด์ค๋ค.
2. ๊ทธ๋ฆฌ๊ณ nginx์ ์ค์ ํ ํ์ฌ ํฌํธ๊ฐ 8088์ธ์ง, 8089์ธ์ง ํ์ธํ์ฌ ์๋ก์ด ํ๋ก์ธ์ค์ ํฌํธ๋ฅผ ๊ฒฐ์ ํ๋ค.
3. ์ ์์ ์ผ๋ก ์๋ก์ด ํ๋ก์ธ์ค๊ฐ ๋์์ก๋์ง Spring Actuator๋ฅผ ํตํด ํ์ธํ๋ค.
4. ์ ์์ ์ผ๋ก ๊ตฌ๋์ด ๋์๋ค๋ฉด nginx๋ฅผ ๋ฆฌ๋ก๋ํ์ฌ ์๋ก์ด ํ๋ก์ธ์ค๋ฅผ ๋ฐ๋ผ๋ณด๊ฒํ๊ณ ๊ธฐ์กด ํ๋ก์ธ์ค๋ kill ํ๋ค.
# 1
# ์คํ๋ง ํ๊ฒฝ ๋ณ์ ์ค์
# export DB_HOST=localhost
# 2
CURRENT_PORT=$(sudo cat /etc/nginx/conf.d/service-url.inc | grep -Po '[0-9]+' | tail -1)
if [ ${CURRENT_PORT} -eq 8089 ]
then
echo "๋ธ๋ฃจ ์ปจํ
์ด๋ ์คํ"
sudo -E nohup java -jar /home/ubuntu/backend/build/perfume-api-0.0.1.jar --spring.profiles.active=dev --server.port=8088 /> /home/ubuntu/backend/backend.log 2>&1 &
BEFORE_COLOR="green"
AFTER_COLOR="blue"
BEFORE_PORT=8089
AFTER_PORT=8088
elif [ ${CURRENT_PORT} -eq 8088 ]
then
echo "๊ทธ๋ฆฐ ์ปจํ
์ด๋ ์คํ"
sudo -E nohup java -jar /home/ubuntu/backend/build/perfume-api-0.0.1.jar --spring.profiles.active=dev --server.port=8089 /> /home/ubuntu/backend/backend.log 2>&1 &
BEFORE_COLOR="blue"
AFTER_COLOR="green"
BEFORE_PORT=8088
AFTER_PORT=8089
else
echo "๋ฑ๋ก๋ ํฌํธ ์์"
exit 1
fi
# 3
for cnt in $(seq 10)
do
echo "์๋ฒ ์๋ต ํ์ธ์ค(${cnt}/10)";
if curl -s http://127.0.0.1:${AFTER_PORT}/api/actuator/health > /dev/null
then
UP="up"
break
else
UP="down"
fi
if [ "${UP}" != "up" ]
then
sleep 10
continue
else
break
fi
done
if [ $cnt -eq 10 ]
then
echo "์๋ฒ ๊ตฌ๋ ์คํจ"
exit 1
fi
# 4
sudo sed -i "s/${BEFORE_PORT}/${AFTER_PORT}/" /etc/nginx/conf.d/service-url.inc
sudo nginx -s reload
echo "๋ฐฐํฌ ์๋ฃ"
echo "$BEFORE_COLOR server down(port:${BEFORE_PORT})"
sudo lsof -t -i:${BEFORE_PORT} | xargs -I {} sudo kill -15 {}
๋ง์น๋ฉฐ
์์ฃผ ๊ฐ๋จํ ๋ฌด์ค๋จ ๋ฐฐํฌ๋ฅผ ์๋ฃํ๋ค.
์ฒ์์ CD๋ฅผ ์งํํ๋ฉด์ ํ๊ฒฝ๋ณ์, Nginx ์ค์ ์ค์ ๋ฑ์ผ๋ก ์ธํด ์์ฃผ ์ ๋ฅผ ๋จน์๋๋ฐ ์ด๋ ๊ฒ ์ ๋์ํ๋ ํ์ดํ๋ผ์ธ์ ๊ตฌ์ถํ๋ ํ๋ณตํ๋ค ใ _ใ
์์ผ๋ก Nginx๋ฅผ ์ข ๋ ๊ณต๋ถํด์ ์ด๋ ํ ์ค์ ๋ค์ด ์๋์ง ํ์ธํด๋ณด์์ผ๊ฒ ๋ค.
์ฐธ๊ณ ์๋ฃ
'Spring Boot > ๊ฐ๋ฐ ๊ธฐ๋ก' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Spring Cacheable์ ๋์ ์๋ฆฌ (0) | 2024.09.22 |
---|---|
Spring Boot์ Spring Security ํ๋ก์ ํธ์ Swagger ์ ์ฉํ๊ธฐ (0) | 2022.06.10 |
[Spring Security] JWT Tutorial (5) ํ์๊ฐ์ , ๊ถํ ๊ฒ์ฆ (0) | 2022.04.28 |
[Spring Security] JWT Tutorial (4) Repository ์์ฑ, ๋ก๊ทธ์ธ (0) | 2022.04.28 |
[Spring Security] JWT Tutorial (3) JWT ์ฝ๋, Security ์ค์ ์ถ๊ฐ (0) | 2022.04.28 |
๋๊ธ