[목표]
멘토님과 월요일 정기 미팅하기
프로젝트 흐름/진행도 구성(파이프 라인)(진행중)
노션과 벨로그 정리하기(진행중)
AWS 오토스케일링 적용하기(ALB)
배포완료 후 발표 자료 구상하기
프로젝트 전체 흐름 정리하고 멘토님께 보여드릴 문서 작성
진행 장표 작성
오토스케일링 수정(진행중)
부하발생기 사용해보기(k6)
정적 검사툴로 확인(소나큐브)
CloudFront 캐시 무효화
졸음
멘토님께 드릴 말씀 정리 (팀원 진행도 문서로 확인)
벨로그 정리
해당 서비스 활용 시나리오 정리
PPT 마무리
어제 다 못쓴 진행 장표를 써보겠다. 프로젝트 수행 경과의 이슈트래킹 분석과 구상 결론 도출부분을 작성해서 제출했다.
프로젝트 개요, 프로젝트 팀 구 성 및 역할, 프로젝트 수행 절차 및 방법에 대해 작성했고, 프로젝트 수행 경과 같은 경우 어느정도 작성했습니다.(대강)
ALB 헬스 체크를 3000번 포트로 하니까 Health가 뜬다. 근데 문제는 접속이 잘 안된다.
그래서 재 빌드를 하고 실행해봤으나 안된다… 이유를 찾아봐야겠다.
멘토님 메일로는 연락이 안되서 카톡으로 남겨두었다.
식사를 하고 왔다. 등촌 칼국수가 생각나는 식사였다.

아마존 오토스케일링이 헬스 체크는 되는데 CORS 문제가 생겨서 전에 해결했던 사례를 살펴보면서 해결해보고자 한다.
그리고 혹시나 멘토님이 오실걸 생각해서 문서들을 확인하고 사이트를 확인하고 있다.

