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

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

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

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

오늘은 코로나 검사 결과가 아직 안 나온 팀원이 있어서 온라인으로 프로젝트를 진행했습니다.

 

코로나 검사 결과

다행히 음성이었습니다. 그리고 시간이 지나고 보니 결과가 나온 크루들은 전부 음성이었습니다. 나머지 크루들도 모두 별 탈 없기를 바라며, 하루 빨리 코로나 확진세가 잡혔으면 좋겠습니다. 이러다가 수료 전까지 루터 회관을 못 가는 것이 아닐까 걱정이 되는 군요.

 

깃허브 액션을 활용하여 EC2 인스턴스 접근하기

이전 포스팅과 다르게 CD라고 적지 않은 이유는 해당 작업이 굉장히.. 굉장히 빡셌기 때문입니다. 자동 배포 코드 쪽은 이후에 다루겠습니다.



저는 어제 분명 ssh를 통해 깃허브 액션 측에서 EC2 인스턴스에 접근하였다고 적어두었지만, 사실 그건 제대로 된 것이 아니었습니다. 제리가 임시로 ssh 접근 포트를 8000번으로 설정해 두어서 깃허브 액션에서 아무런 제약없이 접근이 가능했던 것이죠. 원래대로 ssh 접근 포트를 22번으로 바꾸고 나서는 깃허브 액션의 IP가 white list에 없으므로 접근이 불가했습니다.



처음 생각한 것은 "아, 깃허브 액션 쪽의 IP를 알아내서 보안 그룹에 해당 IP를 추가해야겠군"이었습니다. 그리고 관련 키워드로 구글링하다보니 한 블로그를 찾았습니다. 깃허브 액션을 실행하면서 동적 IP를 얻어 오고, 그 IP를 인스턴스 보안 그룹에 추가한 후 작업이 끝나면 동적 IP를 보안 그룹에서 제거하는 흐름이었습니다. 하지만, 이 과정에서 우리 EC2에 있는 액세스 키와 시크릿 키를 얻어와야했는데 씨유가 보안 상의 이유로 이것들을 발급해 줄 수 없다고 하셨습니다.



다른 방법을 열심히 찾아 보았지만 액세스 키와 시크릿 키 없이 깃허브 액션에서 EC2 인스턴스로 접근하는 방법을 끝내 찾지는 못했습니다. 그래서 슬랙에 직접 질문을 올렸고, 아래와 같은 답변을 받았습니다.

 



1번 같은 경우는 깃헙 액션 쪽에서 빌드하고 난 결과물을 도커 허브에 올리고, EC2 인스턴스에 해당 허브에 있는 이미지를 내려 받는 것입니다. 구현하기에는 편하겠지만, 결국 수동으로 EC2 인스턴스에 들어가서 이미지를 실행해서 컨테이너로 띄워줘야하는 점이 번거롭습니다.



2번은 깃허브 액션과 연동된 EC2 빌드 서버를 만들고, 해당 빌드 서버에서 운영 서버로 ssh 연결이 가능하도록 구성하는 것입니다. 저는 코드 한 번만으로 배포를 끝내고 싶어서 이 방법을 선택했습니다.



깃허브 액션 Runner라는 것을 설정해야하는데 이 문서에서 잘 설명해 주고 있습니다. 시키는 대로 명령어를 치고 빌드 서버에서 './run.sh' 명령어를 실행하면 아래와 같은 문구가 뜨면 잘 된겁니다.

 


이 상태에서 workflow가 실행되면 진행 상황이 빌드 서버와 연동됩니다. 다만, 기존의 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

 

 

바로 run-on의 속성이죠. 기존에는 깃허브 액션 내장 우분투 환경을 이용하였지만, 이번에는 우리가 구축한 빌드 서버를 이용해야 합니다. self-hosted라는 것인데, 이것은 우리가 방금 설정했던 Runner 안에 있는 라벨 중의 하나입니다.

 

 

 

여기서 self-hosted, Linux, X64 라벨이 있는데, 여기서 아무 라벨이나 run-on에 적어 주면 Runner 중의 해당 라벨이 있는 Runner가 동작합니다.



그런데, 여기서 서브 모듈 관련 에러가 발생할 수 있습니다. 다만, 이 부분은 친절하게도 오류 메시지를 다 띄워주고 Git 버전만 올려주면 됩니다.

 

 



그러면 위와 같이 빌드가 성공되었다는 메시지를 볼 수 있습니다.


이제 ssh를 통해 빌드 서버에서 운영 서버로 연결해 봅시다. 일단 코드부터 보겠습니다.

 

 

