Network

[Infra] GitHub Actions + DockerHub + AWS EC2 로 프로젝트 CI/CD 구축

kyunge_ev 2023. 3. 14. 22:50

여러 프로젝트를 만들면서 배포를 할 때 '젠킨스 + Gitlab' 또는 'Gitlab'으로 CI/CD를 구축하여 배포하였다.

이건 프로젝트가 gitlab 저장소로 관리되어있어야 하는데 초반에 만들어둔 프로젝트는 github 저장소에 있다보니 기존 방법 대로 CI/CD를 하려면 gitlab으로 프로젝트를 옮기는 과정이 필요했다.

gitlab 👉 github 미러링은 해봤는데 github 👉 gitlab 미러링은 처음...

방법은 비슷하겠거니하고 찾아봤는데 "pull mirroring"을 하면된다고한다.(참고로 깃랩에서 깃헙은 push mirroring)

gitlab 미러링으로 들어가 pull로 변경하려고 보니

변경해야하는 Mirror direction이 비활성화되어 클릭이 안되는것...

찾아보니 github actions 쉘스크립트로 gitlab에 미러링(?) 되게 할 수 있으나,

https://forum.gitlab.com/t/when-mirroring-project-direction-selector-is-disabled-only-push-available/25173

 

When mirroring project, direction selector is disabled - only "push" available

I have forked a project and I want my fork to automatically pull from upstream. But the “pull” direction is not available - see screenshot

forum.gitlab.com

위의 내용을 보면 무료버전에서는 지원이 안되는것 같다.

github actions를 이용해야한다면 미러링이아닌 CI/CD를 구축해야겠다고 판단!

해당 내용을 기억하기 위해 포스팅한다.


🛠 필요한 환경

  • Docker Hub
  • AWS EC2 (Ubuntu)
  • 프로젝트가 저장되어있는 Github 레포지토리

1. CI Workflow 생성

github repository(배포할 프로젝트가 커밋되어있는) > Actions  

Java + gradle로 빌드할 것이기 때문에 해당 Configure 클릭

아래와 같은 화면이 나오는데 gradle.yml < 이부분은 원하는 title로 변경할 수 있음

.yml 파일은 자신의 환경과 맞춰서 커스텀해줘야함

완료되면 start commit 클릭

2. .yml 파일 작성

# github repository actions 페이지에 나타낼 이름
name: Java CI with Gradle

# event trigger - 이벤트가 정의되는 부분
# 'main' branch로 push 또는 pull request가 일어나 경우 해당 workflow가 실행된다.
on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

# workflow는 여러개의 job으로 구성되고 job는 또 여러개의 steps로 이루어진다.
jobs:
  build:
  	# 어떤 OS 환경에서 실행되는지
    runs-on: ubuntu-latest
	
    # JDK 설정 
    steps:
    - uses: actions/checkout@v3
    - name: Set up JDK 11
      uses: actions/setup-java@v3
      with:
      	# 자바버전은 11
        java-version: '11'
        # 이전에는 'adopt'를 사용했는데 현재는 temurin을 사용하기를 권장하고 있음
        distribution: 'temurin'
    
    # Gradle build
    - name: Grant execute permission for gradlew
      run: chmod +x gradlew
    
    - name: run build
      # test는 건너뛰고 build
      run: ./gradlew clean build -x test

gradle build 부분에서 아래 세 가지 경우를 확인하여 원하는 걸로 변경해주면된다.

난 test 수정이 좀 필요해서 test는 건너뛰고 빌드로 선택했다.

# build + test
- name: Build with Gradle
  run: ./gradlew build
  
# test에서 에러나는지 확인
- name: run test
  run: ./gradlew test

# test는 건너뛰고 build -> build에서 에러나는지 확인
- name: run build
  run: ./gradlew clean build -x test

✅ 에러

처음에 jdk 설정 부분 checkout@3 을 checkout@2로 해서 입력했는데

