🤔 개발자라면 꼭 마주하게 되는 CI/CD 과정 어떤 도구를 활용하는 것이 좋을까요?
JetBrains에서 조사한 통계를 알아보겠습니다.
❗ 매년 조금씩 바뀌지만, GitHub Action과 Jenkins는 항상 상위권에 있는 것을 확인할 수 있습니다.
따라서, 두 가지 CI/CD 방법에 대해서 다뤄볼 생각입니다. 우선 두 가지 CI/CD 도구가 어떤 차이를 가지고 있는지 비교해 보겠습니다.
다음과 같은 차이점들이 있는데 결과적으로는 Jenkins는 초기 세팅이 Github Action보다는 조금 더 복잡하지만 확장성이 좋다고 볼 수 있습니다. 그만큼 Github Action은 사용하기 조금 더 쉽다는 장점이 있습니다.
⚠️ 그런데 CD 작업에서 Github Action을 사용하게 된다면 여러 서버들을 public IP로 설정해야 된다는 단점이 존재하기도 합니다.
(Jenkins는 AWS VPC 내부에 존재하는 EC2에 띄워서 private subnet에 존재하는 인스턴스에 접근 가능하게 만들 수 있지만, Github Action은 외부에 존재하는 클라우드라서 private 인스턴스에 접근하기 힘들기 때문입니다!)
결과적으로 두개를 모두 알아볼 예정인데, 이번 시간에는 Github Action에 대해서 먼저 알아보겠습니다.
✅ Github Actions 구조와 기본 용어
💠 워크 플로우(Workflow)
기본적으로 깃허브 워크 플로우는 위의 사진에 포함되는 요소들을 가지고 있습니다.
하나의 실행 단위, 하나의 프로세스라고 생각하시면 됩니다(하나의 쉘 스크립트라고 생각해도 좋습니다).
워크플로는 리포지토리의 .github/workflows 디렉토리에 정의됩니다. 이곳에 yml 파일을 만들기만 하면 됩니다! 리포지토리에 다음과 같은 각각의 다른 작업 집합을 수행하는 여러 워크플로가 있을 수 있습니다.
워크 플로우는 다음과 같은 내용들을 포함하고 있습니다
- Event
- Runner
- Job
- Action
💠 이벤트(Event)
워크플로우가 실행되는 조건(트리거)에 해당됩니다. (if문이라고 생각하셔도 좋습니다)
이벤트의 조건이 충족되게 되면 워크플로우가 실행되게 됩니다.
ex) A 브랜치에 push를 할 경우, B 브랜치에 pull request를 할 경우
💠 러너(Runner)
Runner의 내부에서는 Job들이 실행이 됩니다
러너는 말그대로 Job의 행위를 실행(Run)시켜 주는 VM 머신입니다. Ubuntu와 node 등 다양한 환경에서 Job을 실행시켜 줄 수 있습니다.
💠 작업(Job)
이것 역시 Runner에서 실행되는 워크 플로우의 단계 집합입니다. 여러개의 단계는 동일한 Runner에서 실행되며 앞 단계에서 생성된 데이터를 다음 단계에서 사용할 수 있습니다.
💠 액션(Actions)
GitHub Actions에서 제공하는 기본 기능을 확장하는 모듈입니다. 자주 사용되는 반복 작업을 자동화하여 워크플로우를 간결하게 유지
할 수 있도록 만들어져 있습니다.
사용자가 직접 작성 가능하며, GitHub Marketplace에서 가져와 사용 가능합니다!
Github Action에서 가장 중요한 기능이라고 해도 무방합니다.
😀 즉, github/workflows 디렉토리에 특정 조건(Event)에 따라서 여러 작업(Job)들이 특정 러너(Runner) 위에서 실행되도록 쉘 스크립트를 작성하는 것이 전부입니다.
이제 각각의 기능에 대해서 구체적으로 알아보도록 하겠습니다.
✅ 이벤트(Event)
💡 공식 문서에 있는 내용을 다 써보았는데요 ... 꽤 많이 있습니다. 가볍게 읽고 넘어가시면 좋을 것 같아요!
CI/CD와 관련되어서 사용될 것 같은 기능들은 ⭐ 표시를 해두겠습니다..
💠 branch_protection_rule
브랜치 보호 규칙이 변경될 떄 실행되는 트리거
- created : 새로운 보호 규칙이 생성될 때
- edited : 기존 보호 규칙이 수정될 때
- deleted : 보호 규칙이 삭제될 때
on:
branch_protection_rule:
types: [created, deleted]
jobs:
notify:
runs-on: ubuntu-latest
steps:
- name: Notify on Branch Protection Change
run: echo "Branch protection rule was created or deleted!"
다음과 같이 규칙에 변화가 생기면 작동되도록 설계할 수 있습니다. 웹훅 이벤트입니다. 이는 특정 이벤트가 발생했을 경우 지정된 URL로 데이터를 전송할 수 있는 기능입니다.
💠 check_run
GitHub에서 실행되는 테스트(예: GitHub Actions, Jenkins, CircleCI)가 실행되면 작동하는 트리거입니다. 인텔리제에서 돌리는 Test를 의미하는 것이 아닙니다!!
- created : 체크 실행이 새로 생성될 때
- rerequested : 체크 실행을 다시 요청할 때
- completed : 체크 실행이 완료될 때
- requested_action : 특정 작업을 요청할 때
//예시 1: Slack으로 알림 보내기
on:
check_run:
types: [completed]
jobs:
notify:
runs-on: ubuntu-latest
steps:
- name: Send notification to Slack
uses: slackapi/slack-github-action@v1
with:
channel-id: "#ci-status"
slack-message: "Check run has been completed!"
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
//예시 2: 특정 체크가 실패할 경우 재실행
on:
check_run:
types: [completed]
jobs:
retry_failed:
runs-on: ubuntu-latest
if: ${{ github.event.check_run.conclusion == 'failure' }} # 실패한 경우만 실행
steps:
- name: Retry check run
run: echo "Check run failed, retrying..."
check_run 역시 웹훅 이벤트입니다. 예시에서 보여준 Slack 알림 전송처럼 테스트와 관련하여 실패 감지 및 알림으로 활용가능합니다.
💠 check_suite
여러개의 check_run을 하나로 묶어서 테스트 그룹이 전부 실행되고 나면 check_suite이 발생하고 이것을 트리거로 사용합니다.
- completed : 모든 체크 실행이 완료된 경우.
웹훅 이벤트입니다.
💠 create
이벤트는 새로운 브랜치(Branch) 또는 태그(Tag)가 생성될 때 트리거되는 웹훅 이벤트입니다. 즉, GitHub 저장소에서 새로운 브랜치나 태그가 만들어지면 자동으로 워크플로우가 실행됩니다.
- 3개 이상의 태그를 한 번에 생성 시 발생 x
💠 delete
이벤트는 새로운 브랜치(Branch) 또는 태그(Tag)가 삭제될 때 트리거되는 웹훅 이벤트입니다.
- 3개 이상의 태그를 한번에 삭제 시 발생 x
💠 deployment
GitHub 저장소에서 새로운 배포(Deployment)가 생성될 때 발생하는 웹훅 이벤트입니다. 즉, GitHub에서 특정 브랜치나 태그를 배포 대상으로 지정하면, 자동으로 GitHub Actions 워크플로우가 실행됩니다.
curl -X POST -H "Authorization: token YOUR_GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/OWNER/REPO/deployments \
-d '{"ref":"main", "required_contexts":[]}'
🤔 위의 코드는 깃허브 API로 배포 요청을 보내는 예시입니다. 다음과 같은 요청이 왔을 때 배포되도록 트리거로 사용할 수도 있다는 뜻입니다.
💠 deployment_status
deployment_status 이벤트는 배포 상태(Deployment Status)가 업데이트될 때 발생하는 웹훅 이벤트입니다. 즉, 외부 시스템(예: AWS, Kubernetes, Heroku 등)이 배포가 성공했는지, 실패했는지를 GitHub에 보고하면 이 이벤트가 발생됩니다.
💠 discussion
GitHub Discussions(토론)에서 특정 활동이 발생할 때 실행되는 웹훅 이벤입니다.
- created : 새로운 Discussion이 생성됨
- edited : 기존 Discussion이 수정됨
- deleted : Discussion이 삭제됨
- transferred : 다른 저장소로 Discussion이 이동됨
- pinned : Discussion이 고정됨
- unpinned : Discussion 고정이 해제됨
- labeled : Discussion에 라벨이 추가됨
- unlabeled : Discussion에서 라벨이 제거됨
- locked : Discussion이 잠김 (Lock)
- unlocked : Discussion 잠금이 해제됨
- category_changed : Discussion의 카테고리가 변경됨
- answered : Discussion에서 답변이 선택됨
- unanswered : Discussion에서 답변이 제거됨
😲 이런 기능도 있는게 신기하네요..?
💠 discussion_comment
GitHub Discussions(토론)에서 댓글이 작성되거나 수정될 때 발생하는 웹훅 이벤트입니다.
- created : 새로운 Discussion 댓글이 작성됨
- edited : 기존 댓글이 수정됨
- deleted : 댓글이 삭제됨
discussion 자체의 기능과 다르게 댓글에 집중되어 있습니다.
💠 fork
누군가 GitHub 저장소를 포크(Fork)할 때 발생하는 웹훅 이벤트입니다.
on:
fork
jobs:
create-issue:
runs-on: ubuntu-latest
steps:
- name: Create an issue in the forked repository
uses: peter-evans/create-issue-from-file@v4
with:
title: "🎉 감사합니다! 저장소를 포크해주셨군요!"
body: "저희 저장소를 포크해주셔서 감사합니다! 궁금한 점이 있으면 언제든지 Issue를 남겨주세요."
labels: "welcome"
이런 식으로 저장소를 fork 해서 가져간 유저에게 Issue를 만들어 줄수도 있습니다!!
💠 gollum
Github 저장소의 Wiki 페이지의 변화를 감지합니다.
💠 issue_comment
이슈(Issue)나 풀 리퀘스트(Pull Request)에 댓글이 생성되거나 수정, 삭제될 때 실행되는 이벤트입니다.
- created : 새로운 댓글이 작성됨
- edited : 기존 댓글이 수정됨
- deleted : 댓글이 삭제됨
- 특정 단어가 포하된 댓글을 감지할 수도 있습니다. 예를 들어서 , "rerun test"를 감지해서 다시 테스트를 돌리도록 만들 수도 있겠네요.
💠 issues
이슈(Issue)의 변화를 감지합니다.
- opened : 새로운 이슈가 생성됨
- edited : 기존 이슈가 수정됨
- deleted : 이슈가 삭제됨
- transferred : 이슈가 다른 저장소로 이동됨
- pinned : 이슈가 고정됨
- unpinned : 이슈 고정이 해제됨
- closed : 이슈가 닫힘
- reopened : 닫힌 이슈가 다시 열림
- assigned : 이슈에 담당자가 할당됨
- unassigned : 이슈의 담당자가 해제됨
- labeled : 이슈에 라벨이 추가됨
- unlabeled : 이슈에서 라벨이 제거됨
- locked : 이슈가 잠김 (Lock)
- unlocked : 이슈 잠금이 해제됨
- milestoned : 이슈에 마일스톤이 추가됨
- demilestoned : 이슈에서 마일스톤이 제거됨
💠 label
라벨(Label)의 변화를 감지합니다.
- created : 새로운 라벨이 생성됨
- edited : 기존 라벨이 수정됨
- deleted : 라벨이 삭제됨
💠 merge_group
merge_group 이벤트는 풀 리퀘스트가 병합 대기열(merge queue)에 추가될 때 워크플로우를 실행합니다.(pull_request 또는 push 이벤트와는 다릅니다)
💠 milestone
레포지토리 내에서 마일스톤이 생성되거나 변경될 경우를 감지합니다.
- created
- closed
- opened
- edited
- deleted
💠 page_build
GitHub Pages 사이트의 게시(publishing) 소스에 푸시(Push)될 경우를 감지합니다.
💠 public
레포지토리가 비공개(private)에서 공개(public)로 변경되는 경우를 감지합니다.
⭐ pull_request
저는 테스트 할 때에는 pull_request 트리거를 애용했습니다. 그 이유는 merge 전에 CI의 이상이 없는지? 확인하고 싶었고 머지를 수행한 이후에 확인하게 되면 또 issue를 파고 다시 pr을 요청하기 귀찮았기 때문입니다...
어느 정도 안정화가 되고 나면 merge를 기준으로 하면 좋을 것 같아요.
다양한 조건을 지정할 수 있습니다.
- assigned: 특정 사용자가 Pull Request(PR)의 담당자로 지정될 때 실행됨.
- unassigned: 특정 사용자가 PR의 담당자에서 해제될 때 실행됨.
- labeled: PR에 라벨이 추가될 때 실행됨.
- unlabeled: PR에서 라벨이 제거될 때 실행됨.
- opened: 새로운 PR이 생성될 때 실행됨.
- edited: PR의 제목이나 설명이 수정될 때 실행됨.
- closed: PR이 닫힐 때 실행됨. PR이 병합되었거나 그냥 닫힌 경우 포함됨.
- reopened: 닫혔던 PR이 다시 열릴 때 실행됨.
- synchronize: PR의 소스 브랜치(head branch)에 새로운 커밋이 추가될 때 실행됨. 즉, force push 또는 push가 발생하면 실행됨.
- converted_to_draft: 기존 PR이 Draft(초안) 상태로 변경될 때 실행됨.
- locked: PR이 잠금(Locked) 상태로 변경될 때 실행됨. 즉, 추가 댓글 작성이 제한될 때 실행됨.
- unlocked: PR의 잠금이 해제될 때 실행됨.
- enqueued: PR이 병합 대기열(Merge Queue)에 추가될 때 실행됨.
- dequeued: PR이 병합 대기열에서 제거될 때 실행됨.
- milestoned: PR에 마일스톤(Milestone)이 추가될 때 실행됨.
- demilestoned: PR에서 마일스톤이 제거될 때 실행됨.
- ready_for_review: Draft 상태였던 PR이 리뷰 가능 상태(Ready for Review)로 변경될 때 실행됨.
- review_requested: 특정 사용자 또는 팀에 리뷰 요청이 들어올 때 실행됨.
- review_request_removed: 특정 사용자 또는 팀에 대한 리뷰 요청이 취소될 때 실행됨.
- auto_merge_enabled: PR에 대해 자동 병합(Auto Merge)이 활성화될 때 실행됨.
- auto_merge_disabled: PR의 자동 병합이 비활성화될 때 실행됨.
☺️ pull request는 따로 지정을 해주지 않으셔도 opened, synchronize, 그리고 reopened시를 감지합니다! 따라서 pull_request만 트리거로 지정해 주시면 PR을 처음 올리고 브랜치에 push할 때마다 편하게 CI 실행이 가능합니다.
다만, PR에서 충돌이 발생한 경우 감지하지 않으면 이 경우 pull_request_target을 사용해야합니다.
공식 문서에 몇 가지 세세한 기능 예시를 소개해서 설명해 보겠습니다 ( 물론 간단히 프로젝트에서 CI/CD 파이프라인을 설계할 때에는 이런 기능들까지 사용하지는 않을 수도 있습니다).
on:
pull_request:
types: [review_requested]
jobs:
specific_review_requested:
runs-on: ubuntu-latest
if: ${{ github.event.requested_team.name == 'octo-team'}}
steps:
- run: echo 'A review from octo-team was requested'
- 특정 대상이 리뷰를 요청한 경우
on:
pull_request:
types:
- opened
branches:
- 'releases/**'
- 특정 브랜치를 대상으로 PR이 열린 경우. 브랜치마다 다른 CI/CD 파이프 라인을 만들 경우 많이 사용하게 되겠죠??
on:
pull_request:
paths:
- '**.js'
- 특정 파일이 변경된 PR에서만 실행
on:
pull_request:
types:
- closed
jobs:
if_merged:
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest
steps:
- run: |
echo "The PR was merged"
- PR이 닫히고 머지가 된 경우.
- 😮 저는 develop이나 main으로 push가 일어난 경우로 보통 CI/CD를 했는데 merge 기준이 조금 더 적합할 수도 있다고 생각하게 되었습니다.
+ 참고 : Fork 저장소에서는 GithubAction이 실행되지 않고 PR을 통해 기본 저장소로 요청되면 이벤트 발생. Dependabot도 비슷하게 취급됩니다.
💠 pull_request_comment(이 아니라 issue_comment를 사용해주세요)
PR 본문(설명) 아래 작성된 일반적인 댓글은 pull_request_comment가 아니라 issue_comment를 써주세요.
😓 많은 분들이 헷갈렸나 봐요..
💠 pull_request_review
이벤트는 PR에 대한 리뷰(Review) 활동(승인, 변경 요청, 의견 제시)을 감지합니다.
다음과 같은 조건 설정이 가능합니다.
- created
- edited
- deleted
on:
pull_request_review:
types: [submitted]
jobs:
approved:
if: github.event.review.state == 'approved'
runs-on: ubuntu-latest
steps:
- run: echo "This PR was approved"
- 이런 식으로 승인되었을 경우에 알림용으로 사용도 가능합니다( 웹훅 이벤트입니다)
💠 pull_request_review_comment
pull_request_review_comment 이벤트는 PR의 특정 코드 줄(diff)에 대한 리뷰 코멘트가 작성, 수정, 삭제될 때 실행됩니다.
즉, PR의 전체 리뷰가 아닌 PR 코드 변경 부분에 대한 개별 코멘트에 반응합니다.
다음과 같은 조건 설정이 가능합니다.
- created
- edited
- deleted
PR 리뷰와 관련된 이벤트 비교
- PR 자체에 대한 일반적인 리뷰 이벤트 → pull_request_review 사용
- PR의 특정 코드 라인에 대한 개별 리뷰 코멘트 → pull_request_review_comment 사용
- PR 본문에 일반적인 댓글 작성 → issue_comment 사용
라고 쓰여있는데요.. 사용할 일이 크게 없을 것 같기는 합니다.
⭐ pull_request_target
- assigned: 특정 사용자가 Pull Request(PR)의 담당자로 지정될 때 실행됨.
- unassigned: 특정 사용자가 PR의 담당자에서 해제될 때 실행됨.
- labeled: PR에 라벨이 추가될 때 실행됨.
- unlabeled: PR에서 라벨이 제거될 때 실행됨.
- opened: 새로운 PR이 생성될 때 실행됨.
- edited: PR의 제목이나 설명이 수정될 때 실행됨.
- closed: PR이 닫힐 때 실행됨. PR이 병합되었거나 그냥 닫힌 경우 포함됨.
- reopened: 닫혔던 PR이 다시 열릴 때 실행됨.
- synchronize: PR의 소스 브랜치(head branch)에 새로운 커밋이 추가될 때 실행됨. 즉, force push 또는 push가 발생하면 실행됨.
- converted_to_draft: 기존 PR이 Draft(초안) 상태로 변경될 때 실행됨.
- locked: PR이 잠금(Locked) 상태로 변경될 때 실행됨. 즉, 추가 댓글 작성이 제한될 때 실행됨.
- unlocked: PR의 잠금이 해제될 때 실행됨.
- enqueued: PR이 병합 대기열(Merge Queue)에 추가될 때 실행됨.
- dequeued: PR이 병합 대기열에서 제거될 때 실행됨.
- milestoned: PR에 마일스톤(Milestone)이 추가될 때 실행됨.
- demilestoned: PR에서 마일스톤이 제거될 때 실행됨.
- ready_for_review: Draft 상태였던 PR이 리뷰 가능 상태(Ready for Review)로 변경될 때 실행됨.
- review_requested: 특정 사용자 또는 팀에 리뷰 요청이 들어올 때 실행됨.
- review_request_removed: 특정 사용자 또는 팀에 대한 리뷰 요청이 취소될 때 실행됨.
- auto_merge_enabled: PR에 대해 자동 병합(Auto Merge)이 활성화될 때 실행됨.
- auto_merge_disabled: PR의 자동 병합이 비활성화될 때 실행됨.
pull_request_target 이벤트는 PR 관련 활동이 발생할 때 실행되며, pull_request 이벤트와는 다르게 PR의 대상(base) 브랜치에서 실행됩니다.
⚠️ 보안과 관련하여 pull_request와 pull_request_target를 잘 골라서 사용하셔야 합니다!!
pull_request_target의 경우 머지 브랜치가 아니라 베이스 브랜치 자체에서 실행이 됩니다. 그런데 예를 들어 Forked 된 레포지토리에서 PR요청이 들어오게 되어도 읽기 + 쓰기 권한을 모두 주는 것과 더불어 Secrets에 접근이 가능하다는 보안 위험이 존재합니다.
따라서,
- 중요한 CI/CD 빌드 및 테스트를 실행
- PR의 변경 코드 실행
와 같은 중요한 작업에서는 pull_request_target을 사용하지 않고 pull_request를 사용하는 것이 좋으며 만약 pull_request_target를 사용하게 될 경우
jobs:
safe-job:
if: github.event.pull_request.head.repo.fork == false # Fork된 PR에서는 실행되지 않음
runs-on: ubuntu-latest
steps:
- run: echo "This job only runs on internal PRs"
다음과 같이 fork 된 레포지토리의 PR에 대해서는 실행되지 않도록 설정하는 것이 좋습니다.
⭐ push
커밋을 푸시하거나 태그를 푸시할 때, 또는 템플릿 저장소에서 새 저장소를 생성할 때 실행됩니다. 예를 들어서 develop 또는 main 브랜치로 push가 되는 경우를 감지하도록 사용할 수 있습니다.
on:
push:
branches:
- 'main'
- 'releases/**'
- 다음과 같이 main이라는 특정 브랜치 또는 releases로 시작하는 배포용 브랜치로 push 될 경우 감지되도록 사용할 수 있습니다.
on:
push:
tags:
- 'v1.*'
- 특정 태그로 실행되도록 실행
on:
push:
paths:
- '**.js'
- 특정 파일 변경 시 실행
💠 repository_dispatch
GitHub 외부에서 발생한 이벤트를 수동으로 GitHub Actions 워크플로우를 트리거할 때 사용하는 기능입니다.
즉, 외부 시스템이나 API에서 GitHub Actions을 실행하고 싶을 때 사용할 수 있는 기능입니다.
💠 schedule
특정 시간에 자동으로 실행하는 기능입니다. POSIX cron 문법을 사용하여 정해진 주기마다 반복적으로 실행 가능합니다.
💠 status
Git 커밋의 상태가 변경될 때 실행되는 이벤트입니다. 즉, 특정 커밋에 대해 성공(Success), 실패(Failure), 오류(Error), 보류(Pending) 등의 상태가 변경될 때 워크플로우를 실행할 수 있습니다.
on:
status
jobs:
if_error_or_failure:
runs-on: ubuntu-latest
if: >-
github.event.state == 'error' ||
github.event.state == 'failure'
steps:
- env:
DESCRIPTION: ${{ github.event.description }}
run: |
echo "The status is error or failed: $DESCRIPTION"
예를 들어서, 빌드 실패 시 Slack 알림을 보낼 수도 있습니다.
check_run과 비슷한 부분이 있습니다. status는 CI/CD 상태 모니터링, 실패 감지에 가깝다면 check_run은 조금 더 세부적인 정보를 제공할 수 있습니다.
💠 watch
watch 이벤트는 GitHub 저장소에 새로운 "Star(⭐️)"가 추가될 때 실행되는 이벤트입니다. 누군가 저장소를 즐겨찾기(Star)하면 GitHub Actions 워크플로우를 실행할 수 있습니다.
💠 workflow_call
workflow_call 이벤트는 다른 GitHub Actions 워크플로우에서 호출될 수 있는 워크플로우를 정의하는 기능입니다.
즉, 재사용 가능한 워크플로우를 만들고, 다른 워크플로우에서 이를 호출하여 실행할 수 있음.
//이런식으로 만들어놓고..
# .github/workflows/reusable-workflow.yml
on:
workflow_call
jobs:
run-reusable-job:
runs-on: ubuntu-latest
steps:
- name: Print message
run: echo "This is a reusable workflow!"
//이런식으로 불러와서 사용합니다
# .github/workflows/caller-workflow.yml
on:
push:
branches:
- main
jobs:
call-reusable-workflow:
uses: owner/repository/.github/workflows/reusable-workflow.yml@main
💠 workflow_dispatch
워크플로우를 수동으로 실행할 수 있도록 해주는 기능입니다. 즉, 사용자가 직접 실행 버튼을 클릭하거나 GitHub API, CLI를 통해 트리거할 수 있음.
on:
workflow_dispatch:
inputs:
logLevel:
description: 'Log level' # 입력 설명
required: true # 필수 입력값 여부
default: 'warning' # 기본값
type: choice # 선택형 입력
options:
- info
- warning
- debug
tags:
description: 'Test scenario tags'
required: false
type: boolean # 불리언 값 입력
environment:
description: 'Environment to run tests against'
type: environment # 환경 변수 입력
required: true
jobs:
log-the-inputs:
runs-on: ubuntu-latest
steps:
- run: |
echo "Log level: $LEVEL"
echo "Tags: $TAGS"
echo "Environment: $ENVIRONMENT"
env:
LEVEL: ${{ inputs.logLevel }}
TAGS: ${{ inputs.tags }}
ENVIRONMENT: ${{ inputs.environment }}
위와 같이 수동적으로 CI/CD를 수행할 하도록 명령할 수도 있습니다!!
💠 workflow_run
다른 GitHub Actions 워크플로우가 실행되거나 완료될 때 트리거되는 이벤트입니다. 즉, 한 워크플로우의 실행 결과를 기반으로 후속 워크플로우를 자동 실행할 수 있음.
다음과 같은 조건을 사용할 수 있습니다.
- requested → 워크플로우 실행이 요청됨. (re-run 실행 시에는 발생하지 않음.)
- in_progress → 워크플로우가 실행 중임.
- completed → 워크플로우 실행이 완료됨.
워크플로우 간 체인을 만들 수 있지만 최대 3단계까지 가능 (A → B → C까지 가능, A → B → C → D → E는 불가능).
😓 생각보다 엄청 많은 기능들이 있네요.. 거의 깃허브와 관련된 모든 것을 Github Actions와 사용 가능하다고 해도 무방할 것 같아요. "이런 기능들이 존재한다"라고 참고만 하고 사용할 때 더 알아보면 좋을 것 같습니다.
✅ 러너(Runner)
러너(Runner)는 GitHub Actions 워크플로우를 실행하는 서버입니다.
워크플로우가 트리거 되면 실행기가 해당 작업을 수행하며, 각 실행기는 한 번에 하나의 작업(Job)만 실행할 수 있습니다.
💠 Github 호스팅 러너 (Cloud-hosted Runner)
- Ubuntu, Windows, macOS 환경을 제공합니다.
- 워크플로우 실행마다 새로운 가상 머신(VM)이 프로비저닝 됩니다.
💠 Larger Runner 🔗
- 더 많은 CPU, RAM, 디스크 용량이 필요한 경우 사용.
- 대규모 프로젝트, 복잡한 빌드, 머신 러닝 모델 학습 등 고성능이 필요한 작업에 적합.
- 기본 제공되는 실행기보다 성능이 높음.
- 유료 플랜에서만 제공됩니다.
💠 자체 호스팅 ( Self-hosted Runner ) 🔗
- 사용자가 직접 서버를 제공하여 실행하는 실행기.
- 특정 운영 체제(예: CentOS, ARM 아키텍처) 또는 특정 하드웨어 환경이 필요한 경우 유용.
- 필요에 따라 가상 머신(VM), 물리 서버, 컨테이너 환경(Docker)에서 실행 가능
자체 호스팅 실행기가 필요한 경우
- 특정 하드웨어 필요
- GPU가 필요한 딥러닝 모델 훈련
- ARM 기반 애플리케이션 빌드 (예: Raspberry Pi)
- 내부 네트워크에서 실행 필요
- 외부 네트워크에 접속할 수 없는 폐쇄적인 환경
- 회사 내부망에서만 접근 가능한 서버
- 비용 절감
- GitHub 호스팅 실행기는 유료 (무료 사용량 초과 시 비용 발생).
- 자체 서버를 이용하면 추가 비용 없이 무제한 사용 가능.
- 빠른 실행 및 캐싱 유지
- GitHub의 기본 실행기는 매번 새 VM에서 실행되므로 캐싱이 유지되지 않음.
- 자체 실행기를 사용하면 Docker 이미지, 빌드 아티팩트 등을 유지 가능.
✅ 작업(Jobs)
작업(Jobs)은 워크플로우에서 실행되는 단계(Steps)의 집합으로, 각 작업은 실행기(Runner)에서 실행되며, 단계 간에는 데이터를 공유할 수 있습니다.
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install dependencies
run: npm install
- name: Run build
run: npm run build
- 예를 들어 다음과 같이 작업 내부의 steps는 데이터를 공유할 수 있습니다. npm을 install 하고 다음 step에서 실행이 가능합니다.
jobs:
build:
runs-on: ubuntu-latest
steps:
- run: echo "Build 실행 중..."
test:
runs-on: ubuntu-latest
steps:
- run: echo "Test 실행 중..."
- 기본적으로 작업들은 서로 독립적이고 병렬적으로 실행됩니다.
- 데이터 직접 공유는 불가능 ( 하지만 아티팩트 업로드 등으로 공유 가능)
jobs:
build:
runs-on: ubuntu-latest
steps:
- run: echo "빌드 실행 중..."
package:
needs: build # 'build' 작업이 완료된 후 실행됨.
runs-on: ubuntu-latest
steps:
- run: echo "패키징 실행 중..."
- needs 명령어를 이용해 종석성을 부여할 수 있습니다.
jobs:
build:
runs-on: ubuntu-latest
steps:
- run: echo "빌드 실행 중..."
- uses: actions/upload-artifact@v4
with:
name: build-output
path: ./build-folder # 빌드 결과 저장
test:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
name: build-output
path: ./build-folder # 빌드 결과 다운로드 후 사용
- run: echo "테스트 실행 중..."
- 작업들 간 빌드 결과를 공유하기 위해서는 아티팩트를 저장하고 다운로드를 통해서 가능합니다..!
✅ 액션(Actions)
GitHub Actions의 작업(Action)은 복잡한 과정을 자동화하고, 코드의 반복을 줄이는 데 도움을 줍니다.
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: 리포지토리 체크아웃
uses: actions/checkout@v3 # GitHub 공식 제공 Action
- name: Node.js 환경 설정
uses: actions/setup-node@v3 # Node.js 환경 구성 Action
with:
node-version: 18
- name: 의존성 설치 및 빌드 실행
run: |
npm install
npm run build
다음과 같이 많이 사용되는 과정들을 간편하게 사용할 수 있도록 만들어 놓은 것이 Action입니다.
Custom Action을 직접 만들 수도 있고 Github Actions Marketplace에서 찾아서 사용할 수도 있습니다!
모두 정리하기에는 너무 많아서 몇 가지만 소개를 해보겠습니다.
💠 TruffleHog OSS
민감한 정보(Secrets) 탐지 및 검증
GitHub 리포지토리, 파일 시스템, 클라우드 환경 등에서 유출된 민감한 정보를 탐색하고 검증하는 보안 스캐닝 도구입니다.
- CI/CD 파이프라인에서 자동으로 보안 검사 가능!
이 도구는 API 키, 데이터베이스 비밀번호, 암호화 키, AWS 인증 키 등 보안적으로 민감한 값(Secrets)을 자동으로 감지합니다.
✅ 4가지 핵심 기능
- Discovery (탐색) → Git, 파일 시스템, Docker 이미지, S3 버킷 등에서 비밀값 검색
- Classification (분류) → 800개 이상의 비밀 유형(AWS, Stripe, Cloudflare, DB 패스워드 등) 자동 분류
- Validation (검증) → 감지된 비밀이 실제 사용 가능한지 확인
- Analysis (분석) → 특정 비밀이 어떤 권한을 가지고 있고, 어떤 리소스에 접근할 수 있는지 분석
💠 Super-Linter
Super-Linter는 여러 프로그래밍 언어의 코드 스타일(linting) 및 정적 분석을 자동으로 수행하는 올인원 도구입니다.
- 개발자들이 설정한 코딩 규칙을 자동으로 검사하고, GitHub에서 자동 검토를 수행하여 코드 품질을 유지하도록 돕는 역할.
⭐ Checkout V4
GitHub Actions에서 실행되는 워크플로입니다.
GitHub Actions 실행 환경에서는 기본적으로 코드가 없으므로 필수적으로 사용해야 합니다.
- CI/CD 파이프라인에서 빌드, 테스트, 배포 작업을 수행하기 전에 반드시 코드 체크아웃 필요!
💠 Cache
GitHub Actions에서 의존성 및 빌드 결과를 캐싱하여 실행 속도를 최적화하는 기능입니다.
- 의존성 패키지(NPM, Gradle, Maven 등)나 빌드된 아티팩트(컴파일된 파일, 결과물)를 저장하여 중복 다운로드/빌드를 줄이고 실행 시간을 단축할 수 있음!
💠 Build and push Docker images
GitHub Actions에서 Docker 이미지를 빌드(Build)하고 컨테이너 레지스트리에 푸시(Push)하는 액션입니다.
- Moby BuildKit을 활용하여 빠르고 효율적인 Docker 빌드 및 캐싱을 지원하며, 멀티플랫폼 빌드, 시크릿 관리, 원격 캐시(remote cache) 등을 지원합니다.
- GitHub Actions CI/CD 파이프라인에서 Docker 배포를 자동화할 때 필수적인 액션입니다.
💠 Setup Node.js
- 특정 버전의 Node.js를 설치하고 설정하여 JavaScript/TypeScript 프로젝트의 빌드 및 테스트 환경을 구성합니다.
- Node 뿐만 아니라 Setup은 Python, Java, 그리고 Go 등등 다양하게 있습니다.
💠 Download/Upload Artifact
- 위에서 언급한 Job들 간에 아티팩트 공유 방법에서 소개했었습니다!
💠 Slack Notification & Telegram Notification
- 워크 플로우의 상태나 결과를 다양한 채널에 알림으로 전송할 수 있습니다.
⚠️ 심지어 chat gpt가 PR을 리뷰해 주는 Action도 존재합니다.
✅ 적용
- 깃허브 액션은 다음과 같이 깃허브에서 template으로 만들 수도 있고 그냥 root 경로에 .github/workflows 아래 yml을 만들고 쉘 스크립트를 작성해 주셔도 괜찮습니다.
그럼 어떻게 구상을 해야 할까요? 우선 간단히 어떤 게 배포 과정을 자동화하고 싶은지 생각해 봅시다.
ex) 나는 develop 브랜치로 merge가 될 경우 배포를 하고 싶었음. Event 조건
CI 단계
- 간단히 Build와 Test를 돌리고 싶다 Test Build와 관련된 Action을 찾아볼까?
- 이때 좀 시간을 단축하기 위해서 캐시를 사용해서 빌드하는 것도 좋아 보인다. Cache Action을 사용?
- 코드 품질 검사와 리뷰를 하고 여러 가지 Action에서 제공하고 있습니다.
- 보안 검사 Truffle Hog 사용해 봐도 좋아 보입니다.
위의 CI가 잘 작동하고 나면 -> Event 조건으로 CI가 돌아가고 나면 실행되게 yml을 따로 만들거나, 하나의 yml에서 처리해도 괜찮을 것 같기는 합니다.
CD 단계
- 도커 이미지를 빌드해서 Docker Hub로 푸쉬하고 -> Docker 관련 Action
- Ec2에서 Image를 받고 나서 실행하고 싶다. -> Action 찾아보기
- 성공했다는 알림을 팀원들에게 Slack으로 보내고 싶다. -> Slack 알림 Action
😀 예를 들어서 위와 같이 구상을 하고 하나하나 공식 문서를 찾아가면서 완성해 나가시면 되겠습니다.
여기서 따로 실습을 하지는 않고 배포 관련 포스트에서 한번 Develop 해보도록 하겠습니다.
생각보다 많은 기능들이 세세하게 제공되고 있다는 점에서 놀랐습니다. 자유롭게 커스터미이징 해서 Github 액션을 사용해 보세요 :)
Reference:
JetBrains - JetBrains 개발자 생태 조사 🔗
티스토리 - Jenkins vs Github Action 어떤 걸 쓰는 게 좋을까? 🔗
공식 문서 - GitHub Docs 🔗
'Server' 카테고리의 다른 글
HTTP 메서드를 알아보자 (0) | 2025.01.03 |
---|---|
HTTP 응답 코드 : 2XX Success (0) | 2024.12.31 |