[프로젝트] 프랑크톤 해커톤 후기

JUJU·2024년 11월 12일
1

프로젝트

목록 보기
26/26

✏️ 플랑크톤 해커톤

서울시립대학교 TEAM BADADA에서 주최한 교내 해커톤에 참가했다.
총 40시간 동안 기획 - 구현 - 발표 준비까지 완료하는 대회였다.

키워드는 당일날 공개되었으며 #서울시, #편의, #서비스 총 3가지의 키워드를 활용하여 어플리케이션을 만들었다.


■ 주제 선정

저번 해커톤에서 아이디어의 중요성을 느꼈다.. (저번 해커톤 후기)
그래서 이번 플랑크톤 해커톤에서는 주제 선정에 정말 많은 시간을 투자했다.
대회가 시작한 뒤부터 다음날 오후 2시 정도까지 아이디어를 기획했다.

그 과정에서 아이디어를 엎기도 하고 다시 롤백하기도 했다.

아이디어는 총 3가지로 추려졌다.

  1. 한강 공원 어플리케이션
    • 한강 공원의 복잡도 해소, 공원 시설물 위치 파악
    • 너무 흔한 아이디어라서 기각

  2. 재난 문자 어플리케이션
    • 재난 문자가 왔을 때 대피소와 챙겨야할 물품 등을 알려주는 서비스
    • 재난 문자는 일반 문자와 다르게 접근 권한을 얻기가 어려움 -> 기각

  3. 축제 관리 어플리케이션
    • 대규모 축제의 관리를 위한 어플리케이션
    • 관리자가 알림을 보낼 수 있는 기능, 축제 정보를 알려주는 AI 챗봇, 축제 구역을 나눠서 혼잡도를 체크하는 기능

최종적으로 축제 관리 어플리케이션을 개발하게 되었다.




✏️ 배운점 - 개발

1. Github CI/CD

Github CI/CD

: GitHub Actions를 활용하여 소프트웨어 개발 워크플로우를 자동화하는 기능. 코드 변경 사항을 테스트하고, 빌드하며, 배포까지 자동으로 처리할 수 있다.

Github Repository에 push하면 AWS EC2에 자동으로 배포하는 기능을 구현했다.


EC2와 Docker를 이용한 배포 과정

1. EC2 인스턴스 생성 및 기본 설정

  • AWS Management Console에서 EC2 서비스를 열고 새 인스턴스를 생성한다.
  • AMI 선택 시 Ubuntu 또는 Amazon Linux를 선택한다.
  • 보안 그룹 설정을 통해 HTTP(80), HTTPS(443), SSH(22) 포트를 연다. SSH 포트는 특정 IP로 제한하여 보안을 강화한다.

2. Docker 및 Docker Compose 설치

  • EC2 인스턴스에 SSH로 접속한다.
  • 아래 명령어를 실행하여 Docker와 Docker Compose를 설치한다.
    sudo apt update
    sudo apt install docker.io
    sudo apt install docker-compose
  • 설치 완료 후 Docker 서비스를 활성화하여 부팅 시 자동으로 실행되도록 설정한다.
    sudo systemctl enable docker

3. GitHub에 배포 스크립트 및 Docker Compose 파일 설정

  • 프로젝트의 GitHub 저장소에 docker-compose.yml 파일을 추가하여 컨테이너 설정을 정의한다.
  • 자동 배포를 위해 .github/workflows/deploy.yml 파일을 추가한다. GitHub Actions 설정은 다음과 같다.
name: CI/CD Pipeline

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v2

      - name: Set up SSH Key
        run: |
          echo "${{ secrets.SSH_KEY }}" > key.pem
          chmod 600 key.pem

      - name: Create required directories on EC2
        run: |
          ssh -o StrictHostKeyChecking=no -i key.pem ubuntu@${{ secrets.EC2_IP }} "mkdir -p /home/ubuntu/app/backend/src/main/resources"

      - name: Copy application-prod.yml to EC2
        run: |
          echo "${{ secrets.YML_PROD }}" > application-prod.yml
          scp -o StrictHostKeyChecking=no -i key.pem application-prod.yml ubuntu@${{ secrets.EC2_IP }}:/home/ubuntu/app/backend/src/main/resources/application-prod.yml

      - name: Copy docker-compose.yml and project files to EC2
        run: |
          scp -o StrictHostKeyChecking=no -i key.pem -r backend frontend README.md ubuntu@${{ secrets.EC2_IP }}:/home/ubuntu/app

      - name: Deploy using Docker Compose
        run: |
          ssh -o ServerAliveInterval=60 -o StrictHostKeyChecking=no -i key.pem ubuntu@${{ secrets.EC2_IP }} "cd /home/ubuntu/app/backend && sudo docker-compose down && sudo docker-compose up -d"

      - name: Clean up SSH Key
        run: rm -f key.pem

⚠️ 위의 작업을 수행하기 위해서는 Github Secrets에 아래의 항목을 등록해야 한다.

  • SSH_KEY: EC2 접속에 사용되는 개인 키 (PEM 형식).
  • EC2_IP: EC2 인스턴스의 퍼블릭 IP 주소.
  • YML_PROD: application-prod.yml 파일의 내용.

4. Elastic IP 설정 및 도메인 연결 (Route 53)

  • AWS 콘솔에서 Elastic IP를 생성하고, 이를 EC2 인스턴스에 연결한다.
  • Route 53에서 mydomain.com 도메인에 대한 호스팅 영역을 생성하고 A 레코드를 추가하여 Elastic IP와 연결한다.

