유니톤 11기 백엔드 참가 후기

yb__char·2024년 4월 21일
3
post-thumbnail

유니톤이 뭐니?

유니톤은 연합(United)을 의미하는 'UNI'와 해커톤(Hackathon)을 합성한 UNITHON으로 IT 커뮤니티 구성원들을 위한 행사로 즐거운 성장과 교류를 목표로 진행되는 해커톤이에요
이번 11기에 선발되는 인원은 60명으로 기획1, 디자인1, 프론트엔드2, 백엔드2명씩 구성되는 인원으로 총 10팀이 해커톤에 참여하였습니다!
작년 10기에는 공덕에 위치하는 프론트원에서 진행을 했었는데, 이번엔 엘리스랩 성수점에서 진행되었어요


유니톤 지원동기

사실 해커톤 경험이 없었기에 2박 3일동안 정말 배포-출시까지 이뤄질 수가 있나?라는 걱정이 조금 더 앞섰어요. 저는 아직 배포나 클라우드에 대한 실력이 부족하다고 생각하였고 오히려 참여하면 발목잡지 않을까 시작도 안했는데 걱정을 많이했어요😅

그래도 주위에서 후기를 들어보면 어차피 출시는 다 하게 된다, 걱정마라, 오히려 재밌어 등등 얘기들을 들으니 부담없이 도전하고자 하는 마음으로 지원서를 작성하기 시작했어요. 요즘 프로젝트를 하면서 드는 생각은 부담없이 하는 마음이 오히려 좋은 영향력을 가져오는 거 같아요. 그래서 "놀다 오자"라는 마음으로 글자를 채워나가기 시작했어요

아 그리고 IT 연합 동아리 및 커뮤니티 유경험자에게는 선발될 수 있는 이점이 있답니다! 활동했던 사람들과 교류할 수 있으며 활동에 대한 썰도 들으면서 좋은 기회라 생각해요~~


유니톤 합격!.!👏

유니톤 모집으로 구글폼을 작성하였는데, 희망하는 포지션 1지망, 2지망, 기술 스택 등등 인적사항과 자기소개서를 작성하도록 되어 있었습니다.

자기소개서 1번 문항으로 이전에 진행했던 프로젝트나 과제 등 개발자로서 협업 했던 경험과 역할 작성하였는데 디프만 14기에서 활동했던 내용을 정리하여 작성했어요. 14기에서 어떠한 역할과 기능을 개발하였고, 문제를 해결한 상황 등등 작성하였는데 협업에 대한 내용을 작성하기엔 글자수가 턱없이 부족하였고 그래서 기능 개발한 위주의 내용을 작성했어요

2번 문항으로 본인의 강점이 팀의 결과물, 팀워크, 경험 등에 어떤 영향을 줄 수 있는지 자유롭게 작성하는 항목에선 꾸준히 1일 1커밋을 한 것에 대한 내용과 14기에서 프로젝트를 빠르게 develop 하기 위한 경험들을 녹여내 작성했어요

각각의 500자로 2-3일동안 자투리 시간을 내어 자소서를 작성하였고 제출했다만 막상 작성하고 결과를 기다리니 좋은 기대를 하게 되었는데...

...헉 불합격이라니... 생각보다 지원자가 많았고, 백엔드 내에 경쟁률이 높았다고 들었어요:( 그래서 아쉽지만 다음 12기에 넣어야지 했는데 며칠 뒤 회사 출근하고 아침일과를 하고 있었는데...?

문자로 갑자기..! 충원 소식을 전달받았습니다 ㅋ.ㅋ
칼답하여 바로 참여 의사를 전달하였고 참여 확정!🔥

참가자 안내를 메일을 받으니 정말 선발된 게 실감이 되었어요🙏


유니톤 일정 및 후기

이처럼 4월 5일부터 7일까지 2박3일간 진행되는 유니톤으로 중간중간 다양한 이벤트들과 야식 행사 등 다양한 활동 또한 진행되어서 재밌었습니다:)

후원사로는 해당 이미지와 같이 점핏, 디캠프, 엘리스, F-Lab, 인프런 등 다양한 후원사들이 도서 및 프로젝트 진행을 도와주도록 많은 후원을 해주었습니다 🙌