# 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: Java CI with Gradle on: push: branches: [ main ] pull_request: branches: [ main ] 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 build working-directory: ./backend - 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 }} username: ${{ secrets.EC2_USERNAME }} key: ${{ secrets.EC2_PRIVATE_KEY }} envs: GIT_USERNAME, GIT_PASSWORD script: | ls -a

 


appleboy님께서 만드신 ssh-action 라이브러리를 사용했습니다. 해당 라이브러리를 이곳에서 참고하실 수 있으며, 빌드 서버에 도커가 깔려있어야 합니다. 그리고 해당 도커를 관리자가 깔았고, 깃허브 액션의 대리인인 빌드 서버가 해당 도커를 사용할 때 관리자가 아니라서 그런 것인지 권한 오류가 발생했습니다. 그래서 아래와 같이 docker.sock 파일에 666 권한을 주었습니다.

 

 

sudo chmod 666 /var/run/docker.sock

 



이후에 여러 KEY 값들이 보이는데 각각에 들어가야할 값들은 다음과 같습니다.

 

GIT_USERNAME -> 깃허브 계정 아이디

 

GIT_PASSWORD -> 깃허브 계정 비밀번호

 

EC2_HOST -> EC2 운영 인스턴스 public DNS

 

EC2_USERNAME -> EC2 운영 인스턴스의 유저명. 주로, ubuntu

 

EC2_PRIVATE_KEY -> EC2 운영 인스턴스의 pem 키

 



여기서 깃허브 계정 비밀 번호에 특수 문자가 들어가면 골치가 좀 아픕니다. 특수 문자는 인식 안 되므로 아래 표를 보고 그 값에 맞도록 바꿔서 입력해 주시길 바랍니다.

 

 



그리고 pem 키를 어떻게 입력해야 하나 헤매실 수도 있는데, 해당 pem 파일을 notepad에 붙여 버리면 바로 딱 뜹니다. 이때 "==="로 시작하는 부분도 빠짐 없이 복사해서 시크릿에 등록하시길 바랍니다.



이 상태로 workflow를 실행해 봅시다.

 

 



이렇게 명령어에 맞는 결과가 나오면 잘 된겁니다. 이로써 우리는 깃허브 액션 측에서 운영 서버에 접근할 수 있게 되었습니다.



깃허브 액션을 활용하여 빌드된 프로젝트 운영 서버에 보내기

위 과정을 거치면 빌드 서버에는 우리가 빌드를 거쳤던 프로젝트 디렉토리가 존재하는 것을 알 수 있습니다.

 

 



위에서 darass_jayon_build_work가 바로 그것입니다. 그리고 이를 scp 통신을 통해서 운영 서버로 전송할 수 있습니다.

 

# 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

 



위에서 ssh 통신을 위해 언급드렸던 문서와 동일합니다. 단지 라이브러리만 ssh에서 scp로 바뀌었을 뿐이죠. source와 target은 아시다시피 송신자와 수신자 위치를 적는 것입니다. 여기서 strip_components 속성 없이 디렉토리를 보내면 디렉토리 구조는 아래와 같이 됩니다.

 

github - workspace - README.md - backend - src - build ... 등등

 



여기서 github라는 디렉토리는 불필요하므로 하나의 계층을 제거해 주는 명령어가 바로 strip_components입니다. 마지막으로 해당 workspace의 이름을 우리 프로젝트명에 맞게 2021-darass를 바꿔주도록 아래 ssh 통신에서 작업하였습니다.



이후에는 제리가 인프라 환경을 완전히 구축이 되는대로 docker-compose 명령어만 딱 입력해서 스프링 부트 애플리케이션을 띄우도록 만들면 끝날 것 같습니다. 이 부분은 구현이 되면 바로 기록하겠습니다.

 

빌드 서버에서 깃허브 액션 Runner 유지하기

'./run.sh'를 실행한 상태에서 빌드 서버를 닫아버리면 Runner까지 같이 닫혀버립니다. 이러한 문제도 공식 문서에서 방법을 제시하고 있습니다.

 

sudo ./svc.sh install 
sudo ./svc.sh start
sudo ./svc.sh status 
sudo ./svc.sh stop sudo

 



자세한 내용은 이곳에서 참고하실 수 있습니다.

 

 

 

정리

오늘은 깃허브 액션을 활용한 CD에만 올인했습니다. 나머지 시간은 내일 있을 면접 준비를 하려고 합니다.

댓글

추천 글