[moaloa] 미니프로젝트 개발일지 #6

msw-Hub·2025년 4월 13일
0

moaloa

목록 보기
7/7
post-thumbnail

이번 포스팅에서는 배포과정과 협업으로 Git을 사용하면서 겪은 내용들과 개념들을 정리한다.

모아로아 개발단계에서 가장 많은 시행착오를 겪은 것이 배포 단계였다.
이전에는 cloudtype을 이용해서 간단배포를 진행했었기 때문에, 이번 프로젝트를 진행하면서 AWS를 처음 사용해 많은 것들이 어려웠다.

뿐만 아니라, Git을 그저 코드 공유 장치 겸 코드 폴더 로만 사용하다가 Git Branch 전략도 사용해보고, Jira에 연결해서 사용해보기도 하고 깊게 다루어보지는 않았지만, 새로운 것들이 너무 많아 진행에 있어 많이 버벅이기도 했다.


💻 Git Branch

Git을 이전에 사용할때는 일종의 코드 폴더의 개념으로 사용했지만, 협업을 하다보니, 서로의 코드를 첨삭을 해야하는 경우가 많았다.
물론 이번에 진행한 프로젝트에서는 프론트랑 백엔드의 영역을 구분지어 놓았기에 서로의 코드를 침범하지않아 큰 어려움은 없었지만, 배포까지 진행하는 프로젝트에서 Git에 버전을 작성해두지 않으면, 이후에 코드를 롤백 해야하는 경우에도 문제가 많을 것으로 예상되어, Git에 전략이 없는지 찾아보게 되었다.

Git Branch 전략에는 여러가지가 존재하지만, 큰 흐름으로는 3가지를 많이 말하는것 같다.


1. ✅ Git Flow

📌 개념

  • 릴리스 중심의 브랜치 전략
  • 브랜치를 역할별로 분리해서 기능 개발 → 테스트 → 배포 → 핫픽스까지 체계적으로 관리
  • 대규모 프로젝트, 정기 릴리스 있는 팀에 적합

🔧 브랜치 구조

  • main – 운영/배포용 코드
  • develop – 개발 완료된 코드
  • feature/ – 기능 개발용
  • release/ – 릴리스 준비용 (버그 수정, QA 등)
  • hotfix/ – 운영 중 긴급 수정

✅ 장점

  • 작업 단계 구분이 명확 → 협업 편리
  • QA/릴리스 관리가 체계적

❌ 단점

  • 브랜치가 많고 복잡
  • 릴리스 속도 느림 → 빠른 배포엔 부적합

2. 🌐 GitHub Flow

📌 개념

  • 단순하고 빠른 배포에 적합한 전략
  • Pull Request 기반의 흐름, CI/CD 자동화에 최적화

🔧 브랜치 구조

  • main – 항상 배포 가능한 상태
  • feature/ – 기능 개발 → PR → merge → 자동 배포

✅ 장점

  • 단순하고 빠름
  • 자동 테스트, 리뷰, 배포 파이프라인과 잘 어울림 (CI/CD(지속적 통합/지속적 배포) 파이프라인 등)

❌ 단점

  • 별도의 QA(품질관리)/스테이징(검증) 브랜치 없음 → 버그포함 코드 바로 배포 가능성 → 실수 위험 / 테스트가 개발자의 책임
  • 대규모 릴리스 프로세스에는 부족할 수 있음 (여러 기능을 동시에 개발하고 릴리스할 때는 더 복잡한 브랜치 관리가 필요할)

3. 🛠️ GitLab Flow

GitLab의 존재도 이때 찾아보면서 처음 알았다.
📌 개념

  • Git Flow + GitHub Flow + 환경 기반 브랜치 전략
  • GitLab의 이슈/머지/배포 기능과 잘 통합됨
  • 운영 환경(예: staging, production) 구분에 강점

🔧 브랜치 구조

  • main – 최종 운영 코드
  • feature/ – 기능 개발
  • pre-production, staging, production – 환경별 브랜치
  • 이슈 기반 브랜치 (issue-123-fix-login 등)

