각종 후기/우아한테크코스

[우아한 테크코스 3기] LEVEL 3 회고 (166일차)

제이온 (Jayon) 2021. 7. 17.

안녕하세요? 제이온입니다.

 

그저께와 어제, 그리고 오늘 있었던 일을 기록하려고 합니다.

 

 

PR 날릴 때는 CI만, PR이 merge될 때 CI/CD 적용하기

그 전까지는 하나의 yml에 CI/CD 흐름을 적었기 때문에 단순히 PR만 날리더라도 빌드와 테스트 이후에 배포까지 진행되는 문제가 있었습니다. 그래서 이들을 분리하기로 했습니다.

 

방법은 굉장히 간단합니다. 파일을 분리하는 것이죠. 저는 그동안 yml 파일을 분리하면 다 인식을 하는 것인지 의문이 있었는데 모두 다 정상적으로 인식하는 것을 확인했습니다.

 

 

# This workflow will build a Java project with Gradle
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle

name: Darass PR Checker

on:
  pull_request:
    branches: [ main, develop/be ]

jobs:
  build:

    runs-on: self-hosted

    steps:
    - name: Checkout code 
      uses: actions/checkout@v2
      with:
        token: ${{ secrets.MY_REPO_PAT }}
        submodules: recursive
        
    - name: Set up JDK 11
      uses: actions/setup-java@v2
      with:
        java-version: '11'
        distribution: 'adopt'
        
    - name: Grant execute permission for gradlew
      run: chmod +x gradlew
      working-directory: ./backend
      
    - name: Build with Gradle
      run: ./gradlew clean build
      working-directory: ./backend

    - name: build result to slack
      uses: 8398a7/action-slack@v3
      with:
        status: ${{ job.status }}
        fields: repo, message, commit, author, action, eventName, ref, workflow, job, took
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

 

 

이렇게 pr_cheker라는 파일을 생성하고, on 설정에서는 pr만 적어주면 됩니다.

 

 

# This workflow will build a Java project with Gradle
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle

name: Darass Push Builder

on:
  push:
    branches: [ develop/be ]

jobs:
  deploy:

    runs-on: self-hosted

    steps:
    - name: Checkout code 
      uses: actions/checkout@v2
      with:
        token: ${{ secrets.MY_REPO_PAT }}
        submodules: recursive
        
    - name: Set up JDK 11
      uses: actions/setup-java@v2
      with:
        java-version: '11'
        distribution: 'adopt'
        
    - name: Grant execute permission for gradlew
      run: chmod +x gradlew
      working-directory: ./backend
      
    - name: Build with Gradle
      run: ./gradlew clean build
      working-directory: ./backend
     
    - name: Copy built project
      if: success()
      uses: appleboy/scp-action@master
      env:
        GIT_USERNAME: ${{ secrets.GIT_USERNAME }}
        GIT_PASSWORD: ${{ secrets.GIT_PASSWORD }}
      with:
        host: ${{ secrets.EC2_HOST }}, ${{ secrets.EC2_HOST_2 }}
        username: ${{ secrets.EC2_USERNAME }}
        key: ${{ secrets.EC2_PRIVATE_KEY }}
        envs: GIT_USERNAME, GIT_PASSWORD
        source: '/home/ubuntu/actions-runner/darass_jayon_build_work/2021-darass/2021-darass'
        target: '/home/ubuntu'
        strip_components: 1
      
    - name: AWS EC2에 ssh로 접속해서 scripts 실행시키기
      if: success()
      uses: appleboy/ssh-action@master
      env:
        GIT_USERNAME: ${{ secrets.GIT_USERNAME }}
        GIT_PASSWORD: ${{ secrets.GIT_PASSWORD }}
      with:
        host: ${{ secrets.EC2_HOST }}, ${{ secrets.EC2_HOST_2 }}
        username: ${{ secrets.EC2_USERNAME }}
        key: ${{ secrets.EC2_PRIVATE_KEY }}
        envs: GIT_USERNAME, GIT_PASSWORD
        script: |
          cd /home/ubuntu
          sudo rm -rf 2021-darass
          mv workspace 2021-darass
          cd 2021-darass/backend
          docker-compose up --build -d
          
    - name: build result to slack
      uses: 8398a7/action-slack@v3
      with:
        status: ${{ job.status }}
        fields: repo, message, commit, author, action, eventName, ref, workflow, job, took
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

 

 

