Github Actions CI CD 구축 내용

Github Actions CI CD 구축 내용

생성일
Nov 3, 2023 07:52 AM
상위 항목
최종 편집 일시
Last updated October 24, 2024
태그
Infra
CI/CD
하위 항목

Github Actions CI/CD 구축 내용

 

GitHub Action이 뭘까?

  • 위 링크를 읽어보면 정리가 잘 되어 있어서 이해하기 좋습니다.
이 깃헙 액션이 돌아가는 인스턴스 같은 게 있습니다.
젠킨스, 도커 등은 따로 개발자가 인스턴스에 설치과 구성을 해야 하는데 깃헙 액션을 사용하게 되면 그런 구성을 하는 데 시간을 쓸 필요가 없어 편한 것이 장점 중에 하나입니다.
하지만 우리 사정은 좀 달랐습니다.
내부망 안에서 해결해야 하기 때문에 깃헙 액션을 통해 그레이들 빌드를 하는 CI까지는 깃헙에서 제공해주는 인스턴스를 사용해서 할 수 있다고 해도 공인 아이피가 없는 내부망 서버 인스턴스에 배포할 수는 없는 상태였습니다.
따라서 선택을 해야 했습니다.
  1. 배포가 필요한 서버에 공인 아이피를 부여한다. → 인스턴스가 많아서 돈 낭비.
  1. 기존 젠킨스 체계를 유지한다.
  1. Self-hosted-runner를 쓴다.
결론 적으로 3번을 선택해서 진행하게 되었습니다. Self-hosted runner를 만들어 사용하면 Github 액션의 무료플랜인 2000분 제한도 피해갈 수 있습니다.

Self-Hosted Runner

notion image
  • platform-backend의 settings에 가보면 이런식으로 dev-infra라는 Runner가 등록되어 있다.
  • 위의 글처럼 dev-infra 인스턴스에 Self-hosted runner를 설치한 뒤 백그라운드에서 실행되게 해놓았다.
  • 실행이 잘 되고 있다면 위의 스샷처럼 Slef-hosted runner가 설치된 인스턴스가 목록에 출력되고 Status는 Idle 상태로 초록불이 들어와 있어야 한다.
  • 이렇게 해두면 이제 레포에 집어넣어 놓은 yml 파일의 내용대로 GitHub Actions가 실행될 준비가 된 것이다.

Workflows 정의