✅ 장점

  • 운영 환경별 브랜치 관리 가능 ( 코드 관리 안정화 )
  • GitLab 이슈, 머지 요청과 긴밀하게 연결됨
    예를 들어, 특정 이슈를 해결하기 위해 만든 브랜치에서 머지 요청을 하면, 해당 요청이 어떤 이슈와 관련 있는지 자동으로 표시되어 관리가 더 쉬워진다함

❌ 단점

  • 설정 복잡할 수 있음 ( 다양한 기능을 제공하지만, 초기 설정이 복잡)
  • GitLab 플랫폼에 종속적일 수 있음

"우리 프로젝트는 소규모 프로젝트였고, CI/CD 파이프라인을 도입해보려고 해서 GitHub Flow를 사용해봤다. 그런데 개발 과정에서 feature/ 브랜치를 나누어 작업하다 보니, 중간에 develop 브랜치를 통해 코드를 정리하는 구간이 필요할 것 같아서, GitHub Flowdevelop 브랜치를 추가하는 전략을 선택했다.


✏️ 브랜치 네이밍 규칙

프로젝트에서 여러 사람이 협업할 때, 각 브랜치가 어떤 작업을 하고 있는지 쉽게 파악할 수 있도록 이름을 정하는 규칙을 말한다.
이전에 작업 했을때는 그냥 대충 1.1.1 이런식으로 버전을 작성하는 방식을 사용했지만, 뭘했는지 한번에 파악하기가 힘들고, 버전을 잘 지키지 않아서 곤란했던 적도 있엇다.

물론, 이번 네이밍 전략도 시간이 지남에 따라 많이 지켜지지 않기도 했지만, 이때는 무엇을 작업했는지 큰 흐름을 보기에는 필요함을 느꼈다.

우리는 Jira를 사용 중이였기에, 아래의 틀을 규칙으로 정했다.
[Jira작업번호] FE or BE / 브랜치 / 기능의이름 / #N번째 작업인가 / 간단설명

예:

[SCRUM-43] BE/feature/craft/#1 json구조 변경 및 생활재료시세


⚙️ CI/CD

📌 개념

  1. CI (지속적인 통합)
    개발자들이 작업한 코드를 자주 하나로 합치는 과정으로, 코드 변경 사항을 하나로 합쳐서 테스트하는 과정이다.
    간단하게, 개발자를 위해 빌드와 테스트를 자동화 하는 과정이다.

  2. CD (지속적인 배포 - Continuous Delivery)
    CI 작업을 끝낸 다음 실행하는 작업이다.
    CI에서 통합되고 테스트된 코드가 배포 준비가 된 상태를 만드는 과정이다.
    즉, 빌드와 테스트를 성공적으로 진행했을 때, 깃허브와 같은 코드 저장소에 자동으로 업로드하는 과정을 말한다.

  3. CD의 또 다른 형태 - Continuous Deployment
    Continuous Deployment (지속적인 배포)는 테스트까지 통과하면 자동으로 실 서비스(운영 환경)에 배포하는 방식이다.
    병합한 코드의 내역을 AWS 와 같은 배포 환경으로 보내는 것을 의미하며, 이를 실무에서는 릴리스( "Release")라고 한다.


🔧GitHub Actions <--> AWS Elastic Beanstalk

Git <--> GitHub 연동

  1. git config 명령어를 사용해 이름, 이메일 설정
  2. SSH 인증정보 생성
  3. GitHub에 키 등록

GitHub Actions

CI/CD 파이프라인을 구축하고 자동화할 수 있는 도구로, GitHub에서 제공하는 서비스이다.
작업 폴더 상위에, ../.github/workflows/cicd.yml 경로로 파일을 생성해준다면, 해당 파일의 내용에 맞춰서 CI/CD 작업을 해준다.

이제 GitHub Actions에 워크플로우 파일을 작성해주고, AWS와 연결을 해준다면 CI/CD 동작을 하는 것이다.

내가 작성한 폼은 다음과 같다.

  1. 트리거 설정
    main 브랜치에 푸시가 발생할 때마다 이 워크플로우가 실행.
  2. 작업(Job) 설정
    커밋 메시지에 [BE]가 포함된 경우에만 이 작업이 실행.
    ubuntu-latest 환경에서 실행
  3. 작업 단계(Steps)
    (1) 코드 체크아웃: GitHub 리포지토리의 코드를 체크아웃하여 워크플로우 내에서 사용
    (2) Java 환경 설정
    (3) Gradle 실행 권한 부여
    (4) Gradle 빌드
    (5) 현재 시간 가져오기
    (6) 배포용 패키지 경로 저장
    (7) Elastic Beanstalk 배포