Node.js 12 actions are deprecated. Please update the following actions to use Node.js 16: actions/checkout@v2, actions/setup-java@v2. For more information see: https://github.blog/changelog/2022-09-22-github-actions-all-actions-will-begin-running-on-node16-instead-of-node12/.

위와 같은 에러가 났다.

찾아보니 더이상 v2를 사용하지 않기 때문에 위의 버전을 사용하라는 뜻

v2 > v3 로 변경하니 해결되었다.

3. Docker Hub 가입

docker hub에 내 프로젝트를 빌드하고 빌드한 도커 이미지를 저장해서 사용할 수 있도록 한다.

https://hub.docker.com/

 

Docker Hub Container Image Library | App Containerization

Deliver your business through Docker Hub Package and publish apps and plugins as containers in Docker Hub for easy download and deployment by millions of Docker users worldwide.

hub.docker.com

 

4. Github Acitons Docker 이미지 push 하기

github repository > Settings > Secrets and variables > Actions > New repository secret

secret 값을 입력해준다.

  • DOCKERHUB_USERNAME : Docker Hub에 등록된 유저 이름을 등록한다. 
  • DOCKERHUB_TOKEN : Docker Hub에서 발행한 token 값을 등록한다.

value 값은 한번 넣으면 그 뒤로 볼 수 없기 때문에 저장 관리를 잘해두면 좋다.

5. Docker 관련 step 추가 .yml 파일 수정

  • docker login step
  • yml 파일 > 도커 이미지 빌드 > docker hub push step

위 두가지 step 을 추가한다.

name: Java CI with Gradle

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest
	
    steps:
    - uses: actions/checkout@v3
    - name: Set up JDK 11
      uses: actions/setup-java@v3
      with:
        java-version: '11'
        distribution: 'temurin'
    
    - name: Grant execute permission for gradlew
      run: chmod +x gradlew
    
    - name: run build
      run: ./gradlew clean build -x test
    
    # docker login 설정
    - name: Login to DockerHub
      uses: docker/login-action@v1
      with:
        username: ${{secrets.DOCKERHUB_USERNAME}}
        password: ${{secrets.DOCKERHUB_TOKEN}}
    
    # docker 이미지 빌드 + docker hub push
    - name: build and release to DockerHub
      env:
        NAME: [계정명]
        REPO: [docker hub에 만들어둔 레포이름]
      run: |
        docker build -t $REPO .
        docker tag $REPO:latest $NAME/$REPO:latest
        docker push $NAME/$REPO:latest

docker hub 에 github 프로젝트 레포와 동일한 이름의 레포를 만들어두었다.

해당 레포로 빌드된 이미지를 push하고 추후 EC2로 이미지를 pull 받아올 수 있게 관리할 수 있다.

빌드하면 위와 같이 docker hub에 이미지가 생성되는걸 확인 할 수 있다.

6. Dockerfile 작성

5번으로 docker 빌드 이미지를 만들려면 아래의 Dockerfile이 프로젝트 안에 있어야한다.

나는 8080 포트를 사용중이기 때문에 8081로 실행했다.

***-0.0.1-SNAPSHOT.jar < 이 .jar 파일은 프로젝트에서 build 하면 build > libs 에 저장된다.

해당 파일명을 확인해서 변경해준다.

# APP
FROM openjdk:11-jdk

