Github Action

사용할 장치

  • CICD에는 몇 가지 도구가 있습니다.
    1. Github 액션 CI/CD
    2. 젠킨스
    3. Travis CI + AWS 코드 배포
    4. AWS CodePipeline
  • Jenkins를 사용하기 때문에 AWS EC2는 Jenkins에 대해 하나의 인스턴스만 사용해야 합니다.
  • 위의 단점으로 인해 남은 도구인 Github Action CI/CD, Travis CI + AWS CodeDeploy, AWS CodePipeline을 고민했습니다.
  • Travis CI + AWS 코드 배포
    • Github에 연동되어 설치가 필요 없다는 장점이 있지만 private repo의 경우 1유로의 비용이 듭니다. (한 달에 $69입니다.)
    • 유료라서 제외했습니다.
  • AWS CodePipeline
    • AWS로 관리할 수 있다는 장점이 있지만 파이프라인당 $1 + 추가 비용이 발생합니다.
    • 유료라서 제외했습니다.
  • Github 액션 CI/CD
    • 별도의 설치가 필요 없고, 해당 repo에서 직접 관리가 가능하며, yml 파일로 쉽게 설정할 수 있는 장점이 있습니다.
    • 다만 Wido Private Repo는 유료이지만 액션타임은 2000시간까지 무료라서 툴을 선택했습니다.

실행 과정

1. 상태 확인 코드를 작성합니다.

@RestController
public class HealthCheckController {

    @RequestMapping("/healthCheck")
    public String healthCheck() {
        return "200 ok";
    }
}

2. Dockerfile을 생성합니다. → 이 파일의 최상위 루트 디렉터리에 파일을 만듭니다.


  • 도커파일
FROM openjdk:11
ARG JAR_FILE=build/libs/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ("java","-jar","/app.jar")

삼. docker-compose를 작성합니다. → docker-compose.yaml을 생성하기 위해 컨테이너만 업로드하는 경우에는 docker-compose를 사용할 필요가 없습니다.

version: '3'
services:

  web:
    container_name: web
    image: taeyun1215/ewm
    expose:
      - 8081
    ports:
      - 8081:8081
  • 컨테이너는 웹 서버 컨테이너를 시작하고 도커 허브에 업로드된 이미지를 github action으로 사용하므로 파일의 이미지 부분에 도커 허브에 업로드된 이미지 이름을 적습니다.
  • 또한 포트를 생성하여 이 EC2 서버에 배치합니다.

4. Github 작업 작성

  • 관련 저장소를 입력하고 Action → Java with Gradle → Configure 클릭


  • 이미 작성된 표준이 있지만 표준이 가장 기본이므로 무시하고 새 표준을 만들 수 있습니다.


  • 나는 다음과 같이 썼다.
name: Java CI with Gradle

on:
  push:
    branches: ( "main" )

permissions:
  contents: read

jobs:
  build:
    runs-on: ubuntu-18.04
    steps:
    
    - name: Get Github Actions IP
      id: ip
      uses: haythem/[email protected]

    - name: checkout
      uses: actions/checkout@v3

    - name: Set up JDK 11
      uses: actions/setup-java@v3
      with:
        java-version: '11'
        distribution: 'temurin'

    ## gradle build
    - name: Build with Gradle
      run: ./gradlew bootJar


    ## 웹 이미지 빌드 및 도커허브에 push
    - name: web docker build and push
      run: |
        docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
        docker build -t ${{ secrets.DOCKER_REPO }}/ewm .
        docker push ${{ secrets.DOCKER_REPO }}/ewm
        
    ## docker compose up
    - name: executing remote ssh commands using password
      uses: appleboy/ssh-action@master
      with:
        host: ${{ secrets.HOST }}
        username: ${{ secrets.USERNAME }}
        key: ${{ secrets.KEY }}
        script: |
          docker pull ${{ secrets.DOCKER_REPO }}/ewm
          docker-compose up -d
          docker image prune -f
  • 아래에서 각각 설명하겠습니다.
  • 기본 설정
name: Java CI with Gradle

on:
  push:
    branches: ( "main" )

permissions:
  contents: read
  • 이름: 작업으로 실행할 이름을 지정합니다.
  • on은 워크플로가 어떤 조건에서 실행될 것인지 지정하는 부분입니다.
  • 위 내용은 메인 브랜치에 푸시될 때마다 재배포해야 합니다.
  • 자바 설치