name: CI/CD

on:
  push:
    branches: [ main ]

jobs:
  build:
    if: ${{ contains(github.event.head_commit.message, '[BE]') }} # 커밋 메시지에 [BE]가 포함된 경우에만 실행
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3

    - uses: actions/setup-java@v3
      with:
        distribution: 'corretto'
        java-version: '17'

    - name: Grant execute permission for gradlew
      run: chmod +x gradlew
      working-directory: back-end

    - name: Build with Gradle
      run: ./gradlew clean build
      working-directory: back-end

    - name: Get current time
      uses: josStorer/get-current-time@v2.0.2
      id: current-time
      with:
        format: YYYY-MM-DDTHH-mm-ss
        utcOffset: "+09:00"

    - name: Set artifact
      run: echo "artifact=$(ls ./build/libs)" >> $GITHUB_ENV
      working-directory: back-end

    - name: Beanstalk Deploy
      uses: einaregilsson/beanstalk-deploy@v20
      with:
        aws_access_key: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws_secret_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        application_name: moaloa-springboot
        environment_name: MOALOA-springboot-env
        version_label: github-action-${{steps.current-time.outputs.formattedTime}}
        region: ap-northeast-2
        deployment_package: ./back-end/build/libs/${{env.artifact}}

AWS Elastic Beanstalk

Amazon Web Services (AWS)에서 제공하는 플랫폼 서비스(PaaS)이다.
이 서비스는 애플리케이션을 간단하고 빠르게 배포, 관리, 확장할 수 있도록 돕는 자동화된 환경을 제공한다.
아무래도 간단한 서비스를 운영하는 것이고, 배포를 자동화 하는 것이기에 AWS Elastic Beanstalk(PaaS)를 사용했다.

AWS에서 내가 한 과정은 다음과 같다.

  1. IAM 설정
    Elastic Beanstalk이 AWS의 다른 서비스에 안전하게 접근할 수 있도록, 적절한 권한을 가진 IAM 역할(role)을 먼저 설정
  2. 환경 구성
    (1) 플랫폼 설정 - JAVA
    (2) 역할 부여 - IAM에서 했던거
    (3) 인스턴스 트래픽 및 크기조정 - 예전에는 기본값으로 빠르게 환경을 만들 수 있었지만, 최근 AWS 콘솔 UX가 개선되면서, 다음 항목들을 사용자가 직접 명시적으로 선택해야만 생성 단계로 넘어갈 수 있게 되었다.
    프리티어 범주에 맞게 잘 설정해야한다.
    나는 단일인스턴스, gps3, IOPS 3000, 25GB, t2.micro를 사용했다.
    (4) 해당 설정을 토대로 프로젝트 생성
  3. RDS 설정
    (1) Elastic Beanstalk 설정 내에서 DB활성화 토글 을 클릭하여 설정
    (2) 엔진 (mysql), 인스턴스(db.t3.micro), 이름 및 암호 설정
    (3) 생성 후 엔드포인트 복사 후 환경속성에 URL, USERNAME, PASSWORD를 작성해준다.
  4. EC2 및 RDS 보안그룹 설정 (인바운드 / 아웃바운드)

RDS 접근

로컬에서 테스트할 때는 docker로 DB를 열고 인텔리제이의 DB탭을 통해 연결하거나, MySQL 워크벤치를 활용하여 DB에 접근했다. 하지만, AWSRDS에 접근할 때는 방법이 조금 다르다.

RDS에 접근하기 위한 방법은 여러 가지가 있지만, 퍼블릭 액세스를 허용하는 방법을 선택했다.
이렇게 하면 인텔리제이 DB탭이나 MySQL 워크벤치를 활용하여 RDS에 연결할 수 있다.

이 방법은 접근이 간단하지만, 시간당 금액이 발생한다는 단점이 있다.
따라서, 데이터베이스를 확인하거나 중간에 작업을 해야 할 때만 퍼블릭으로 전환하여 접근했다.
시간당 금액은 약 200원 정도 발생했던 것 같다.