이벤트로는 전체적으로 유니톤 팀원들과 어색한 분위기를 풀고 자유로운 소통을 위해 아이스브레이킹이 진행되었어요! 게임을 통해 퀴즈를 맞춘 사람에게는 이처럼 멘토링 티켓을 부여받는데, 멘토분들은 다들 실력이 출중하신 분들이셨는데 카카오스타일, 무신사, 쿠팡 등 다양하신 분들이 각 분야에서 멘토링을 해주셨어요
전 아쉽게도 프로젝트 하느라 시간이 안나서.... 유니톤에서 후원받은 도서 중 Do it! 점프 투 스프링 부트 3 책을 받았습니다! (나쁘지 않을지도?ㅠㅠㅋㅋㅋ)

이번 유니톤에서 주어진 프로젝트의 주제는 두 개로 기후, 평화 이중에서 한 가지 선택하는 것으로 주제보자마자 "헉" 했다. 도파민, 번아웃 등 다른 주제도 많은데 왜 두가지가 나왔나?
바로 추첨을 하기 때문이에요.

전지전능한 GPT로 공정하게 추첨을 하였고, 기후, 평화가 당첨되었다...🥲

바로 주제 선정이후 각 팀들은 웅성웅성하면서 아이디에이션을 진행했어요.
또한 제가 속한 6팀에서도 팀 아이디에이션을 정하기 바빴고 정말 주제에 대해 벙쪘던 시간이 많았던 거 같아요 ㅋㅋㅋㅋㅋ 기후는 정말 생각치못했어서...

1일차 - 아이디에이션 및 기획, 초기 세팅

우선 피그잼에서 기후에 대한 아이디어 따로, 평화에 대한 아이디어가 있다면 각각 작성하도록 이야기를 하였고, 리서치를 하면서 저는 기후에 대해서는 반려식물과 관련한 주제를 제시했어요. 마침 해커톤 시작일이 4월 5일 식목일이였기에 다른 팀원들에게 어필이 될 듯하여 직장인 및 학생들에게 반려식물 추천하는 서비스를 생각하였어요.

평화에 대해서는 맨 처음 저희 팀원인 기획자 시은님께서 "트레버"라는 책의 모티브에서 아이디어를 제시하였고, 거기서 저는 살을 붙였는데 제가 정말 힘들 때 가끔씩 쇼츠로 "나의 해방일지"를 다시 보곤해요. 그래서 해방일지에 나온 구절 몇가지를 생각하며, 누군가에게 작은 친절과 선의가 타인에게 설렘과 평화를 가져다 줄 수 있지 않을까라는 아이디어를 제시하였어요.

그렇게 "트레버"에서는 한 사람이 다른 3명의 절실히 도움이 필요한 이들을 도우면 그 세명이 또 각각 3명에게 도움을 주고.. 그런 방법으로 수십차례 이어가다 보면 인류 전체에게 도움을 줄 수 있는 아이디어에 평화와 설렘을 줄 수 있도록 해방일지와 유사한 자신의 일기를 작성하여 하루 3명에게 평화를 줄 수 있는 "평화일지" 서비스를 기획하였고, 팀원 모두가 적극적으로 긍정적으로 받아들여 develop 하기 시작했습니다!

바로 기획과 디자인이 주어지지 않았기에, 기획과 디자인 팀원은 1일차에 달리고, 디자인/기획이 나오기전까지 백엔드와 프론트엔드는 기술 스택 정의와 역할 분담 및 Github Organization 구성, 프로젝트 초기 세팅을 한 다음에 다들 집에 다녀오거나 해커톤 장에서 쉬면서 1일차를 보내기로 하였습니다.

백엔드 기술 스택

  • Java 17, Spring boot, Spring Data JPA, Querydsl
  • Spring Security
  • MySQL
  • AWS
    • EC2
    • S3
    • RDS
    • Code Deploy
    • Load Balancer
    • Route53
    • ACM

이와 같은 기술 스택을 선택하였습니다. Spring boot와 JPA는 평소 사용했던 기술이기에 무리없이 소화를 해내었어요. 새롭게 Kotlin + Spring boot를 하기엔 제가 아직 미숙해서... 해커톤 특성인만큼 빠르게 develop 하기 위해 익숙한 기술 스택을 사용하였고, RestControllerAdvice - GlobalResponse, Querydsl, DB 등등 초기 세팅을 시작으로 2일차에 develop 하기 위한 준비를 하였습니당

2일차 - 개발이라쓰고...!