jobs:
  build:
    runs-on: ubuntu-latest
    steps:

    - name: checkout
      uses: actions/checkout@v3

    - name: Set up JDK 11
      uses: actions/setup-java@v3
      with:
        java-version: '11'
        distribution: 'temurin'
  • 직업 → 지금부터 어떤 일을 시작하고 싶은지 적어보세요.
  • running-on → 실행할 운영 체제를 지정합니다.
  • 단계 → 실행 순서를 개별적으로 설정합니다.
    • 이름 → 이름을 입력합니다.
    • used → 이미 만들어진 것을 사용하다.
    • → Java 버전과 JDK를 사용하려면 Temurin을 사용하십시오.
  • 짓다
## gradle build
- name: Build with Gradle
  run: ./gradlew bootJar
  • 기본 분기 코드를 기반으로 빌드 파일을 생성합니다.
  • 빌드 시 빌드 폴더에 JAR 파일이 생성됩니다.

  • Docker 빌드 및 Docker 허브로 푸시
## 웹 이미지 빌드 및 도커허브에 push
- name: web docker build and push
run: |
  docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
  docker build -t ${{ secrets.DOCKER_REPO }}/ewm .
  docker push ${{ secrets.DOCKER_REPO }}/ewm
  • 실행 부분에서 스크립트를 실행하기 위한 스크립트를 작성합니다.
  • ${{ secrets.DOCKER_USERNAME }}, ${{ secrets.DOCKER_PASSWORD }, ${{ secrets.DOCKER_REPO }} 세 가지 매개변수 모두 Github 저장소 비밀 탭에 삽입됩니다.
  • 위 부분은 코드 설명이 끝난 후 작성하도록 하겠습니다.
  • 도커 로그인 → 도커 빌드 → 도커 푸시로 이어지는 논리이고 간단한 도커 명령이므로 계속 진행하겠습니다.
  • AWS EC2에 연결하고 Docker로 배포
## docker compose up
- name: executing remote ssh commands using password
  uses: appleboy/ssh-action@master
  with:
    host: ${{ secrets.HOST }}
    username: ${{ secrets.USERNAME }}
    key: ${{ secrets.KEY }}
    script: |
      docker pull ${{ secrets.DOCKER_REPO }}/ewm
      docker-compose up -d
      docker image prune -f
  • 이미 생성된 ssh 연결 방법(appleboy/ssh-action@master)을 사용하여 EC2 서버에 들어갑니다.
  • 또한 secrets 탭에 ${{ secrets.HOST }}, ${{ secrets.USERNAME }}, ${{ secrets.KEY }} 세 개의 매개변수를 입력했습니다.
  • 스크립트 → EC2 서버에서 실행할 스크립트를 생성합니다.
    • docker pull → docker-compose up -d → docker image prune -f로 이어지는 논리입니다. docker 허브에 있는 이미지를 pull하고 이전에 생성한 docker-compose 파일을 up -d 명령으로 실행합니다.

5. 비밀 등록

  • Github Repo → Settings → Secret and Variables → Action에 접근합니다.


  • 위 페이지에서 New Repo Secret을 클릭하여 하나씩 생성합니다.
    • DOCKER_REPO → ewm (내가 올린 repo명 기준.)


  • DOCKER_USERNAME → taeyun1215
  • DOCKER_PASSWORD → 해당 비밀번호
  • HOST → EC2 퍼블릭 IPv4 및 EC2 퍼블릭 IPv4 DNS
  • USERNAME → ec2-user (최신 EC2용으로 고정)
  • KEY → EC2 생성 시 등록된 PEM 키
    • 해당 PEM 키를 찾으려면 로컬에서 cat ~/.ssh/specified pem key name.pem을 검색한 다음 —–BEGIN RSA PRIVATE KEY—– ~~~ —–END RSA PRIVATE KEY를 검색합니다. —– 전체를 복사하여 붙여넣어야 합니다. 끝에 있는 “%”는 배타적입니다.


6. 액션 런


  • github repo의 메인 브랜치로 푸시하면 자동으로 액션이 수행됩니다.
  • 실행명은 내가 지정한 Java Ci with Gradle인데 하나의 빌드로 합쳐서 지금은 하나만 나온다.
  • Checkout, Set up JDK 11 등을 내가 제공한 이름으로 순차적으로 실행하면 어디에서 오류가 발생했는지 확인할 수 있다.