🤔 문제점 & 시행착오

1. 🔐 HTTP → HTTPS 전환기

1. HTTPS 필요성 인지

  • 클라우드플레어 + 프론트가 HTTPS로 되어 있어 백엔드도 HTTPS가 필요하다는 점을 깨달음
  • HTTP 백엔드는 브라우저에서 차단됨 (Mixed Content)

2. SSL 발급을 위한 도메인 확보

  • HTTPS 설정을 위해서는 SSL을 반드시 발급 받아야한다.
  • 또한 SSL 인증서를 발급 받기 위해서는 도메인이 필요하다.
  • 카페24를 통해 도메인 구매
  • AWS Route 53에 호스팅 영역 생성
  • 생성된 네임서버(NS)를 카페24 도메인에 등록 → 도메인과 AWS 연결 시도

3. ACM 인증서 발급 시도 (실패)

  • AWS Certificate Manager(ACM) 사용 시, 로드 밸런서(ELB)으로 인스턴스 생성해서,
    route53에 등록한 도메인을 우리 서버에 연결 하고 인증서를 발급받아야한다.
  • 그러나 프리 티어 환경에서는 단일 인스턴스만 사용 가능 → ELB 불가
  • 결국 ACM을 통한 인증서 발급 실패

4. 무료로 할 수 있는 방법 탐색 → Let's Encrypt(Certbot) 선택

  • 무료로 SSL 인증서를 발급해주는 비영리 인증기관(CA)
  • 카페 24에서 도메인 등록까지 완료한 후에 서버 콘솔에서 파일을 수정하면된다.
  • Nginx 설정 파일 (nginx.conf)에 SSL 적용
  • 그러나, 서버 재시작 시 설정이 초기화되는 문제 발생

5. Elastic Beanstalk(.ebextensions) 시도

  • .ebextensions로 설정 유지 시도 → 실패
    Elastic Beanstalk 전용 설정 폴더 및 스크립트 시스템으로,
    .ebextensions 디렉토리 안에 YAML 형식의 구성 파일을 넣으면, 앱 배포 시 자동으로 해당 설정을 실행

6. Spring Boot에서 직접 SSL 적용 시도

  • 서버 콘솔에서 인증서 발급 → .p12.jks 형식 변환
  • application.yml에 SSL 설정 추가
  • 그러나 현재 Nginx가 SSL을 처리하고 있기 때문에, Spring Boot에서 내장 톰캣 서버에서 SSL을 사용하는 설정은 필요 없다함

7. finally

  • 서버를 재배포 했을 때, 수동으로 인증서를 발급받아 재설정을 해주는 방식을 했다.
  • 명령어는 다음과 같다

    sudo certbot --nginx -d 서버도메인


2. 💰 비용 발생 문제

배포를 테스트한 첫날부터 약 3일간 비용이 갑자기 치솟아 당황했던 기억이있다.
비용 청구서를 토대로 구글링을 하며 비용이 왜 발생했는지를 찾았다.

1. 프리티어에서 비용발생

  • 퍼블릭 IPv4 발급 후 미사용된 것을 발견하고, 릴리스를 통해 해결.
  • 그러나 추가적으로 비용이 발생한 것을 발견
  • 추가 비용 발생 → RDS가 퍼블릭 IP를 사용 중인 문제를 확인하고, 이를 프라이빗 IP로 수정하여 해결.

2. AWS 과금 정보 및 비용관리 탭

  • 해당 탭에서 비용이 어디서 발생했는지를 상세히 확인가능.
  • Route53 을 이용해서 인증서 발급 시도했던 것으로 일부 발생.
  • 잦은 재배포로 인해 S3 시용량이 한도 초과
  • Data Transfer 사용량이 한도 초과
    로스트아크 Open API에서 잦은 요청을 통해 발생한 데이터 전송량 증가가 원인인 것으로 판단.