#컨테이너 안에 .jar 파일을 app.jar 파일로 복사
COPY build/libs/***-0.0.1-SNAPSHOT.jar app.jar

EXPOSE 8081

# root 대신 nobody 권한으로 실행
USER nobody
ENTRYPOINT ["java",  "-jar", "app.jar"]

7. .yml 에 deploy 관련 내용 추가하기

github aciton의 yml 파일에 deploy 관련 내용을 추가하여 내 프로젝트를 컨테이너 서버에 올린다.

name: Java CI with Gradle

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest
	
    steps:
    - uses: actions/checkout@v3
    - name: Set up JDK 11
      uses: actions/setup-java@v3
      with:
        java-version: '11'
        distribution: 'temurin'
    
    - name: Grant execute permission for gradlew
      run: chmod +x gradlew
    
    - name: run build
      run: ./gradlew clean build -x test
    
    - name: Login to DockerHub
      uses: docker/login-action@v1
      with:
        username: ${{secrets.DOCKERHUB_USERNAME}}
        password: ${{secrets.DOCKERHUB_TOKEN}}
    
    - name: build and release to DockerHub
      env:
        NAME: [계정명]
        REPO: [docker hub에 만들어둔 레포이름]
      run: |
        docker build -t $REPO .
        docker tag $REPO:latest $NAME/$REPO:latest
        docker push $NAME/$REPO:latest
     
  # 배포 스크립트 작성
  deploy:
    needs: build
    name: Deploy
    runs-on: [ self-hosted, label-development ]
    steps:
      - name: Docker run
        run: |
			# 컨테이너명으로 된 컨테이너가 올라와있으면 stop > rm > rmi 명령어를 사용하여 컨테이너와 이미지를 삭제한다.
              docker ps -q --filter "name=[컨테이너명]" | grep -q . && docker stop "[컨테이너명]" && docker rm  "[컨테이너명]" && docker rmi  "[docker hub에 올라와있는 도커 이미지명]"
              # 새로운 버전의 이미지를 컨테이너에 올린다.
              docker run -d --name [컨테이너명] [필요한 환경변수가 있으면 -e를 사용하여 넣어준다(ex)db서버 등] -p 8080:8080 [docker hub에 올라와있는 도커 이미지명]

8. runners 설정 

Settings > Actions > Runners > New self-hosted runner

 

Download / Configure 에 적힌 명령어를 차례대로 EC2에 입력해서 실행한다.

Configure의 첫 번재 코드까지 입력하면 아래 두가지를 입력해야하는 상황이 발생

1번은 복수개의 runner를 등록하게 될 때 github 상에서 구분할 수 있는 runner의 이름을 지정

2번은 실행되는 runner를 구분하기 위한 것으로 yml 파일의 deploy에서 runs-on에 설정해주었던 label-development를 입력

1,2번으로 설정한 이름들은 Settings > Actions에서 확인 할 수 있다.

여기서 중요! ./run.sh 로 실행하면 실행 후 다른 명령어를 입력할 수 없다.

nohup ./run.sh &

위 nohup 명령어를 사용하여 백그라운드로 runner를 실행시킨다.

이렇게 나오는데 해당 프로세스 아이디 이름으로 돌아가고 있다는 것을 뜻한다.

확인해보고 싶다면, 위 명령어를 입력한 위치에 nohub.out 이라는 파일이 생겼을 텐데

cat nohup.out

위의 명령어를 입력하여 보면 돌아가는 내용을 확인 할 수 있다.

 

 

 

 

 

📚 참고블로그

https://insight-bgh.tistory.com/474

 

CI/CD 구축하기(2) - Docker Hub

이번편에서는 지난 CI/CD 구축하기(1) - Github Action 이란? 에서 빌드한 결과를 Docker 이미지로 만들어서 Docker Hub에 push 해보는 과정까지 진행해보겠다. 1. Docker Hub 회원 가입 및 토큰 발행 먼저 Docker Hu

insight-bgh.tistory.com

https://zzang9ha.tistory.com/404

 

GitHub-Actions로 CI/CD 구축하기(AWS, Docker, SpringBoot)

GitHub-Actions로 CI/CD 구축하기(AWS, Docker, SpringBoot) 안녕하세요, 이번 시간에는 GitHub-Actions로 CI/CD를 구축하는 방법에 대해 알아보겠습니다. 해당 포스팅이 CI/CD를 전체적으로 포함하고 있기는 하지만

zzang9ha.tistory.com

https://velog.io/@soosungp33/Github-Actions%EC%9C%BC%EB%A1%9C-AWS-EC2%EC%97%90-CICD-%EA%B5%AC%EC%B6%95%ED%95%98%EA%B8%B0

 

Github Actions으로 AWS EC2에 CI/CD 구축하기

AWS EC2에 CI/CD 구축하기

velog.io