WEEK 17 나만무 MVP TIL(7월7일 월요일)

Devkty·2025년 7월 9일
post-thumbnail

[목표]
멘토님과 월요일 정기 미팅하기
프로젝트 흐름/진행도 구성(파이프 라인)(진행중)
노션과 벨로그 정리하기(진행중)
AWS 오토스케일링 적용하기(ALB)
배포완료 후 발표 자료 구상하기
프로젝트 전체 흐름 정리하고 멘토님께 보여드릴 문서 작성
진행 장표 작성
오토스케일링 수정(진행중)
부하발생기 사용해보기(k6)
정적 검사툴로 확인(소나큐브)
CloudFront 캐시 무효화

10:00 ~ 10:45

졸음
멘토님께 드릴 말씀 정리 (팀원 진행도 문서로 확인)
벨로그 정리
해당 서비스 활용 시나리오 정리
PPT 마무리

10:45 ~ 11:40

어제 다 못쓴 진행 장표를 써보겠다. 프로젝트 수행 경과의 이슈트래킹 분석과 구상 결론 도출부분을 작성해서 제출했다.

프로젝트 개요, 프로젝트 팀 구 성 및 역할, 프로젝트 수행 절차 및 방법에 대해 작성했고, 프로젝트 수행 경과 같은 경우 어느정도 작성했습니다.(대강)

11:40 ~ 12:00

ALB 헬스 체크를 3000번 포트로 하니까 Health가 뜬다. 근데 문제는 접속이 잘 안된다.
그래서 재 빌드를 하고 실행해봤으나 안된다… 이유를 찾아봐야겠다.
멘토님 메일로는 연락이 안되서 카톡으로 남겨두었다.

12:00 ~ 13:00

식사를 하고 왔다. 등촌 칼국수가 생각나는 식사였다.

13:00 ~ 14:10

오토스케일링을 도전하고 중단하다.

아마존 오토스케일링이 헬스 체크는 되는데 CORS 문제가 생겨서 전에 해결했던 사례를 살펴보면서 해결해보고자 한다.

그리고 혹시나 멘토님이 오실걸 생각해서 문서들을 확인하고 사이트를 확인하고 있다.

또 CORS 설정 문제인데, 생각보다 오래걸릴 것 같아서 진행 중단하기로 했다. 나중에 시간이 된다면 다시 알아보겠지만, 지금은 서버 과부하 걸릴 것 같으면 사양을 올리는 방법을 선택하겠다.

멘토님 미팅 (14:10 ~ 15:30)

멘토님과 이야기를 했다.
전체적인 흐름도 소개 및 Ci/CD 로직 설명했다. 최근 프로젝트, 알림 보충을 했다. 등을 설명했다.

[피드백]

  • 양방향 통신이 되면 좋을 것 같다.
  • 백로그? 이슈가 5가지면 브런치가 5개 나오는건 너무 복잡해 지지 않을까?
  • 그래서 백로그를 통해서 하는게 좋지 않을까?
  • 깃헙이랑 IDE랑 코드 플래너를 연동할 수 있는 방향을 생각하자.
  • 좀 더 쉽게 쓸수 있는 이슈트래킹 서비스에 대해서 생각을 해보자.
  • 이슈트래킹 서비스를 왜 만들고자 했는지? 확인하자
  • 초등학생이나 엄청 쉽게 풀어쓴 Jira라고 볼 수도 있을것 같다.
  • 코덱스 적극적으로 사용해보면 좋겠다.
  • 유저입장에서 어떤 장점을 가질 수 있는가?
  • 이거 왜 쓰냐? Jira와 차별점을 둘 수 있는 점들을 찾아보자.
  • 요즘 개발자들이 많이 짤린다. 이제는 개발자가 기획과 같은 PM역할도 많이 해야한다.
  • Jira가 Ai 기능이 적으니까 굳이 필요없는 기능을 간소화하는것도 전략이다.
    → 시나리오를 제대로 써서 서비스의 매리트를 찾자.

기능추가: 5주만에 했다고 할만한 퀄리티? (Ai 적극활용을 통해서)