기획에서 로그인/회원가입에 대해 카카오 OAuth를 하려니 머리가 새하얘졌다. 재작년 쯤 "시니어스"라는 프로젝트를 하면서 야매로 개발했던 카카오 로그인 구현을 다시금 상시시키며 공부하면서 개발을 하였고 이번엔 야매로 했던 기억을 제대로 알고 쓰자는 마인드로 개발과 리팩토링을 동시에 진행하였다.

카카오 developers 사이트에 필요한 환경구성부터 client-id, client-secret 등등 발급과 getProvider,,WebClient 통신,, 토큰 발급까지 이걸 로컬에서 4시간만에 끝내다니...?
잠깐씩 보았던 Kakao 로그인 다이어그램을 허투로 본게 아니구나라는 뿌듯함을 얼른 담당 프론트엔드 개발자에게 자랑하러 갔었다 😆

그런데 "아차차... 배포 안했구나..."
...

그래서 호다닥 AWS에서 EC2 서버 생성부터 IAM 권한 부여, S3, Code Deploy, RDS 생성 및 파이프라인 연결 등등 구성을 시작하였습니다. 2일차 3시쯤인가 AWS 배포를 하려니 "와 정말 시간이 부족하다..."라는 생각으로 초조해지기 시작했어요 ㅋㅋㅋㅋㅋㅋㅋㅋ 이쯤 아마 거의 실성하면서 구성했어요

환경 구성 후에 배포 스크립트를 작성하였고, main, develop, feature 브랜치로 구분한 git-flow 방식이기에 main에 push 이벤트 발생 시 즉시 배포, develop에는 PR 시 자동으로 check를 하여 이상이 없는 지 확인했어요.

# main
name: Daybook - BackEnd - CD

on:
  push:
    # main branch에 push(merge)될 경우 실행됩니다.
    branches: [ "main" ]

permissions:
  contents: read