총 3가지의 workflows를 만들어 두었다.
  1. main-deploy.yml
    1. # This workflow uses actions that are not certified by GitHub. # They are provided by a third-party and are governed by # separate terms of service, privacy policy, and support # documentation. # This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle name: Deploy - Funding, Exchange, Toast, Mydata, Nice on: push: branches: [ "**/master", "**/develop"] paths-ignore: - 'kftc/**' - 'nh/**' env: LOCAL_DIR: /home/모자이크/actions-runner/_work/platform-backend/platform-backend TARGET_DIR: /home/모자이크 jobs: build-dev: if: github.ref == 'refs/heads/develop' runs-on: dev-infra steps: - uses: actions/checkout@v3 - name: Set up JDK 17 uses: actions/setup-java@v3 with: java-version: '17' distribution: 'temurin' - name: Grant execute permission for gradlew run: chmod +x gradlew # Build - name: Build with Gradle run: ./gradlew clean :funding:build :exchange:api:build :toast:build :nice:build :mydata:build -Dspring.profiles.active=dev -x test #scp to dev server and run - name: scp ssh pipelines uses: cross-the-world/ssh-scp-ssh-pipelines@latest env: LASTSSH: "kill and run boot applications" with: host: ${{ secrets.DEV_SERVER_HOST }} user: ${{ secrets.SSH_USER_NAME }} pass: ${{ secrets.SSH_PASSWORD }} scp: | "$LOCAL_DIR/funding/build/libs/funding-dev-0.0.1-SNAPSHOT.jar" => "$TARGET_DIR/funding/" "$LOCAL_DIR/exchange/api/build/libs/api-dev-0.0.1-SNAPSHOT.jar" => "$TARGET_DIR/exchange/" "$LOCAL_DIR/toast/build/libs/toast-dev-0.0.1-SNAPSHOT.jar" => "$TARGET_DIR/toast/" last_ssh: | echo $LASTSSH ls -la sh /home/모자이크/funding/run-funding.sh sh /home/모자이크/exchange/dev.sh sh /home/모자이크/toast/test.sh - name: Post to a Slack channel id: slack uses: slackapi/slack-github-action@v1.24.0 with: # Slack channel id, channel name, or user id to post message. # See also: https://api.slack.com/methods/chat.postMessage#channels # You can pass in multiple channels to post to by providing a comma-delimited list of channel IDs. channel-id: '모자이크' # For posting a simple plain text message slack-message: "✅[DEV]\n${{ github.workflow }}\n-${{ github.job }} 실행\n 결과: ${{ job.status }}" env: SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} build-prod: if: github.ref == 'refs/heads/master' runs-on: dev-infra steps: - uses: actions/checkout@v3 - name: Set up JDK 17 uses: actions/setup-java@v3 with: java-version: '17' distribution: 'temurin' - name: Grant execute permission for gradlew run: chmod +x gradlew # Build - name: Build with Gradle run: ./gradlew clean :funding:build :exchange:api:build :toast:build :nice:build :mydata:build -Dspring.profiles.active=prod -x test - name: Post to a Slack channel id: slack uses: slackapi/slack-github-action@v1.24.0 with: # Slack channel id, channel name, or user id to post message. # See also: https://api.slack.com/methods/chat.postMessage#channels # You can pass in multiple channels to post to by providing a comma-delimited list of channel IDs. channel-id: '모자이크' # For posting a simple plain text message slack-message: "🚨[PROD]\n${{ github.workflow }}\n-${{ github.job }} 실행\n결과: ${{ job.status }}" env: SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
    2. name
      1. workflow의 이름은 Deploy - Funding, Exchange, Toast, Mydata, Nice 이다.
    3. on
      1. 어떤 이벤트가 일어났을 때 이 워크플로우를 실행할 지 정하는 곳이다.
      2. master, develop브랜치에 푸시가 일어났을 때를 감지한다.
      3. 다만 paths-ignore를 통해서 master, develop 브랜치에 푸시가 일어났어도 kftc, nh 폴더에 대한 변경만 있는 경우에는 워크플로우를 실행시키지 않고 skip 한다.
    4. env
      1. 워크플로우 안에서 사용할 수 있는 공통 환경 변수를 정의할 수 있다.
      2. 파일 안에서 불러다 쓰고 싶을때는 $변수명 을 넣어주면 된다.
    5. jobs
      1. notion image
        Untitled
      2. 이 워크플로우 안에서 실행될 task를 정의하는 부분이다.
      3. jobs 안의 build-dev는 job의 이름을 정의한 것이다.
      4. if 조건을 줘서 develop 브랜치에 푸시가 된 경우에는 build-dev 잡을 실행하도록 하고 master 브랜치에 푸시가 된 경우에는 build-prod 잡이 실행되도록 한다.
      5. job의 steps
        1. notion image
          Untitled
        2. 위 그림처럼 step을 정의한 순서대로 실행된다.
        3. 최신 브랜치의 커밋을 체크아웃하고 자바 17 환경에서 돌아가도록 세팅한다.
        4. gradlew가 실행될 수 있도록 chmod +x 로 실행권한을 준다.
        5. gradle-wrapper를 사용하여 funding, exchange, toast, nice, mydata 모듈을 profile에 따라 빌드한다.
        6. ssh-scp-sshpipelines (깃업 액션 마켓에서 가장 적합해 보이는 액션을 찾아서 적용함.) 템플릿을 사용하여 빌드된 jar 파일을 scp를 사용하여 profile에 맞는 서버에 복사한다. (이 때 각 경로들이 “”로 묶여있지 않았을 때는 맨 위의 파일 하나만 복사되는 버그가 있었다.) (${{ }} 으로 정의된 변수들은 repository secrets로 아래 사진에 나와 있는 곳에서 추가하여 사용할 수 있다.)
          1. notion image
            Untitled
        7. scp가 완료되면 ssh 접속을 통해 last_ssh 아래쪽의 스크립트들을 실행하도록 하여 실행되고 있는 애플리케이션을 내리고 다시 올린다.
        8. 그 다음 이 잡의 성공 여부를 slackapi/slack-github-action 템플릿을 사용하여 dev_team 채널에 알림을 보낸다. (이를 위해 incoming_webhook이 아닌 슬랙봇을 추가하여 해결했다. incoming_webhook은 Github_Token의 권한 문제로 실행이 안되는 버그가 있어서 안됐고 봇은 봇 토큰이 따로 있어서 OAuth가 잘 동작하는 것 같다.)
  1. external-kftc-deploy.yml
    1. # This workflow uses actions that are not certified by GitHub. # They are provided by a third-party and are governed by # separate terms of service, privacy policy, and support # documentation. # This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle name: Deploy - Kftc on: push: branches: [ "**/master", "**/develop"] paths: - 'kftc/**' env: LOCAL_DIR: /home/모자이크/actions-runner/_work/platform-backend/platform-backend TARGET_DIR: /home/모자이크 jobs: build-kftc-dev: if: github.ref == 'refs/heads/develop' runs-on: dev-infra steps: - uses: actions/checkout@v3 - name: Set up JDK 17 uses: actions/setup-java@v3 with: java-version: '17' distribution: 'temurin' - name: Grant execute permission for gradlew run: chmod +x gradlew # Build - name: Build with Gradle run: ./gradlew clean :kftc:build -Dspring.profiles.active=dev -x test #scp to dev server and run - name: scp ssh pipelines uses: cross-the-world/ssh-scp-ssh-pipelines@latest env: LASTSSH: "kill and run boot applications" with: host: ${{ secrets.DEV_EXTERNAL_HOST }} user: ${{ secrets.SSH_USER_NAME }} pass: ${{ secrets.SSH_PASSWORD }} scp: | "$LOCAL_DIR/kftc/build/libs/kftc-dev-0.0.1-SNAPSHOT.jar" => "$TARGET_DIR/kftc/" last_ssh: | echo $LASTSSH ls -la sh /home/wefunding/kftc/run-kftc.sh - name: Post to a Slack channel id: slack uses: slackapi/slack-github-action@v1.24.0 with: # Slack channel id, channel name, or user id to post message. # See also: https://api.slack.com/methods/chat.postMessage#channels # You can pass in multiple channels to post to by providing a comma-delimited list of channel IDs. channel-id: '모자이크' # For posting a simple plain text message slack-message: "✅[DEV]\n${{ github.workflow }}\n-${{ github.job }} 실행\n 결과: ${{ job.status }}" env: SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} build-kftc-prod: if: github.ref == 'refs/heads/master' runs-on: dev-infra steps: - uses: actions/checkout@v3 - name: Set up JDK 17 uses: actions/setup-java@v3 with: java-version: '17' distribution: 'temurin' - name: Grant execute permission for gradlew run: chmod +x gradlew # Build - name: Build with Gradle run: ./gradlew clean :kftc:build -Dspring.profiles.active=prod -x test #scp to dev server and run - name: scp ssh pipelines uses: cross-the-world/ssh-scp-ssh-pipelines@latest env: LASTSSH: "kill and run boot applications" with: host: ${{ secrets.DEV_EXTERNAL_HOST }} user: ${{ secrets.SSH_USER_NAME }} pass: ${{ secrets.SSH_PASSWORD }} scp: | "$LOCAL_DIR/kftc/build/libs/kftc-prod-0.0.1-SNAPSHOT.jar" => "$TARGET_DIR/kftc/" last_ssh: | echo $LASTSSH ls -la sh /home/모자이크/kftc/run-kftc.sh - name: Post to a Slack channel id: slack uses: slackapi/slack-github-action@v1.24.0 with: # Slack channel id, channel name, or user id to post message. # See also: https://api.slack.com/methods/chat.postMessage#channels # You can pass in multiple channels to post to by providing a comma-delimited list of channel IDs. channel-id: '모자이크' # For posting a simple plain text message slack-message: "🚨[PROD]\n${{ github.workflow }}\n-${{ github.job }} 실행\n결과: ${{ job.status }}" env: SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
      기본 골조는 main-deploy.yml과 같다.
      다만 다른 점은 on 아래에 ignore-paths가 아니라 paths를 사용하여 kftc 폴더에 변화가 일어난 경우만 감지하도록 한 것이다.
  1. external-nh-deploy.yml
    1. 내용은 kftc의 경우와 같다.

이렇게 하여 GitHub Action을 이용한 CI/CD 구축이 완료되었다.