[질의응답시간]
오토스케일링 안하는게 나은가? → 명분(대용량 트래픽을 제어하는 실제 서비스 처럼)이 있다면 충분히 할만하다. 그리고 내가 하고 싶음. 지금아니면 돈 내고 해야되자나
프로젝트 파이프라인에 대해서 이해가 되시는지? 어떤 파이프 라인을 원하시는지?

15:30 ~ 17:30

팀 오늘 할일(진행중인일)

명석 형: Ai 이슈 자동화 보강, 진입점 구현(프론트엔드), 비밀번호 찾기 구현
권호 형: 알림 체계 구현
윤호 형: 코드 품질 검사 구현
진혁 형: 최근 편집한 기록 구현(요약 페이지)
나: 오토스케일링 수정(부하 발생기), 벨로그

벨로그 정리를 어제자까지 마쳤다.

17:30 ~ 18:00

오토스케일링 정상화하기 전에 부하 테스트기를 만들어서 현재 서버에 부하를 걸어보려고 한다.

k6로 사용자 수 과부하 테스트 해보기 (오토스케일링 X)

본격적으로 오토스케일링 CORS 정상화 전에 현재 t2.medium 서버에서는 어느정도의 유저를 수용할 수 있을지 k6를 통해서 확인해보기로 했다.
https://sjparkk-dev1og.tistory.com/221
위의 블로그로 k6의 사용법과 테스트 방식에 대해 알수 있다.

1. 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

2. 디렉토리 만들고, 테스트 스크립트 작성

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);
}

3. 위의 파일이 있는 디렉터리에서 해당 명령어로 실행하면된다.

k6 run health.test.js

4.여러가지 상황을 가정하여 부하 테스트 진행

k6 부하 테스트의 동시 사용자 수(vus)와 시간(duration)은 테스트 목적, 서버 스펙, 실제 예상 트래픽에 따라 다르게 설정합니다.


실무에서 많이 쓰는 기본 예시

목적동시 사용자(vus)시간(duration)
간단한 Smoke Test1~510~30초
기본 부하 테스트10~5030초~1분
실제 트래픽 시뮬50~2001~5분
한계(Stress) 테스트200~1000+1~10분

실전 팁

  • 초기에는 10~50명, 30초~1분으로 시작해서 서버가 잘 버티는지 확인
  • 점차 vus(동시 사용자)와 duration(시간)을 늘려가며 서버 한계점 파악
  • 운영 서버에서는 너무 높은 값으로 테스트하면 실제 서비스에 영향이 갈 수 있으니 주의!

사이트 접속 부분 부하테스트

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%)

18:00 ~ 19:00

식사를 하고 왔다.

19:00 ~ 22:00

해당 내용은 위에 이어서 적었다.

K6를 가지고 여러 인원수와 시간에서 부하테스트를 진행했다. 오토스케일링을 해결하기 전에 1대의 t2.medium 서버가 어느정도 부하를 받아야 다운 되는지 알기 위해서이다.

단순 접속 테스트: 5분 200명 가능 (부하 25)
프로젝트 3개 조회: 30초 20명 가능 (부하 50)
프로젝트 9개 조회: 1분 100명 가능 (부하 87)

22:00 ~ 23:30

부하 테스트와 DevOps를 위한 정적 검사 도입(소나큐브)

정민코치님 조언대로 배달의 민족에서 어떤 식으로 부하 테스트를 하는지 알아보았다.

배달의 민족에서는 nGrinder 라는 자바 기반 웹 성능 측정도구가 있는데, 이걸 보고 nodejs용 측정도구를 도입하면 좋겠다고 생각했다. 기존에는 AWS 측정 그래프와 k6 결과에만 의존했기 때문이다. 이걸 보면서 반영이 느리기도하고 시각적 정보가 적어서 잘되는지, 왜 이러한 결과가 나오는지에 대한 의문점이 많았다. 이러한 도구들을 사용해서 좀 더 효과적인고 디테일하게 알아보고자 한다.

또한, 난 인프라뿐만 아니라 Devops까지도 생각하고 있어서 기존에는 동적검사만 했다면, 지금부터라도 코드 품질과 안정성을 위해 정적/동적 검사를 수행하기로 생각했다.