5. 자동 배포 테스트 및 확인

  • GitHub 저장소의 main 브랜치에 변경 사항을 푸시한다.
  • GitHub Actions가 실행되어 EC2에 자동으로 배포된다.
  • mydomain.com에 접속하여 애플리케이션이 정상적으로 동작하는지 확인한다.

2. 이미지 저장 로직

프론트에서 백으로 전송하는 이미지를 저장하고, 프론트가 요청할 때마다 다시 보내주는 로직을 구현해야 했다.

이전 해커톤에서 이미지를 저장하는 로직을 구현해봤었기 때문에 쉽게 구현할 수 있을거라 생각했다.


하지만

생각보다 시간이 오래걸렸다..
저번에 LingoConnect를 만들 때는 EC2에 배포하지 않았기 때문에 개발 환경에서만 어플리케이션을 실행했다.
하지만, 이번에는 EC2에 배포하였기 때문에 개발 환경이 아닌, 릴리스 환경에서 동작하는 이미지 저장 로직을 구현해야 했다.

컴파일과 jar 파일에 대한 지식이 부족해서 시간이 오래 걸린 것 같다.

First Try

처음에는 resources/static/img 에 이미지를 저장해두면 mydomain.com/img/myImage.jpg 를 통해 이미지에 접근할 수 있을 것이라 생각했다.

하지만, 당연하게도 이 로직은 동작하지 않았다.

Spring Boot 애플리케이션이 릴리스 환경에서 실행되면, 애플리케이션이 하나의 jar 파일로 패키징된다. 이때 resources/static 디렉토리에 있는 정적 리소스는 jar 파일 내부에 포함된다. 하지만, jar 파일 실행 중에 동적으로 생성된 파일resources/static 경로에 저장하더라도, 이 파일들은 실행 중인 jar 파일 내부에 반영되지 않기 때문에 외부에서 접근할 수 없다.

문제를 해결하기 위해 이미지를 직접 DB에 저장하는 방식을 사용했다.

Second Try

이미지를 BLOB로 저장
이 접근 방식에서는 이미지를 데이터베이스의 BLOB(Binary Large Object) 필드에 저장했다. 이를 통해 다음과 같은 장점을 얻었다:

  • 이미지 데이터가 데이터베이스에 저장되므로, 외부 파일 시스템을 관리할 필요가 없다.
  • 트랜잭션 관리가 용이해져 데이터 일관성을 보장할 수 있다.


    그러나 단점도 존재한다:
  • 이미지 파일 크기가 클 경우 데이터베이스 크기가 빠르게 증가하여 성능에 영향을 미칠 수 있다.
  • 빈번한 파일 저장 및 읽기 작업이 데이터베이스의 부하를 증가시킬 수 있다.

이 방식은 간단한 이미지 관리에는 적합했지만, 대규모 애플리케이션에서는 성능 문제를 야기할 가능성이 있었다.


일단 시간이 없었기 때문에 위의 방식을 사용했다. 해커톤이 끝난 뒤에 찾아보니 아래와 같은 방법도 있다고 한다.

외부 파일 시스템 사용

애플리케이션 외부 경로에 파일을 저장하고, 이 경로를 Spring Boot에서 제공할 수 있도록 설정한다.

  • 파일을 /opt/app/images/와 같은 경로에 저장하고, Spring Boot의 WebMvcConfigurer를 활용해 URL로 매핑한다.
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/img/**")
                .addResourceLocations("file:/opt/app/images/");
    }
}



✏️ 배운점 - Non개발

1. 해커톤은 그만 나가야겠다

기존 지식을 테스트해보고, 빠르게 적용해보는 것은 좋은 취지이다. 하지만, 해커톤에 반복적으로 참가하다 보니 몸이 버티지 못하는 상황이 발생했다.
또한, MVP(Minimum Viable Product) 구현에 집중하다 보니 코드의 퀄리티가 떨어지고, 새로운 기술에 도전할 시간도 부족했다.


2. 프론트엔드를 배워야겠다

API 연결을 직접 테스트할 수 있는 능력이 필요하다는 것을 느꼈다. Swagger로 API를 테스트하는 것과 실제로 프로젝트에서 API가 제대로 동작하는지 확인하는 것은 다른 차원의 작업이다.
그리고 프로젝트의 전반적인 내용을 이해하고 조율할 수 있는 개발자가 있어야 결과물이 더 좋아진다는 점도 알게 되었다.


3. 또또 강조되는 아이디어

결국, 아이디어가 뛰어난 팀이 우승을 차지한다. 아이디어의 중요성을 다시 한 번 깨달았다.
이번 해커톤에서 우승을 차지한 팀은 서울시 도서 검색 어플리케이션을 개발했다.
찾아보니 비슷한 서비스가 많긴 했지만, 우승 팀은 "검색"이라는 기능에 집중해서 완성도를 높였다.
여러 기능을 조잡하게 섞기보다, "검색"이라는 기능 하나에 집중하여 서비스의 완성도를 높이고 다른 서비스들과의 차별점을 두었다.

만약 해커톤에 다시 참가하게 된다면, 조금 흔한 아이디어라도 빠르게 결정한 뒤 완성도를 높이는 방식을 채택할 것 같다.

profile
개발자 지망생

0개의 댓글

관련 채용 정보