비슷한 방식으로 push_builder 파일을 만든 후 CI/CD 흐름을 적되, on 설정에서 push만 적어줍니다. 이것은 pr이 merge가 되는 순간 해당 pr에 있던 커밋이 push가 되기 때문입니다.

 

 

Merge된 브랜치는 자동으로 삭제하기

그동안 merge가 된 브랜치는 수동으로 지우지 않으면 그대로 남아있었습니다. 원래는 merge된 브랜치도 참고할 수도 있을 것이다라는 이유로 남겨두었으나, 난잡하기만 하지 실제로 효용성이 떨어졌습니다. 그래서 깃허브 액션으로 Merge 브랜치 삭제 자동화를 구축했습니다.

 

 

name: Delete branch on close pr
on: 
  pull_request:
    types: [closed]
  
jobs:
  delete-branch:
  
    runs-on: self-hosted
    
    steps:
      - name: delete branch
        uses: SvanBoxel/delete-merged-branch@main
        env:
          GITHUB_TOKEN: ${{ secrets.MY_REPO_PAT }}

 

 

SvanBoxel님이 개발하신 라이브러리를 활용했습니다. pr에서 closed된 타입에 대해서 merge된 브랜치를 지워주는 역할을 합니다.

 

 

깃허브 액션 실패시 알림이 오지 않는 버그 수정하기

오늘 깃허브 액션 설정 파일을 만지다 보니 배포 과정이 실패하는 문제가 있었습니다. 그런데, 중간에 오류가 생기면 슬랙 알림 작업까지 오기도 전에 끊겨서 알림이 가지 않는 버그를 발견했습니다. 이것은 코드 한 줄을 제가 빼 먹은 탓이었습니다...

 

 

    - name: build result to slack
      uses: 8398a7/action-slack@v3
      with:
        status: ${{ job.status }}
        fields: repo, message, commit, author, action, eventName, ref, workflow, job, took
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
      if: always()

 

 

바로 맨 밑에 있는 'if: always()' 설정입니다. 이것을 걸어놔야 전체적인 workflows가 실패해도 해당 작업은 반드시 실행이 됩니다. 그래야 빌드나 배포 과정에서 문제가 발생해도 정상적으로 슬랙에 실패 알림이 가게 됩니다.

 

 

 

 

이런 식으로 실패 알림이 잘 오는 것을 확인할 수 있습니다.

 

 

Self-hosted runner를 도커로 관리할 수 있을까?

 

 

위 그림은 우리 프로젝트의 아키텍쳐입니다. 여기서 잘 보시면 나머지는 모두 도커로 관리되는데 Github actions 호스팅 서버는 도커로 관리되지 않고 있습니다. 일단 이 기능 자체가 저에게 매우 생소해서 도커고 뭐고 기능 구현에 초점을 맞췄기 때문이죠.

 

그래서 오늘은 해당 기능을 도커 컨테이너로 띄우려고 노력했습니다. 방법 자체도 해당 포스팅에서 쉽게 알려주셔서 구현하는 데 어려움이 없었습니다.

 

그런데.. 한 가지 큰 문제가 있었습니다. 

 

 

    - name: Copy built project
      if: success()
      uses: appleboy/scp-action@master
      env:
        GIT_USERNAME: ${{ secrets.GIT_USERNAME }}
        GIT_PASSWORD: ${{ secrets.GIT_PASSWORD }}
      with:
        host: ${{ secrets.EC2_HOST }}, ${{ secrets.EC2_HOST_2 }}
        username: ${{ secrets.EC2_USERNAME }}
        key: ${{ secrets.EC2_PRIVATE_KEY }}
        envs: GIT_USERNAME, GIT_PASSWORD
        source: '/home/ubuntu/actions-runner/darass_jayon_build_work/2021-darass/2021-darass'
        target: '/home/ubuntu'
        strip_components: 1

 

 

