CI/CD는 애플리케이션 개발 단계로부터 배포 때까지의 모든 단계를 자동화
를 통해서 좀더 효율적이고 빠르게 사용자에게 빈번히 배포할 수 있는것을 말한다.
테스트, 빌드, Dockerizing, 저장소에 전달하는 것까지 프로덕션 환경으로 서비스를 배포할 수 있도록 준비하는 프로세스, 지속적인 통합
1. 코드 변경사항을 주기적으로 빈번하게 merge
오랜 기간 동안 개발을 진행하다가 한번에 merge를 한다면 많은 충돌이 일어날 것이다. 그렇기에, 가능한 작은 단위로 나누어서 주기적으로 빈번히 개발하고 계속해서 통합하여 나가는 것이 중요하다.
흐름을 보자면,
2. 통합 단계의 자동화
1번의 방법은 너무나 귀찮은 단점이 있다. 여기서 자동화를 사용한다면 귀찮은 작업을 줄일 수 있다.
자동화를 사용한 이후의 흐름
저장소로 전달된 프로덕션 서비스를 실제 사용자들에게 배포하는 프로세스, 지속적인 배포
deploy(배포)
CD를 적용한 후의 흐름
만약 CI/CD를 하지 않는다면 위와 같은 작업을 매번 기능을 수정될 때마다 수작업을 적용시켜야하나 CI/CD를 적용하면 간단한 명령어 만으로 위와 같은 작업을 자동으로 수행
대표적인 것 : github action, jenkins 등이 존재
이러한 CI/CD의 논리는 DevOps 방식의 논리를 극한으로 끌어올리는 경우
github repository가 있다면 github action을 사용하여 workflow를 구성할 수 있습니다.
Github Action
은 Github 저장소를 기반으로 소프트웨어 개발 Workflow
를 자동화 할 수 있는 도구이다. 테스트, 빌드, 배포 등의 다양한 작업들을 자동화하여 처리한다. GitHub Actions는 코드 저장소(repository)로 유명한 GitHub에서 제공하는 CI(Continuous Integration, 지속 통합)
와 CD(Continuous Deployment, 지속 배포)
도구이다. 당연히 GitHub에서 코드를 관리하고 있는 소프트웨어 프로젝트에서 사용할 수 있으며 개인은 누구나 GitHub에서 코드 저장소를 무료로 만들 수 있기 때문에 다른 CI/CD 서비스 대비 진입장벽이 낮은 편입니다.
Github Action을 사용하면 자동으로 코드 저장소에서 어떤 이벤트가 발생했을 때 특정 작업이 일어나게 하거나 주기적으로 어떤 작업들을 반복해서 실행시킬 수도 있습니다. 예를 들어, 누군가가 코드 저장소에 Pull Request를 생성하게 되면 GitHub Actions를 통해 해당 코드 변경분에 문제가 없는지 각종 검사를 진행할 수 있습니다. 어떤 새로운 코드가 메인(main) 브랜치에 유입(push)되면 GitHub Actions를 통해 소프트웨어를 빌드(build)하고 사용 서버에 배포(deploy)할 수도 있습니다. 뿐만 아니라 매일 밤 특정 시각에 그날 하루에 대한 통계 데이터를 수집시킬 수도 있습니다.
이렇게 소프트웨어 프로젝트에서 지속적으로 수행해야하는 반복 작업들을 업계에서는 소위 CI/CD
라고 많이 줄여서 부릅니다. 사람이 매번 직접 하기에는 비효율적인데다가 실수할 위험도 있기 때문에 GitHub Actions와 같은 자동화시키는 것이 유리합니다.
GitHub Actions는 기존 CI/CD 서비스 대비 간편한 설정과 높은 접근성으로 특히 개발자들 사이에서 많은 호응을 얻고 있는데요. 예전에는 CI/CD가 DevOps 엔지니어의 전유물로만 여겨지곤 했었는데 최근에는 GitHub Actions을 통해서 일반 개발자들도 어렵지 않게 CI/CD 설정을 스스로 하는 것을 보게 됩니다.
GitHub Actions에서 가장 상위 개념인 워크플로우
(Workflow, 작업 흐름)는 쉽게 말해 자동화해놓은 작업 과정이라고 볼 수 있습니다. 하나 이상의 job으로 이루어져 있으며 이벤트에 의해 실행된다. 워크플로우는 코드 저장소 내에서 .github/workflows
폴더 아래에 위치한 YAML 파일로 설정하며, 하나의 코드 저장소에는 여러 개의 워크플로우, 즉 여러 개의 YAML 파일을 생성할 수 있습니다. Workflow는 Github 저장소에서 발생하는 build, test, package, release, deploy 등 다양한 이벤트를 기반으로 직접 원하는 Workflow를 만들 수 있다. Workflow는 Runners라고 불리는 Github에서 호스팅 하는 Linux, macOS, Windows 환경에서 실행된다. 그리고 이 Runners를 사용자가 직접 호스팅하는 환경에서 직접 구동시킬 수도 있다.(self-hosted runner)
이 워크플로우 YAML 파일에는 크게 2가지를 정의한다.
1) on
속성을 통해서 해당 워크플로우가 언제 실행되는지를 정의
코드 저장소의
main
브랜치에push
이벤트가 발생할 때 마다 워크플로우를 실행하려면 다음과같이 설정
다른 예시는 매일 자정에 워크플로우를 실행하려면 다음과 같이 설정합니다.
2) jobs
속성을 통해서 해당 워크플로우가 구체적으로 어떤 일을 해야는지 명시해야 한다.
Github Actions에서 작업(Job)
이란 독립적인 가상 머신(machine) 또는 컨테이너(container)에서 돌아가는 하나의 처리 단위를 의미합니다. 하나의 워크플로우는 여러 개의 작업으로 구성되며 적어도 하나의 작업은 있어야 합니다. 그리고 모든 작업은 기본적으로 동시에 실행되며 필요시 작업 간에 의존 관계를 설정하여 작업이 실행되는 순서를 제어할 수 있습니다.
작업은 워크플로우 YAML 파일 내에서 jobs
속성을 사용하며 작업 식별자(ID)와 작업 세부 내용 간의 맵핑(mapping) 형태로 명시가 된다.
예를 들어, job1
, job2
, job3
이라는 작업 ID를 가진 3개의 작업을 추가하려면 다음과 같이 설정한다.
작업의 세부 내용으로는 여러가지 내용을 명시할 수 있는데 필수로 들어가야 하는 runs-on
속성을 통해 해당 리눅스나 윈도우즈와 같은 실행 환경을 지정해줘야 합니다.
예를 들어, 가장 널리 사용되는 우분투의 최신 실행 환경에서 해당 작업을 실행하고 싶다면 다음과 같이 설정한다.
작업에서 가장 중요한 부분은 작업 순서를 정의하는 것일텐데요. 이 부분은 steps 속성을 통해서 설정을 하며 다음 섹션에서 자세히 알아보겠습니다.
보통 작업은 일반적으로 여러 단계의 명령을 순차적으로 실행하는 경우가 많은데 Github Actions에서는 각 작업(job)이 하나 이상의 단계(step)로 모데링 된다.
작업 단계는 단순한 커맨드(command)나 스크립트(script)가 될 수도 있고 다음 섹션에서 자세히 설명할 액션(action)이라고하는 복잡한 명령일 수도 있습니다. 커맨드나 스크립트를 실행할 때는 run
속성을 사용하며, 액션을 사용할 때는 uses
속성을 사용합니다.
예를 들어, 자바스크립트 프로젝트에서 테스트를 돌리려면 코드 저장소에 코드를 작업 실행 환경으로 내려 받고, 패키지를 설치한 후, 테스트 스크립트를 실행해야 한다. 이 3단계의 작업은 아래와 같이 steps
속성을 통해서 명시될 수 있다.
워크플로우 파일 내에서 작업 단계를 명시해줄 때는 주의할 부분이 있다. YAML 문법에서 시퀀스(sequence) 타입을 사용하기 때문에 각 단계 앞에 반드시 -
를 붙여야 한다.
마지막으로 살펴볼 개념은 Github Actions의 꽃이라고 할 수 있는 액션(action)
이다. 액션은 Github Action에서 빈번하게 필요한 반복 단계를 재사용하기 용이하도록 제공되는 일종의 작업 공유 메커니즘이다. 이 액션은 하나의 코드 저장소 범위 내에서 여러 워크플로우 간에서 공유를 할 수 있을 뿐만 아니라, 공개 코드 저장소를 통해 액션을 공유하면 Github 상의 모든 코드 저장소에서 사용이 가능해집니다.
Github에서 제공하는 대표적인 공개 액션으로 바로 위 예제에서도 사용했던 체크 아웃 액션 (actions/checkout
)을 들 수 있는데 대부분의 CI/CD 작업은 코드 저장소로 부터 코드를 작업 실행 환경으로 내려받는 것으로 시작하므로 이 액션은 범용적으로 사용한다.
뿐만 GitHub Marketplace에서는 수많은 벤더(vendor)가 공개해놓은 다양한 액션을 쉽게 접할 수가 있습니다. 한 마디로 이 액션을 중심으로 하나의 큰 커뮤니티가 형성이 되고 더 많은 사용자와 벤더가 GitHub Actions으로 몰려드는 선순환이 일어나고 있습니다.
Github 액션 러너 애플리케이션이 설치된 서버이다. runner
는 workflow가 트리거될 때 실행하는 서버입니다. 각 runner는 1번에 1개의 job을 실행할 수 있습니다. Github에서 호스팅해주는 Github-hosted runner와 직접 호스팅하는 Self-hosted runner로 나뉩니다. Github-hosted runner는 Azure의 Standard_DS2_v2로 vCPU 2, 메모리 7GB, 임시 스토리지 14GB입니다.
워크 플로우를 실행하는 특정 활동이나 규칙이다. 커밋의 push, pull request가 생성되었을 때뿐만 아니라 저장소 dispatch event를 통해 Github 외부에서 발생하는 활동으로도 이벤트를 발생시킬 수도 있다.
# push나 pull request가 발생할 때 워크 플로우 실행
on: [push, pull_request]
또한 schedule에 POSIX cron 문법으로 스케쥴 이벤트를 발생시킬 수도 있다.
on:
schedule:
- cron: '*/15 * * * *'
jobs:
example-job:
runs-on: unbuntu-latest
steps:
- name: Retrieve secret
# 환경변수로 저장하고
env:
super_secret: ${{ secrets.SUPERSECRET }}
# 저장한 환경변수를 활용한다.
run: |
example-command "$super_secret"
needs
키워드를 통해 작업이 의존성을 갖도록 지정하면 된다.jobs:
setup:
runs-on: ubuntu-latest
steps:
- run: ./setup_server.sh
build:
needs: setup
runs-on: ubuntu-latest
steps:
- run: ./build_server.sh
test:
needs: build
runs-on: ubuntu-latest
steps:
- run: ./test_server.sh
needs
키워드를 통해 build, test 작업이 각각 이전 작업인 setup, build 작업이 끝난 후에 실행되도록 설정했다.
strategy
키워드를 사용하면 된다.jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
# 다양한 버전의 Node.js를 이용하여 작업을 여러번 실행
node: [6, 8, 10]
steps:
- uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node }}
GIthub의 러너는 각 작업에서 새로운 환경으로 실행되므로 작업들이 종속성을 재사용하는 경우 파일들을 캐싱하여 성능을 높이면 된다. 캐시를 생성하면 해당 저장소의 모든 워크 플로우에서 사용 가능하다.
jobs:
example-job:
steps:
- name: Cache node modules
uses: actions/cache@v2
env:
cache-name: cache-node-modules
with:
# `~/.npm` 디렉토리를 캐시해 성능을 높인다
path: ~/.npm
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
저장소에 .github/workflows
폴더를 만들어서 .yml
형식 파일을 만든 뒤 Workflow를 정의하는 것이다.
간단한 예시
⚠️ 반복 스케줄은 UTC 타임존 시간을 사용하고, 기본 브랜치나 마지막 커밋을 기준으로 동작한다. 최소 간격은 5분까지만 가능하다.
예를 들자면 master
브랜치 또는 v1
태그가 push되었을 때 test
폴더 안에 어떤 파일이 변경된 경우에 workflow가 실행되게 할 수 있다.
실행환경은 runs-on
항목으로 지정하고, github이 호스팅하는 머신 환경은 Ubuntu
,Windows
, MacOS
가 있다.
예를들어, NPM 패키지를 빌드해서 배포하거나 Go 바이너리를 Github 저장소에 release에 올리는 동작을 적절한 도구나 여러 API를 조합해서 만든 것을 Action으로써 활용하는 것이다. 그리고 이렇게 만든 Action을 공유하면 마치 코딩할 때 라이브러리를 가져다 쓰는 것처럼 쓸 수 있다.
도커 컨테이너로 Action을 만드는 경우 일관된 동작을 보장할 수 있는 장점이 있지만, Github이 호스팅하는 리눅스 환경에서만 실행할 수 있다.
Javasript로 Action을 만들면 좀 더 간단하며, 도커 컨테이너보다 더 빨리 실행된다.
이렇게 만든 Action에 필요한 Input, Output 설정이나 메인 실행 파일 같은 메타 정보를 정의하기 위해 action.yaml
또는 action.yml
을 반드시 작성해야 한다.
action.yml
마지막에 정의한 index.js
이름으로 메인 실행 파일을 만든다.
Javascript로 Action 로직을 만드는 경우 도움이 될만한 Node.js 패키지가 있다.
@actions/core, @actions/github 이 두 패키지는 Input, Output을 쉽게 처리하고, Github Action 컨텍스트에 접근할 수 있는 인터페이스 등을 제공한다.
Action 저장소가 다른 저장소의 Workflow에서 사용되려면 반드시 Public 저장소로 설정되어 있어야 한다. 아래 내용은 위에서 살펴본 Workflow 예제에 Hello world Step 부분을 수정했다.
만약 Action을 공유할 목적이 아니라 특정 프로젝트에 종속된 구성을 한다면 action.yaml
파일을 어디에 두던 상관이 없다. 하지만 .github/actions/action1
, .github/actions/action2
같은 구성을 하는 것이 관리하는 측면에서 유용하다.
Action을 독립된 Git 저장소로 구성한다면, 반드시 Public 저장소 타입으로 만들어야 한다.
하지만 이 저장소가 바로 Github 마켓 플레이스에 올라가는 건 아니다. 하지만 Github이 자동으로 action.yml
을 감지해서 마켓 플레이스에 올릴 수 있다는 배너를 노출해준다.
GitHub Actions는 YAML 구문을 사용하여 워크플로를 정의합니다. 각 워크플로는 .github/workflows라는 디렉터리의 코드 repository에 별도의 YAML 파일로 저장됩니다.
직접 작성할 수도 있지만 아래와 같이 템플릿을 활용하면 좋습니다.
Configure 버튼을 누르면 쉽게 workflow를 생성할 수 있습니다.
workflow 파일 내 컴포넌트 이해하기
master 브랜치에 Push 또는 Pull Request가 올 경우 실행되는 CI란 이름을 갖는 Workflow 파일입니다.
위와 같이 저장을 한다면 아래 예시처럼 시각화된 workflow를 볼 수 있습니다.
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
○ Event에 대해 작성하는 부분
○ 어떤 조건에 Workflow를 Trigger 시킬지
○ push(Branch or Tag), pull_request, schedule을 사용할 수 있음
단, 다른 CI/CD 도구에 있는 즉시 실행 버튼은 없음
○ 단일 Event를 사용할 수도 있고, array로 작성할 수도 있음
on: push
# 또는
on: [pull_request, issues]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Run a one-line script
run: echo Hello, world!
- name: Run a multi-line script
run: |
echo Add other actions to build,
echo test, and deploy your project.
○ Workflow는 다양한 Job으로 구성됨
○ 여러 Job이 있을 경우, Default로 병렬 실행
○ build라는 job을 생성하고, 그 아래에 2개의 step이 존재하는 구조
○ runs-on은 어떤 OS에서 실행될지 지정
○ strategy - matrix 인자를 사용하면 어떤 파이썬 버전에서 테스트할지 확인할 수 있음.
○ steps의 uses는 어떤 액션을 사용할지 지정함. 이미 만들어진 액션을 사용할 때 지정
민감한 정보 사용해야된다면 Github > Settings > secrets 에 저장하여 환경변수로 사용할 수 있습니다.
job 끼리 의존 관계를 설정해 순서를 정의할 수 있습니다.
job1은 job2이 시작되기 전에 성공적으로 완료되어야 하고 job3은 job1과 job2이 모두 완료될 때까지 기다립니다.
setup 실행, 성공하면 build가 실행되고 성공하면 test가 실행됩니다.
다양한 OS, 플랫폼, 언어의 여러 조합에서 테스트를 실행하려는 경우 빌드 매트릭스를 활용하면 됩니다. 빌드 옵션을 배열로 받는 strategy 키워드를 사용하면 됩니다.
GIthub의 runner는 각 작업에서 새로운 환경으로 실행되므로 작업들이 종속성을 재사용하는 경우 파일들을 캐싱하여 성능을 높일 수 있습니다. 캐시를 생성하면 해당 저장소의 모든 workflow에서 사용할 수 있습니다.
artifact를 사용하면 job끼리 데이터를 공유하거나 workflow가 끝나고 데이터를 저장할 수 있습니다. workflow에서 생성된 파일을 upload하고, 다른 job에서 사용할 경우 업로드된 파일을 download해서 사용하는 방식입니다. job_1에서 math-homework.txt 파일을 생성하고 업로드합니다. 다음 job_2는 job_1에서 업로드한 파일을 다운로드하고 연산한 후, 다시 업로드합니다. job_3은 job_2에서 업로드한 파일을 다운받아 출력하고 끝나는 예시입니다.