- CI (Continuous Integration): 지속적 통합
- CD (Continuous Delivery or Continuous Deployment): 지속적 제공 또는 지속적 배포
개발자들이 코드 변경사항을 특정 브랜치(또는 특정 저장소)에 통합하는 과정을 의미한다.
CI 과정을 거친 코드를 자동으로 실제 운영 환경에 배포하는 과정을 의미한다. CD는 Continuous Delivery(지속적 제공)와 Continuous Deployment(지속적 배포)로 나뉜다.
*이후 내용은 Continuous Deployment 를 기준으로 한다.
CI/CD 는 현대 소프트웨어 개발에서 필수적인 실천 방법으로, 팀의 협업을 개선하고 소프트웨어의 품질을 높이는 것이 목적이다. 또한 빠른 개발 주기와 높은 품질의 소프트웨어 제공을 가능하게 한다. 그런 점에서 * 애자일 방법론 이나 * DevOps 문화와 잘 어울린다.
* 애자일 방법론
작은 목표단계를 설정하고 짧은 기간 안에 설계, 구현, 피드백, 개선 과정을 반복하는
소프트웨어 개발 방법론이다.
* DevOps 문화:
개발팀과 운영팀 간의 협업 강화를 통해 제품 제공 속도를 높이고, 품질 개선을 목표로 하는
소프트웨어 개발 방법론이다.
참고 ①)
릴리스(Release)와 배포(Deployment)의 차이
릴리스(Release)
소프트웨어의 새로운 버전이 공식적으로 완성되어 사용 가능한 상태를 의미한다. 특정 기능이나 개선사항들이 완성된 상태이나, 실제 프로덕션 환경에 적용되지 않은 단계의 버전이다.
배포(Deployment)
릴리스된 소프트웨어를 실제 환경에 적용하는 과정이다. 최종 사용자나 고객을 대상으로 한다는 점에서 릴리스와 차이이다. 소프트웨어는 항상 릴리스 이후 배포되는 순서를 갖는다.
CI/CD 맥락에서의 의미
- CI: 변경사항 통합, 테스트 등을 자동화하여 릴리즈를 목표로 함.
- CD: 릴리스된 소프트웨어를 자동화 과정을 통해 배포를 목표로 함.
참고 ②)
"CI/CD 파이프라인 구성" 이란?
개발, 테스트, 배포 과정의 자동화 단계를 설정한다는 의미이다. 구체적 단계는 각 개발팀마다 다르지만, 핵심적으로 다음 단계를 포함한다.
- 버전 관리 시스템(Git 등) 설정
- CI/CD 도구(Jenkins, Github Actions 등) 선택
- 자동화된 빌드 프로세스 구성
- 자동화된 테스트 환경 구축
- 자동화된 배포 프로세스 구축
- 모니터링 및 피드백 시스템 설정
- etc.
CI/CD(지속적 통합 및 배포) 도구에는 다양한 옵션이 있다.
이번 게시글에서는 Github Action 에 대해 알아보겠다. 그 이유는 널리 사용되는 버전 관리 플랫폼 Github 의 내장 도구로써, 누구나 쉽게 CI/CD 파이프라인 구성할 수 있는 환경이 제공되기 때문이다. 부가적으로는 다음과 같은 장점 또한 있다.
Event 유형
카테고리 이벤트 설명 저장소 관련 push 특정 브랜치로 푸시할 때 pull_request PR이 열리거나, 업데이트되거나, 재개될 때 create 브랜치나 태그가 생성될 때 delete 브랜치나 태그가 삭제될 때 fork 저장소가 포크될 때 release 릴리스가 생성, 수정, 삭제될 때 이슈 및 PR 관련 issues 이슈가 열리거나, 수정되거나, 삭제될 때 issue_comment 이슈나 PR에 댓글이 달릴 때 pull_request_review PR 리뷰가 제출, 수정, 삭제될 때 pull_request_review_comment PR 리뷰 댓글이 생성, 수정, 삭제될 때 스케줄 관련 schedule 정해진 시간에 주기적으로 Workflow를 실행 수동 트리거 workflow_dispatch UI나 API를 통해 수동으로 Workflow를 트리거 repository_dispatch 외부 이벤트에 의해 Workflow를 트리거 기타 watch 저장소에 스타가 추가될 때 gollum 위키 페이지가 생성되거나 업데이트될 때 page_build GitHub Pages 사이트가 빌드될 때 status 커밋의 상태가 변경될 때 label 라벨이 생성, 수정, 삭제될 때 milestone 마일스톤이 생성, 수정, 삭제될 때 project 프로젝트 카드가 생성, 수정, 삭제될 때
위에서 짧게 이야기 했듯이, .yml
혹은 .yaml
확장자를 가진 YAML 파일에 GitHub Actions의 Workflow 를 정의한 양식이다. 루트 디렉토리에 .github
폴더를 생성한 뒤 작성한다.
workflow 작성은 아래와 같이 할 수 있다. (간단한 예시 코드이다.)
# 📍 .github/practice-workflow.yml
# Workflow의 이름을 정의
name: Build and Test
# Workflow를 트리거하는 이벤트를 지정
on:
# main branch에 push 이벤트가 발생할 때 실행
push:
branches: [ main ]
# Job들을 정의
jobs:
# 'build' Job 정의
build:
# Job이 실행될 운영 체제 환경 지정
runs-on: ubuntu-latest
# Job 내의 Step들을 정의
steps:
# Step 1: 현재 저장소의 코드를 Checkout
- uses: actions/checkout@v2
# Step 2: Node.js 환경 설정
- name: use Node.js
uses: actions/setup-node@v2
with:
node-version: '14'
# Step 3: 프로젝트 의존성 설치
- name: install dependencies
run: npm ci
# Step 4: 프로젝트 빌드
- name: build project
run: npm run build
# Step 5: 빌드 결과물을 Artifact로 업로드
- name: upload build artifact
uses: actions/upload-artifact@v2
with:
name: dist
path: dist # 빌드 결과물이 저장된 디렉토리
# 'test' Job 정의
test:
# build Job이 완료된 후에 실행
needs: build
# Job이 실행될 운영 체제 환경 지정
runs-on: ubuntu-latest
# Job 내의 Step들을 정의
steps:
# Step 1: 현재 저장소의 코드를 Checkout
- uses: actions/checkout@v2
# Step 2: Node.js 환경 설정
- name: Use Node.js
uses: actions/setup-node@v2
with:
node-version: '14'
# Step 3: 프로젝트 의존성 설치
- name: Install dependencies
run: npm ci
# Step 4: 이전 Job에서 생성한 Artifact 다운로드
- name: Download build artifact
uses: actions/download-artifact@v2
with:
name: dist
path: dist
# Step 5: 테스트 실행
- name: Run tests
run: npm test
참고)
GitHub Actions에서 Job 이름은 필수이지만, Workflow와 Step의 이름은 선택사항이다. 그러나 Workflow 이름은 GitHub UI에서의 식별을 위해 지정을 권장하며, 복잡한 Step의 경우에도 이름 지정을 고려해야 한다.
오픈소스 프로젝트로 NPM 패키지를 Github에 공개했다. 공개 이후 생각을 해보니, 누구나 main 브랜치를 PR이 open 가능할 텐데, 일일히 pull 받아 code와 version 을 확인하고 배포하기 어렵다고 생각했다.(다행히 아직 pull 요청이 쏟아지는 일은 일어나지 않았다.) 내가 직접 모든 요청을 검수하더라도 기여자 입장에선 빠르게 피드백을 받을 수 없으니 장기적으로 좋지 못할 것이다.
안정적인 버전관리와 빠른 릴리스,배포 가 필요한 시점이라고 생각해 Github Action 을 통해, CI/CD 파이프라인을 구축하게 되었다.
간단히 요약해서 다음 3가지 경우에 대해 Workflow 를 준비했다.
Workflow | 목적 | 트리거 이벤트 | 주요 액션 |
---|---|---|---|
Build and Test | 코드 빌드 및 테스트 자동화 | - main 브랜치로의 push - main 브랜치로의 pull request | 1. Node.js 설정 2. 의존성 설치 3. 프로젝트 빌드 4. 테스트 실행 |
---------------- | ------ | -------------- | ---------- |
Check for Version Updates | PR의 버전이 main 브랜치보다 높은지 확인 | - Pull request 열림 - Pull request 동기화 - Pull request 재개 | 1. 현재 브랜치 버전 확인 2. main 브랜치 버전 확인 3. 버전 비교 및 경고 |
---------------- | ------ | -------------- | ---------- |
Deploy | README 업데이트 및 NPM 배포 | main 브랜치로의 push | 1. README의 버전 업데이트 2. 변경사항 커밋 및 푸시 3. 프로젝트 빌드 4. NPM에 배포 |
각 Workflow 이름을 클릭해보면 관련 설정을 직접 확인할 수 있다.
YAML 파일만 작성하면, Github Bot이 자동으로 실행해주기 때문에 쉽고 간단하게 이용할 수 있다. 처음에는 YAML 문법에 대한 거부감이 있을 수 있지만, 특정 시점에 어떤 작업이 이뤄지는지 직관적으로 보이기 때문에 금방 익숙해질 수 있다.
원격저장소에 push 한 이후에는 마우스 동작이 많이지곤 했는데, 순서가 거의 반복된다.
- 새로 추가된 branch에 대해 PR open
- approve 된다면, main에 merge
- reject 된다면, 수정 후 새 커밋 이력 push
- PR close
이러한 반복되는 작업을 자동화할 수 있다는 점에서 GitHub Actions가 유용하다.
또한 오픈소스 프로젝트나 협업 개발 과정에서 원격 상에서 이뤄지는 동작을 일관되게 맞춤으로써 휴먼 에러를 줄일 수 있다.
추가)
이전에 사용해본 도구 중 Husky 가 떠올랐다. GitHub Actions 가 Github 상에서 동작하는 워크플로우 자동화 도구라면, Husky는 로컬환경에서 워크플로우를 자동화한다.
Husky를 사용해 로컬에서 commit 혹은 원격으로 push 전에 기본적인 검증(lint 검사, 단위 테스트 등)을 실행하고, GitHub Actions를 통해 추가적인 테스트, 빌드, 배포를 자동화한다면 로컬과 원격 환경을 아우르는 CI/CD 파이프라인을 구축할 수 있을 것이다.