일단 소나큐브 정적 검사가 시간이 오래 걸리므로 중간 점검겸 돌려 놓고 과부하 테스트와 오토스케일링을 구축하겠다.

소나큐브 돌려보기

예전에 Java 프로젝트로 직접 돌려본 경험이 있어서 금방할 수 있을것 같다.
소나큐브 공식 페이지에서 소나큐브 커뮤니티 버전과 소나큐브 스캐너를 다운 받으면된다.
스캐너 같은 경우 CLI로 작동해야하므로 환경변수에 bin 폴더 경로를 기입해야한다.

  1. 먼저 소나큐브의 bin폴더의 windows-x86-64, StartSonar로 로컬호스트에 서버를 전개한다.
  2. localhost:9000번으로 접속후 admin/admin으로 접속한다. 초회에는 비번 바꾸기!
  3. Projects 탭에서 Create alocal project를 누른다음에 프로젝트 이름을 작성하고 Next를 누른다.
  4. 특별한게 없으면 Use the global setting로 진행한다. Create Project를 누르면 생성된다.
  5. 생성후엔 Analysis Method 창이 나올텐데, 우리는 로컬로 테스트 할거라 Locally로 토큰을 발급받는다.
  6. 해당 토큰은 복사해두고 잘 저장해두자.
  7. 프로젝트 루트 디렉토리에 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
  1. 분석실행하기
    • PowerShell 또는 CMD에서 프로젝트 루트 폴더로 이동
    • 아래 명령어 실행 (토큰은 SonarQube에서 발급한 값)
    • npm 패키지를 인스톨해야된다.
npm install -g @sonar/scan
sonar \ -Dsonar.host.url=http://localhost:9000 \ -Dsonar.token=토큰값 \ -Dsonar.projectKey=프로젝트키
  1. 이제 다시 localhost:9000 으로 가서 결과를 확인하면된다.

→ 백엔드, 프론트엔드 둘다 똑같은 방식으로 분석 실행하면된다.

[참고] 프론트엔드는 해당 실행 명령어를 써야한다. NextJS 기준 폴더 구조가 다르기 때문이다.

sonar \ -Dsonar.host.url=http://localhost:9000 \ -Dsonar.token=sqp_f720371728faf024df25122f0036a9756c1113c5 \ -Dsonar.projectKey=Cord_Planner_Frontend / -Dsonar.sources=app,components,lib,scripts

백엔드와 프론트엔드의 중간 결과는 다음과 같다. 보안 관련 핫스팟은 확인 결과 오탐지여서 무시해도 된다.

23:30 ~ 01:30

운동하고 왔다.

01:30 ~ 04:30

서버 다운으로 인한 문제 확인. → 명석이형 패스워드 리셋 페이지 suspens로 감싸는 부분 수정

CloudFront 캐시 무효화 설정

계속해서 CloudFront가 캐싱된 전 옛날 페이지를 불러온다. 테스트 하는데 문제가 있어서 우선적으로 수정해보겠다. CloudFront 해당 배포에서 무효화 생성 누른다음 /* 로 설정합니다.

팀의 진척도를 확인했다.

팀 오늘 할일(2시 기준)

명석 형: 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 해결하기…

다시 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;
        }

https://github.com/Krafton-Jungle-Weight/Codeplanner_Backend/commit/e742f05f599fcb02a1fa61fc83bfee6b5b2ff85f

https://github.com/Krafton-Jungle-Weight/Codeplanner_Frontend/commit/20b18b3dcbfac837f7c20d55b185d68e92499db8

메인에 올려서 서버에 올려보겠다. 서브 서버는 삭제후 클론 받아서 세팅해보겠다.

음… 안된다. 졸리니 내일 와서 code-planner.com 이 들어가 있는 URL을 프로젝트 파일에서 하나하나 확인하면서 문제를 찾아봐야겠다.

profile
모든걸 기록하며 성장하고 싶은 개발자입니다. 현재 크래프톤 정글 8기를 수료하고 구직활동 중입니다.

0개의 댓글