또 CORS 설정 문제인데, 생각보다 오래걸릴 것 같아서 진행 중단하기로 했다. 나중에 시간이 된다면 다시 알아보겠지만, 지금은 서버 과부하 걸릴 것 같으면 사양을 올리는 방법을 선택하겠다.
멘토님과 이야기를 했다.
전체적인 흐름도 소개 및 Ci/CD 로직 설명했다. 최근 프로젝트, 알림 보충을 했다. 등을 설명했다.
[피드백]
기능추가: 5주만에 했다고 할만한 퀄리티? (Ai 적극활용을 통해서)
[질의응답시간]
오토스케일링 안하는게 나은가? → 명분(대용량 트래픽을 제어하는 실제 서비스 처럼)이 있다면 충분히 할만하다. 그리고 내가 하고 싶음. 지금아니면 돈 내고 해야되자나
프로젝트 파이프라인에 대해서 이해가 되시는지? 어떤 파이프 라인을 원하시는지?
명석 형: Ai 이슈 자동화 보강, 진입점 구현(프론트엔드), 비밀번호 찾기 구현
권호 형: 알림 체계 구현
윤호 형: 코드 품질 검사 구현
진혁 형: 최근 편집한 기록 구현(요약 페이지)
나: 오토스케일링 수정(부하 발생기), 벨로그
벨로그 정리를 어제자까지 마쳤다.
오토스케일링 정상화하기 전에 부하 테스트기를 만들어서 현재 서버에 부하를 걸어보려고 한다.
본격적으로 오토스케일링 CORS 정상화 전에 현재 t2.medium 서버에서는 어느정도의 유저를 수용할 수 있을지 k6를 통해서 확인해보기로 했다.
https://sjparkk-dev1og.tistory.com/221
위의 블로그로 k6의 사용법과 테스트 방식에 대해 알수 있다.
# Ubuntu
sudo apt install k6
설치 시에 다음과 같은 오류가 걸릴수 있다. apt 저장서에 k6 패키지가 없어서 그런 것이니 snap 패키지로 설치를 진행하면 된다.
ubuntu@ip-172-31-38-111:~/loadtest$ sudo apt install k6
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
No apt package "k6", but there is a snap with that name.
Try "snap install k6"
E: Unable to locate package k6
해결법(버전 확인까지)
sudo snap install k6
k6 version
만약, snap이 설치되어 있지 안다면
sudo apt update
sudo apt install snapd
sudo snap install k6
mkdir loadtest
cd loadtest
// nano 또는 vim을 통해 스크립트 작성
nano health.test.js
vim health.test.js
다음코드를 작성한다.
import http from 'k6/http';
import { check, sleep } from 'k6';
export let options = {
vus: 50, // 동시 접속자 수
duration: '30s', // 테스트 시간
};
export default function () {
const res = http.get('https://code-planner.com/api/health');
check(res, { 'status was 200': (r) => r.status == 200 });
sleep(1);
}
k6 run health.test.js
k6 부하 테스트의 동시 사용자 수(vus)와 시간(duration)은 테스트 목적, 서버 스펙, 실제 예상 트래픽에 따라 다르게 설정합니다.
| 목적 | 동시 사용자(vus) | 시간(duration) |
|---|---|---|
| 간단한 Smoke Test | 1~5 | 10~30초 |
| 기본 부하 테스트 | 10~50 | 30초~1분 |
| 실제 트래픽 시뮬 | 50~200 | 1~5분 |
| 한계(Stress) 테스트 | 200~1000+ | 1~10분 |
사이트 접속 부분 부하테스트
import http from 'k6/http';
import { check, sleep } from 'k6';
export let options = {
vus: 50, // 동시 접속자 수
duration: '30s', // 테스트 시간
};
export default function () {
const res = http.get('https://code-planner.com/api/health');
check(res, { 'status was 200': (r) => r.status == 200 });
sleep(1);
}
프로젝트 조회 부분 부하테스트(로그인 후)
import http from 'k6/http';
import { check, sleep } from 'k6';
export let options = {
vus: 20,
duration: '1m',
};
export default function () {
// 1. 로그인 요청
const loginRes = http.post('https://code-planner.com/api/auth/login', JSON.stringify({
email: 'prkty0@gmail.com',
password: 'qwerqwer'
}), { headers: { 'Content-Type': 'application/json' } });
check(loginRes, { 'login status 200': (r) => r.status === 200 });
// 2. 토큰 추출
const token = loginRes.json('accessToken');
// 3. 토큰을 포함해 프로젝트 조회
const projectsRes = http.get('https://code-planner.com/api/projects', {
headers: { Authorization: `Bearer ${token}` }
});
check(projectsRes, { 'status was 200': (r) => r.status == 200 });
sleep(1);
}
먼저 헬스체크를 통해 단순 접속 과부하 테스트를 했다.
k6 접속 30초 100명 가능 (CPU15%)
접속 30초 200명 가능 (CPU20%)
접속 5분 200명 가능 (CPU25%)
프로젝트 조회 테스트
프로젝트 3개 조회 1분 20명 가능 (CPU50%)
프로젝트 9개 조회 1분 20명 가능(CPU65%)
프로젝트 9개 조회 1분 30명 가능(CPU75%)
프로젝트 9개 조회 1분 50명 1, 2, 3차(CPU76%)
프로젝트 9개 조회 1분 100명 (CPU87%)
식사를 하고 왔다.