바로 빌드된 프로젝트를 운영 서버를 넘기는 과정이었습니다. 기존에는 EC2 서버에서 빌드된 프로젝트 디렉토리가 있는 절대 경로를 source에 적어주었지만, 지금은 해당 빌드된 프로젝트 디렉토리가 도커 컨테이너 안에 존재했기 때문에 이 경로를 어떻게 찾아서 적어주어야 하나 막막했죠.

 

오늘은 월요일에 있을 발표 준비도 해야 하고, 일단은 CI/CD 과정이 잘 동작하고 있으므로 해당 부분은 추후 해결해 보려고 합니다.

 

 

이슈에 라벨을 다는 과정을 자동화할 수 없을까?

 

 

우리 저장소에서는 위와 같이 이슈에 백엔드/프론트엔드 라벨을 붙여서 어떠한 팀에서 구현한 기능인지 명시해 주고 있습니다. 하지만, 그렇게 중요하다고 판단하지 않아서 실수로 빼 먹는 경우가 잦습니다. 그래서 이것도 자동화할 수 없을까 생각했고, 구글링하다보니 이 기능을 제공하는 라이브러리를 찾았습니다. 다만, 처음 보는 속성이 많이 보여서 약간의 학습을 한 다음 적용해야겠습니다.

 

 

면접

저번에 S사의 면접 최종 탈락을 경험하고, E사의 1차 면접에 합격하여 그저께 최종 면접을 보고 왔습니다. S사 때만 해도 실제 기업 면접은 처음이었고 굉장히 긴장이 되고 떨렸습니다. 그렇게 있던 실력도 제대로 어필하지 못하고 머리도 하얘져서 상당히 당황을 많이 했었습니다. 하지만, 그러한 경험은 저를 더욱 성장하게 만들어 주었습니다.

 

우선 가장 많이 대답을 못했던 부분이 인프라 쪽이었는데 그 때의 생각을 되새기면서 현재 CI/CD와 인프라 구축에 많은 시간을 쏟고 있고 재미도 많이 느끼고 있습니다. 이제는 전에 대답 못했던 질문을 저만의 경험적인 답변으로 맘껏 이야기할 수 있게 되었습니다.

 

다른 기술 질문에서도 정답을 말하려는 습관이 있었는데, 그것보다는 최대한 저의 경험을 살려야겠다는 생각을 했습니다. 그리고 그렇게 답변하기 위해 다른 블로그의 멋드러진 정답을 찾기보다는 저만의 내용을 만들었습니다.

 

또한, 최종 탈락 이후 여러 번 면접을 보면서 어느 정도 여유가 생기기 시작했습니다. 전에는 딱딱하게 앉아만 있었다면, 이제는 점점 면접 내에서 자세도 조금은 풀 수 있고 면접관님이 말씀하시는 약간의 유머에 대해 웃을 수 있었습니다.

 

본론을 돌아와서 E사의 면접은 기술 실장님께서 들어오셨는데 인상도 좋으시고 분위기도 편하게 만들어주시려는 모습이 정말 좋았습니다. 그리고 기술 면접 중에 SSL 흐름을 그려보라는 질문이 있었는데, 제가 중간에 어느 정도 설명하다가 막혀도 "지금까지 80점 맞았어요. 우리 한 번 노력해서 100점 맞아봅시다!" 라고 밝게 말씀해 주시고 힌트도 주시는등 면접자가 답변을 잘할 수 있도록 해 주셨습니다. 또한, 단순히 저를 평가하기 위한 질문 말고도 앞으로 훌륭한 개발자가 되기 위해서는 어떻게 해야하는지 귀한 조언도 해 주셨습니다.

 

답변을 완벽하게 못한 질문도 있었지만, 면접 내내 미소를 지으면서 면접을 즐기고 온 것 같습니다. 다음 주 최종 결과가 나오지만, 결과와는 무관하게 이번 면접은 제가 성장했음을 느낄 수 있어서 만족스러웠습니다.

 

 

정리

이틀 간 개발적인 부분과 면접 부분에서 많이 성장했다고 생각합니다. 그리고 포비가 말씀해 주신 "조급해 하지 말고 여유 있게 학습에 집중했으면 좋겠다.' 라는 조언을 잘 새기면서 앞으로도 여유있게 학습해 보려고 합니다.

댓글

추천 글