3. 해결

  • 비용이 많이 나온 것은 퍼블릭 IPv4 발급으로 인한 비용청구나, RDS가 퍼블릭 IP를 통한 비용이 많이 나온 것이기에 이를 수정하며 해결하였다.
  • 이외의 비용 청구들은 Data Transfer 사용이나, S3의 한도량 초과 문제인데, 이는 찾아보니, 프리티어 한도를 초과해도 발생하는 비용이 굉장히 작아 비용 추세를 보고 조절하기로 하였다.
  • 배포 첫 12월은 여러가지 문제로 US$2.25가 발생했지만, 이후 달들은 평균 US$0.14가 발생했다.
    약 한달의 192원 정도 발생했기에, 그대로 두기로 하였다.

3. 📦 JSON 파일 생성 경로 관련

내 서버 코드를 보면 JSON파일을 통해 데이터를 저장하고, 프론트로 전달하는 방식이다.
그러나, 해당 방식으로 동작시, 정상적으로 동작하지 않았으며 이를 해결하려는 시행착오를 겪은 내용이다.

1. JSON 파일 경로 지정 오류

  • application.yml을 통해 JSON 파일의 경로를 지정했지만,
    해당 경로는 로컬 테스트 환경을 기준으로 설정되어 있어, 배포 서버에서는 파일 생성 오류가 발생함 ❌
  • 상대경로를 통해서 해두었기에, 로컬과 배포 서버 사이에서 차이가 없을 것이라 생각했지만,
    Elastic Beanstalk에 배포하게되면 코드 자체를 배포하는 방식이 아니라, .jar 같은 결과물을 가져다가 실행하기 때문에,
    코드 내에서 JSON파일을 생성하게 되면, .jar이 실행되는 디렉토리에서 파일이 생성되게된다.

2. 배포 환경 경로 문제 해결 시도

  • EC2 인스턴스에 접속하여 .jar 파일의 실제 위치 확인
  • .jar 파일이 위치한 디렉터리 옆에 JSON 파일이 생성되도록 경로를 수정함

3. PuTTY

  • 이전에 버추얼머신이나, 라즈베리파이를 작업했을 때 PuTTY를 이용했던 경험이 있다.
    해당 경험을 토대로 PuTTY를 내가 배포한 AWS환경에서 적용해 보려했다.
  • Key Pair를 붙여주고 SSH 설정을 수동으로 수정
  • 보안 그룹에 SSH 접근을 허용
  • .pem.ppk로 변환하여 PuTTY에 설정
  • 을 해보았지만, 실패하여 EC2에서 제공하는 터미널을 사용하였다.

4. 🖥️ 크롤링

우리는 크롤링을 통해 인게임의 보석 데이터를 쌓고 이를 기반으로 정보를 제공해야하는데, AWS Free Tier로 크롤링을 진행하면
여러 가지 문제가 발생할 가능성이 높다.

1. 리소스 문제

  • AWS 프리티어 한도 내에서 크롤링을 진행하면 리소스가 부족해질 수 있음.
  • 잦은 데이터 요청으로 인해 서버에 과부하가 발생할 우려가 있음.
  • 요청 속도 제한이나 서버 성능 문제로 크롤링 시간이 길어짐.

2. 데이터 오류 문제

  • 로컬 환경에서 테스트할 때 정상적으로 동작하던 크롤링이, 서버 환경에서는 잦은 데이터 오류를 발생시킴.
  • API 응답 지연이나 서버 과부하로 인한 데이터 누락 또는 잘못된 데이터 처리 발생.

3. 크롬 드라이버

  • 배포된 로컬에 크롬도 설치하고 크롬 드라이버도 설치해야하며, 재배포되었을때, 해당 설치도 다시 진행해야한다는 문제점이 있다

4. 결론

  • 결국 크롤링은 데이터셋만이 필요하기에, 로컬에서 진행하는 방향으로 했다. 순서는 다음과 같다.
    (1) 로컬에서 크롤링을 해서 데이터셋을 만들고 해당 데이터를 DB에 넣는다.
    (2) 이후 해당 컬럼을 복사해서 JSON.stringify()를 거친뒤 배포된 데이터베이스에 컬럼을 추가한다.
    (3) DB에 해당 데이터를 JSON파일로 만드는 로직을 구성 후, POSTMAN을 통해서 수동으로 파일을 생성해준다.

(ci/cd 구현 출처) 스프링 부트 3 백엔드 개발자되기 자바2편 책

profile
천천히 시작하는 개발자

0개의 댓글