해당 내용은 위에 이어서 적었다.
K6를 가지고 여러 인원수와 시간에서 부하테스트를 진행했다. 오토스케일링을 해결하기 전에 1대의 t2.medium 서버가 어느정도 부하를 받아야 다운 되는지 알기 위해서이다.
단순 접속 테스트: 5분 200명 가능 (부하 25)
프로젝트 3개 조회: 30초 20명 가능 (부하 50)
프로젝트 9개 조회: 1분 100명 가능 (부하 87)
정민코치님 조언대로 배달의 민족에서 어떤 식으로 부하 테스트를 하는지 알아보았다.
배달의 민족에서는 nGrinder 라는 자바 기반 웹 성능 측정도구가 있는데, 이걸 보고 nodejs용 측정도구를 도입하면 좋겠다고 생각했다. 기존에는 AWS 측정 그래프와 k6 결과에만 의존했기 때문이다. 이걸 보면서 반영이 느리기도하고 시각적 정보가 적어서 잘되는지, 왜 이러한 결과가 나오는지에 대한 의문점이 많았다. 이러한 도구들을 사용해서 좀 더 효과적인고 디테일하게 알아보고자 한다.
또한, 난 인프라뿐만 아니라 Devops까지도 생각하고 있어서 기존에는 동적검사만 했다면, 지금부터라도 코드 품질과 안정성을 위해 정적/동적 검사를 수행하기로 생각했다.
일단 소나큐브 정적 검사가 시간이 오래 걸리므로 중간 점검겸 돌려 놓고 과부하 테스트와 오토스케일링을 구축하겠다.
예전에 Java 프로젝트로 직접 돌려본 경험이 있어서 금방할 수 있을것 같다.
소나큐브 공식 페이지에서 소나큐브 커뮤니티 버전과 소나큐브 스캐너를 다운 받으면된다.
스캐너 같은 경우 CLI로 작동해야하므로 환경변수에 bin 폴더 경로를 기입해야한다.
sonar-project.properties 파일 생성하자.sonar.projectKey=프로젝트 키
sonar.projectName=프로젝트 이름
sonar.projectVersion=1.0
sonar.sources=src
sonar.sourceEncoding=UTF-8
# 분석 제외할 경로
sonar.exclusions=**/*.spec.ts,**/node_modules/**,**/dist/**
# TypeScript 설정
sonar.language=ts
sonar.typescript.tsconfigPath=tsconfig.json
npm install -g @sonar/scan
sonar \ -Dsonar.host.url=http://localhost:9000 \ -Dsonar.token=토큰값 \ -Dsonar.projectKey=프로젝트키
→ 백엔드, 프론트엔드 둘다 똑같은 방식으로 분석 실행하면된다.
[참고] 프론트엔드는 해당 실행 명령어를 써야한다. NextJS 기준 폴더 구조가 다르기 때문이다.
sonar \ -Dsonar.host.url=http://localhost:9000 \ -Dsonar.token=sqp_f720371728faf024df25122f0036a9756c1113c5 \ -Dsonar.projectKey=Cord_Planner_Frontend / -Dsonar.sources=app,components,lib,scripts
백엔드와 프론트엔드의 중간 결과는 다음과 같다. 보안 관련 핫스팟은 확인 결과 오탐지여서 무시해도 된다.
운동하고 왔다.
서버 다운으로 인한 문제 확인. → 명석이형 패스워드 리셋 페이지 suspens로 감싸는 부분 수정
계속해서 CloudFront가 캐싱된 전 옛날 페이지를 불러온다. 테스트 하는데 문제가 있어서 우선적으로 수정해보겠다. CloudFront 해당 배포에서 무효화 생성 누른다음 /* 로 설정합니다.
팀의 진척도를 확인했다.
명석 형: Ai 이슈 자동화 보강, 진입점 구현(프론트엔드), 비밀번호 찾기 구현 → 거의 완료
권호 형: 알림 체계 구현 → 담당자 본인일시 알림옴, 클릭시 댓글 기능 구현, 확장 가능성 있음.
윤호 형: 코드 품질 검사 구현 → 깃헙 변경 사항 가져와서 검사까지 가능
진혁 형: 최근 편집한 기록 구현(요약 페이지) → NextJS 프론트엔드 공부? 내일 5시경까지 하는걸로 결정
나: 오토스케일링 수정(부하 발생기), 벨로그 → 정적검사 완료, 부하 테스트 일부분 완료, cloudfront 캐싱 무효화 설정, 오토스케일링 수정중
멘토님의 명분이 있다면 오토스케일링 하라는 말씀을 듣고 자심감을 가지고 다시 세팅해보기로 했다. 일단 템플릿 사용자 스크립트에 다음과 같이 pm2 프로세스 이름을 수정하고, 각 프로세스가 pm2 설정 파일 기반으로 실행되도록 다시 만들었다.
V9 pm2 프로세스 네임 본서버와 동기화, pm2 설정 파일기반 실행
#!/bin/bash
# 1. 기본 패키지 설치
apt-get update -y
apt-get install -y curl git build-essential wget gnupg2 ca-certificates lsb-release ufw
# 2. Node.js 22.16.0 설치
NODE_VERSION=22.16.0
ARCH=$(uname -m)
if [ "$ARCH" == "x86_64" ]; then
ARCH="x64"
elif [ "$ARCH" == "aarch64" ]; then
ARCH="arm64"
else
echo "Unsupported architecture: $ARCH"
exit 1
fi
curl -O https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-$ARCH.tar.xz
tar -C /usr/local --strip-components=1 -xJf node-v$NODE_VERSION-linux-$ARCH.tar.xz
rm node-v$NODE_VERSION-linux-$ARCH.tar.xz
# Node.js 확인
node -v
npm -v
# PM2 설치 및 환경 설정
npm install -g pm2
export HOME=/home/ubuntu
export PM2_HOME=/home/ubuntu/.pm2
# 3. PostgreSQL 17.5 설치
sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor > /usr/share/keyrings/postgresql.gpg
echo "deb [signed-by=/usr/share/keyrings/postgresql.gpg] http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list
apt-get update -y
apt-get install -y postgresql-17
# PostgreSQL 버전 확인
sudo -u postgres psql -c "SELECT version();"
# 4. Nginx 설치
apt-get install -y nginx
# 5. 방화벽 설정
ufw allow OpenSSH
ufw allow 5432/tcp
ufw allow 'Nginx Full'
ufw --force enable
# 6. 프로젝트 클론
mkdir -p /home/ubuntu/codeplanner
chown -R ubuntu:ubuntu /home/ubuntu/codeplanner
cd /home/ubuntu/codeplanner
# Backend
if [ ! -d "Codeplanner_Backend" ]; then
sudo -u ubuntu git clone https://github.com/Krafton-Jungle-Weight/Codeplanner_Backend.git
else
cd Codeplanner_Backend
sudo -u ubuntu git pull origin main
cd ..
fi
# Frontend
if [ ! -d "Codeplanner_Frontend" ]; then
sudo -u ubuntu git clone https://github.com/Krafton-Jungle-Weight/Codeplanner_Frontend.git
else
cd Codeplanner_Frontend
sudo -u ubuntu git pull origin main
cd ..
fi
# 7. 백엔드 설치 및 실행
cd /home/ubuntu/codeplanner/Codeplanner_Backend
chown -R ubuntu:ubuntu .
sudo -u ubuntu npm install
sudo -u ubuntu npm run build
sudo -u ubuntu pm2 start ecosystem.config.js --env production
# 8. 프론트엔드 설치 및 실행
cd /home/ubuntu/codeplanner/Codeplanner_Frontend
chown -R ubuntu:ubuntu .
sudo -u ubuntu npm install
sudo -u ubuntu npm run build
sudo -u ubuntu pm2 start ecosystem.config.js --env production
# 9. PM2 상태 저장
sudo -u ubuntu pm2 save
→ 이렇게 해도 DB연동을 위해 본격적으로 실행되기 전에 보안그룹을 설정해야 한다. 만약, 그렇게 못했다면 백엔드 캐시 밀고 재빌드 해야함.
계속해서 CORS 문제가 나와서 EC2를 지우고, EC2 오토 스케일링을 위한 세팅을 재시작했다.
헬스 체크가 되고 IP를 통해 접속했을떄 웹사이트가 나오도록 해보겠다.
방화벽을 해제하는 부분이 필요하다고 해서 V10 시작 템플릿에 추가했다. 현재의 EC2에는 적용 완료 해두었다.
ufw allow 5000/tcp
ufw allow 3000/tcp
다시 CORS 관련 문제가 생겨서 코드 일부분을 수정했다. 지우지 말걸…
백엔드
.env.production
밑의 코드에 오토스케일링 EC2 주소를 추가했다.
CORS_ORIGIN=https://code-planner.com,[https://code-planner.com:5000](https://code-planner.com:5000/),[https://code-planner.com:3000](https://code-planner.com:3000/),[http://3.39.195.132:3000](http://3.39.195.132:3000/)
프론트엔드
nginx.conf
CORS 헤더 추가와 OPTIONS preflight 요청 처리 부분에서 ‘Access-Control-Allow-Origin’이 와일드카드(*)로 되어 있어서credentials: 'include'를 사용하는 요청에서는 브라우저가 무조건 차단하므로 $http_origin always 로 바꿧다.
# CORS 헤더 추가
add_header 'Access-Control-Allow-Origin' $http_origin always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
# OPTIONS preflight 요청 처리
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' $http_origin;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Content-Length' 0;
add_header 'Content-Type' 'text/plain charset=UTF-8';
return 204;
}
메인에 올려서 서버에 올려보겠다. 서브 서버는 삭제후 클론 받아서 세팅해보겠다.
음… 안된다. 졸리니 내일 와서 code-planner.com 이 들어가 있는 URL을 프로젝트 파일에서 하나하나 확인하면서 문제를 찾아봐야겠다.