jobs:
  build:
    # build를 진행할 운영체제를 선택합니다.
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3
      # JDK를 11 버전으로 셋팅합니다.
      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'temurin'

      - name: Setup Gradle
        uses: gradle/gradle-build-action@v2
        with:
          arguments: check
          cache-read-only: ${{ github.ref != 'refs/heads/main' && github.ref != 'refs/heads/develop' }}

      # 프로젝트 저장소에 업로드하면 안되는 설정 파일들을 만들어줍니다.
      - name: Make application.yml
        run: |
          # 필요한 yml 파일들을 만들어줍니다.
          mkdir -p ./src/main/resources
          echo "$APPLICATION" > ./src/main/resources/application.yml
        env:
          APPLICATION: ${{ secrets.APPLICATION }}
        shell: bash

      - name: Gradle 권한 부여
        run: chmod +x gradlew

      - name: Gradle로 빌드 실행
        run: ./gradlew bootjar

      # 배포에 필요한 여러 설정 파일과 프로젝트 빌드파일을 zip 파일로 모아줍니다.
      - name: zip file 생성
        run: |
          mkdir deploy
          cp ./docker/docker-compose.blue.yml ./deploy/
          cp ./docker/docker-compose.green.yml ./deploy/
          cp ./appspec.yml ./deploy/
          cp ./docker/Dockerfile ./deploy/
          cp ./scripts/*.sh ./deploy/
          cp ./build/libs/*.jar ./deploy/
          chmod +x ./deploy/deploy.sh
          zip -r -qq -j ./daybook-app.zip ./deploy

      # AWS에 연결해줍니다.
      - name: AWS 연결
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ secrets.AWS_REGION }}

      # S3에 프로젝트를 업로드 합니다.
      - name: S3에 프로젝트 업로드
        run: |
          aws s3 cp \
          --region ap-northeast-2 \
          ./daybook-app.zip s3://daybook-server

      # CodeDelploy에 배포를 요청합니다.
      - name: Code Deploy 배포 요청
        run: aws deploy create-deployment --application-name daybook-code-deploy-app
          --deployment-config-name CodeDeployDefault.AllAtOnce
          --deployment-group-name daybook-code-deploy-app
          --s3-location bucket=daybook-server,bundleType=zip,key=daybook-app.zip
# develop
name: develop(pull_request) Test
on:
  pull_request:
    branches:
      - develop
jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        java-version: [ 17 ]
    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Set up Java
        uses: actions/setup-java@v3
        with:
          java-version: ${{ matrix.java-version }}
          distribution: 'adopt'

      - name: Grant execute permission for gradlew
        run: chmod +x ./gradlew

      - name: Setup Gradle
        uses: gradle/gradle-build-action@v2
        with:
          arguments: check
          cache-read-only: ${{ github.ref != 'refs/heads/main' && github.ref != 'refs/heads/develop' }}

사실 테스트 서버가 있다면 조금 더 매끄럽게 프로젝트를 진행할 수도 있겠지만, 해커톤이니까... 라는 생각으로 빠르게 배포하는 게 목적이였습니당 이후 배포가 완료되었을 시에는 아래 시스템 아키텍처의 구성을 가지게 되었고

여기서 Nginx같은 경우는 EC2 내부에서 진행을 하려다가 우선적으로 http의 배포하였습니다 모든 과정을 완벽하게 배포하기엔 프론트엔드가 작업 시간이 부족할 수도 있어서 3일차에 Load Balancing을 통해 https 배포까지 했어요.

2일차 트러블 슈팅

  1. 배포는 어느 정도 끝났으니 이제 붙여놓은 actuator health-check를 확인해보니?
    Welcome to nginx 페이지를 확인하게 되었... 와 뭐지..
    바로 서버 접속해서 sudo vim /etc/nginx/nginx.conf 로 nginx config 파일을 확인해봤어요
    server {
         # listen 80
         location / {
                proxy_pass http://localhost:8080;
                proxy_set_header Host $http_host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Scheme $scheme;
         }
    }

사실 개인적으로 무중단 배포를 하기 위해 8081, 8082를 처음에 구성하다가 생각보다 잘안되고, deploy.sh를 작성하는데에 공수가 들어서 단일 port로 해결하였습니다! 그래서 8080에 대한 proxy 설정을 안해줬었고, 80 server 블럭 내에 작성하고 restart 해도 안되는 현상이 있어 바깥쪽에 config 하여 http://{탄력적 IP}/{health-check uri}를 접속하니 올바르게 동작되었네요🤔

그렇게 배포를 성공하고 같이 작업하던 백엔드 팀원이 개발한 도메인 피처 기능을 붙여 사용해보는데...
또 조졌네 이거.. SecurityContext에 사용자 정보를 못가져와서 대략 난감했던 상황이 왔어요.
UserDetails를 통해 context에 있어야할 memberId가 Null인 상황이니
그래서 TokenFilter 코드를 뜯어보면서 setAuthentication을 하는 데에는 문제가 없었어요.
문제는 바로 decode할 getClaims 메서드인데, token을 decode하는 데에 있어서 SecretKey를 올바르게 decode하지 못한 점이였던 것이였습니다🥲

private static SecretKey createSecretKey(String key) {
		byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
		return new SecretKeySpec(keyBytes, SignatureAlgorithm.HS256.getJcaName());
}

private Map<String, Object> getClaims(String jwt) {
		try {
			if (jwt == null || jwt.isEmpty()) {
				return null;
			}
			// SecretKey key = createSecretKey(secretKey);
			return Jwts.parserBuilder()
				.setSigningKey(key)
				.build()
				.parseClaimsJws(jwt)
				.getBody();
		} catch (Exception e) {
			// 예외 처리
			e.printStackTrace();
			return null;
		}
	}

jwt 토큰이 property로 가져온 secretKey가 정상적으로 만들지 못해 올바르지 않는 secretKey라고 명시가 되어있었고, 주석처리한 SecretKey key를 넣어 올바른 SecretKey를 생성해 signing이 이루어져 decode 할 수 있었습네다.... 이걸 3시간동안 찾고 있었던 나.. 반성해..

그렇게 resolver와 커스텀 어노테이션을 구성하여 UserDetails에 있는 memberId를 활용하여 도메인 개발을 2일차 밤 8시에 진행하게 되었습니다

3일차 - 벌써 엔딩..?

3일차 새벽 12시?1시쯤에 이슈가 터졌어요.
새벽에 1차적인 작업이 끝나고 프론트엔드에서 도메인 구입과 배포를 진행하였고, https인 프론트엔드 도메인이 http인 백엔드 API 엔드포인트를 호출했을 때 발생되는 문제 Mixed Content가 발생되었어요. 이와 같은 해결 방법도 존재하지만 보안상 찝찝하고 프론트엔드 팀원중에 AWS에 대해 잘 알고 게셔서 페어로 클라우드 환경 구성을 하였습니다
vercel 내에 도메인 연결과 동시에, ACM 인증서 발급과 Route53 A 레코드 발급을 우선적으로 진행했어요. *.도메인 으로 asterisk 표기로 ACM 인증서를 받았으며, Load Balancer를 구성하였습니다!

이때 처음으로 Load Balancer를 만져보았어요
과연 내가 잘 구성할 수 있을까란 생각보다는 벌써 구성해볼생각에 설렜달까...?

아래 링크가 저희가 구성했던 방식과 유사했어요

기본적인 네트워크 그룹 구성과 발급받았던 ACM 인증서를 등록하였고, 리스너 및 규칙을 정의했습니다!
HTTPS port는 443이기에 ACM 인증서 발급이 필수에요. 이외에는 백엔드에서 미리 개발한 health-check url을 설정하고 그랬답니다.

위와 같이 구성을 하였고, 이제 api 도메인을 통신하는데 놀랍게도 타임아웃....
타임아웃이 일어난 이유는 보통 95퍼가 보안 그룹 이슈라더고요
그래서 바로 보안 그룹 이슈를 보면서... 둘 다 밤을 새서 그런가 넣고자 한 보안그룹을 잘못넣었어요 ㅋㅋㅋㅋ
바로 해결하였고, 새벽 3시에 배포를 완료했어요 👏👏

이 로그인 페이지가 누군가에게는 단순한 페이지일지라도 접속이 되는 순간 "와...됐다..!"도 잠시
응 정신차려~ 바로 리액션 기능과 댓글 기능을 만들었어야 해서 다대다 테이블 매핑부터 진행하고 도메인 피처 개발을 진행했어요 ㅋ.ㅋ

새벽 4시쯤엔가 1시간만에 댓글, 리액션 MVP 기능을 개발하였고, 5시에 처음으로 해커톤장에서 쪽잠을 잤습니다😵‍💫
그렇게 8시에 다시 눈뜨고 다들 QA가 한창이여서 QA 버그사항을 반눈 뜬채로 수정하고 배포하고 반복 후 10시에 프로젝트 발표 전까지 코드만 두들겼슴다 ㅎㅎㅎ


그렇게 10시까지 저희 팀이 하고자 했던 MVP 기능 개발을 완료했습니당
10시 이후에는 유니톤 모든 팀들이 준비한 발표를 진행하는 시간을 가졌어요~
어떠한 팀은 iOS, Android 앱 프로젝트였는데, iOS 같은 경우 2박3일 기간 내에 애플 로그인도 붙여서 서비스를 만들고, AI를 붙인 팀도 있어서 다들 생각보다 퀄리티가 굉장히 높았던 기억이 있네요:)

발표 이후에는 각 팀의 시연 부스를 돌아다녀 체험해볼 수 있는 시간을 가지는데, 다들 기후, 평화라는 주제를 가지고 재밌는 서비스를 만들어냈더라고요.

저희 팀도 우당탕한 시연부스를 만들고 다들 디자인과 설계에 대한 칭찬을 아낌없이 해주어서 그저 감개무량...
어느 팀은 앱 네이티브에서 목탁 소리가 둥둥둥... ㅋㅋㅋㅋ 개인적으로 인상 깊었던 팀이였는데 계속 서비스 해줬으면 좋겠어요 ㅋㅋㅋㅋㅋ

그렇게 대망의 마지막 일정인 수상식이 진행되고 아쉽게 저희 팀은 수상하지 못했어요ㅠㅜ

제가 배포를 조금만 더 빨리해서 다른 팀에게 홍보하고, UT까지 진행하고자 한 욕심이 있었는데 아쉽게도 받을만큼의 시간이 없었습니다 🥲
사실 유니톤 참가 확정이 나왔을때 수상까지 하고 싶은 약간(?) 의욕심(의욕+욕심)이 있었어요 (우리 디프만 10분만팀이 그렇게 언급해달라고...)
그렇지만 아쉽다는 마음보다는 새롭게 성장할 수 있는 포인트와 빠르게 develop 하면서 저에게 부족한 점을 명확히 알게 된 첫 해커톤이였어요
만약 다음 12기에서도 기회가 된다면 수상을 목표로...! 12기에서 만나는 사람들과 프로젝트를 재밌게 이어나가보고 싶네요:)

Github Repo

굿즈는 못참지~

profile
안녕하세요 백엔드 개발자 차윤범입니다 :)

0개의 댓글

관련 채용 정보