CI/CD 플랫폼과 기본 개념 알아보기

cozzin·2023년 8월 15일
0

이번 글에서는 CI/CD가 무엇인지, 어떤 DevOps 플랫폼이 있는지, 동작을 이해할 때 도움되는 용어들을 알아보겠습니다. 저도 1년 반 전에만 해도 CI 개념을 잘 몰랐지만 SDK 자동화 도입하면서 CircleCI, Github Action을 다룰 기회가 많았습니다. 개발팀에서 본인이 DevOps 작업을 많이 하지 않더라도 작동 원리를 알아두면 도움이 될 거라 생각합니다. 아무래도 외부 환경에 메세지를 보내거나 빌드하는 과정에서 언젠가 에러가 발생할 수 있습니다. 제 글을 통해 개념을 익혀뒀다가 필요할 때 앞장서서 문제를 해결할 수 있으면 좋겠습니다.

CI가 뭐지? - Continuous Integration

CI(지속적인 통합)는 코드를 공유 리포지토리의 선택된 분기에 초기에 자주 통합하는 방식입니다. 독립적으로 기능을 구축하고 개발 주기가 끝날 때 기능을 통합하는 대신 개발자가 공유 메인라인에 매일 커밋하여 하루 종일 여러 번 코드를 공유 리포지토리와 통합합니다. 모든 커밋은 자동화된 테스트 및 빌드를 트리거합니다. 실패하면 신속하게 수리할 수 있습니다.
출처: https://circleci.com/docs/about-circleci/#what-is-ci-cd

협업 경험이 별로 없을 때는 작업한 것을 저장해서 압축파일로 만들고, 그 압축파일들을 열고 코드를 수동으로 합쳤던 기억이 있습니다. git을 사용해서 그런 협업 경험을 개선하게 되었습니다. 코드를 하나로 합칠 때 conflict가 발생하긴 하지만, 3-way merge를 통해서 비교적 편리하게 합칠 수 있습니다. 그런데 기존에는 잘 작동하던 기능이 코드를 합치고 나면 기대하는 대로 작동하지 않는 경우가 꽤 있습니다.

코드가 통합되고 나서도 기능이 작동하는 것을 검증해주면 좋겠죠? 이런 검증을 위해서 merge 후에 빌드를 해보고, 테스트 코드 결과를 검증해보고, 배포가 가능한지도 확인해보면 좋습니다. 그런데 끊임없이 최신 코드들이 통합되는 상황에서 매번 테스트를 하기 어렵습니다.

지겹고 여러번 반복되는 일은 자동화하면 좋은데요. 자동화된 테스트를 로컬 환경에서도 작동할 수 있습니다. 하지만 로컬에서 테스트를 실행하면 로컬 환경의 리소스를 점유하게되는 단점이 있습니다. 그래서 대부분의 개발팀에서는 CI 서버에서 자동으로 테스트를 실행합니다.

자동으로 테스트를 실행한다라고 표현했는데 사실 CI 동작이 언제 실행될지는 정하기 나름입니다. 어떤 조건을 만족하면 동작을 실행할지(trigger), 선행 조건은 무엇인지(requires), 어떤 환경에서 실행할지(enviornment), 병렬로 실행할지(parallelism) 설정해둘 수 있습니다. 다양한 조건과 환경으로 테스트를 실행하고 결과를 리포트로 받아볼 수 있습니다.

CD는 뭐지? - Continuous Delivery, Continuous Deployment

CI에 비해서 CD라는 용어는 일상에서는 별로 들어보지 못했습니다. 평소에는 CI 서버라고 부르는게 전부였습니다. 용어를 자세히 찾아보니 CI 과정 이후 -> 버그테스트 -> staging 릴리즈 -> production 배포 하는 과정을 CD 라고 부릅니다. 앱 개발 입장에서보면 버그 테스트 -> 앱 릴리즈 -> AppStore 심사 등록이 CD에 포함될 것 같네요.

Continuous Delivery와 Continuous Deployment 앞 글자만 따면 동일하게 CD 이지만 차이점이 존재합니다. 한 걸음 나아가서 production 배포까지 자동화 하면 Continuous Deployment 라고 부를 수 있습니다.

  • Continuous Delivery: 버그테스트 -> staging 릴리즈 -(수동) -> production배포
  • Continuous Deployment: 버그테스트 -> staging 릴리즈 -(자동)-> production배포

CI/CD 플랫폼

CI/CD 플랫폼은 엄청나게 많습니다. 이 중에 제가 사용해본 플랫폼은 Jenkins, Github Action, CircleCI가 있습니다.

  • Jenkins
  • CircleCI
  • Github Action
  • GitLab
  • Bamboo
  • TravisCI
  • TeamCity

플랫폼 마다 인터페이스가 조금씩 다르고 가격 정책도 달라서 선택하기 전에 고민이 필요합니다. 플랫폼을 관리하는 방식에서 크게 다른 점이 있다면 On-premise 방식과 Cloud 방식이 있습니다.

On-premise

On-premise는 직접 설치해서 관리하는 방식입니다. 대표적으로 On-premise 방식에서 사용되는 플랫폼은 Jenkins 입니다. 오픈소스이고 무료라서 소규모 팀에서 많은 선택을 받는 것 같습니다. 몇 가지 단점과 장점이 있습니다.

장점

  • 디바이스 구매 비용과 전기세를 빼면 직접적인 추가 비용이 들지 않습니다. (이걸 유지하기 위한 시간이 드니까 간접적으로 보면 인건비가 들겠네요)
  • 팀을 위한 공용 서버가 1대 생기는거라서 필요한 프로그램이나 스크립트를 마음대로 실행할 수 있습니다. CI/CD 플랫폼 이외에도 다른 서버를 운영하면서 생산성을 키울 수도 있겠네요.

단점

  • 직접 설치해서 사용해야해서 디바이스 관리가 필요합니다. 회사 맥미니에 CI 서버를 설치해두고 쓴 적이 있는데 의도치않게 서버가 종료되면 누군가 다시 켜야했습니다.
  • 캐시 용량도 가득차면 한 번씩 초기화가 필요해서 불편합니다.
  • Xcode 같은 환경 설정을 동적으로 변경하기 어렵습니다.
  • 보통 물리 서버 1대를 사용하는데, CPU, RAM 리소스의 한계가 있기 때문에 여러 Job을 실행시키기 어렵습니다.

Cloud

많은 곳에서 클라우드 방식을 사용하고 있습니다.

장점

  • 개발 환경을 관리하기 쉽습니다. 기본 제공되는 도커 이미지들에서 선택해서 사용할 수 있습니다.
  • 여러 Job을 병렬로 실행시킬 수 있습니다. 빌드를 위해 가상 서버를 띄워서 사용하기 때문에 여러 Job을 동시에 실행해도 충돌이 나지 않습니다.
  • 일관된 동작을 보장받을 수 있습니다.
  • 물리 서버를 관리하지 않아도 됩니다.

단점

  • CI를 열심히 사용할 수록 비용이 증가합니다.
  • 개발 환경 설정이 쉽지만 플랫폼에서 도커 이미지를 deprecated 시키는 경우도 있습니다.
  • 하나의 플랫폼에 의존되면 다른 플랫폼으로 넘어가기 어렵습니다. 불가능한 것은 아니지만 CI 실행을 위한 설정 파일이 플랫폼 마다 다릅니다.

CI/CD 플랫폼 핵심 용어 살펴보기

플랫폼 마다 용어가 조금씩 다를 수 있지만, 전체적인 흐름은 비슷합니다. CircleCI, Github Action를 예시로 어떤 개념들이 있는지 알아봅시다. 최근에 가장 많이 사용했던 플랫폼들이고 Docs도 잘 되어 있어서 이걸 예시로 들겠습니다.

Config

CI/CD가 작동할 조건, 환경, 명령어들을 관리하는 파일입니다. CI/CD를 처음 세팅할 때 이 파일들을 생성하게 됩니다.

  • CircleCI: 프로젝트 최상단에 config.yml 파일 하나만 두고 관리합니다. 파일을 쪼갤 수 없는건 상당히 불편합니다.
  • Github Action: .github/workflows/ 폴더 아래에 yml 파일을 생성해서 workflow를 관리합니다.

https://circleci.com/docs/concepts/#workflows

CircleCI:

version: 2.1

jobs:
  build1:
    docker:
      - image: cimg/ruby:2.4-node
      - image: cimg/postgres:9.4.12
    steps:
      - checkout
      - save_cache: # Caches dependencies with a cache key
          key: v1-repo-{{ .Environment.CIRCLE_SHA1 }}
          paths:
            - ~/circleci-demo-workflows
#...
workflows:
  build_and_test: # name of your workflow
    jobs:
      - build1
      - build2:
          requires:
           - build1 # wait for build1 job to complete successfully before starting
           # see circleci.com/docs/workflows/ for more examples.
      - build3:
          requires:
           - build1 # wait for build1 job to complete successfully before starting
           # run build2 and build3 concurrently to save time.

Github Action:

name: learn-github-actions
run-name: ${{ github.actor }} is learning GitHub Actions
on: [push]
jobs:
  check-bats-version:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '14'
      - run: npm install -g bats
      - run: bats -v

Workflows

두 플랫폼 모두 workflows 라고 부르는 작업 단위가 있습니다. repository에 event가 발생하면 job들을 실행합니다. 순차적으로 실행할 수도 있고, 병렬로 실행할 수도 있습니다.

위에서 소개했던 YAML 파일에 어떻게 작동할지 정의합니다. 하나의 repository는 여러개의 workflow를 가질 수 있습니다.

github action 예시: event 발생 후 순차적으로 작업 실행합니다.

CircleCI 예시: event 발생 후 4개의 job은 build_config_builder, build_config_ref, build_api_docs, js_build 각자 실행시키고, 4개가 모두 완료되었을 때 build job을 실행시키는 예시입니다.

Jobs

하나의 workflow 안에서 사용되는 steps의 모음 입니다. 각 step은 shell script 명령어가 될 수 있고, 아니면 action을 실행할 수 있습니다.

Runners(Executor)

Job은 어떤 환경에서 실행될지 지정할 수 있습니다. 예를 들어 docker, machine, windows, macos 이런 것들을 지정합니다.

CircleCI의 macOS 환경을 사용하면 xcode 버전을 지정할 수 있습니다. 여러 버전의 Xcode 위에서 테스트하거나 아카이빙할 수 있어서 좋습니다. https://circleci.com/docs/executor-intro/#macos

jobs:
  build: # name of your job
    macos: # executor type
      xcode: 14.2.0

    steps:
      # Commands run in a macOS virtual machine environment
      # with Xcode 14.2.0 installed

Actions(Orbs)

Action은 명령어 라이브러리 같은 느낌인데, 자주 사용되고 유용한 명령어들을 라이브러리 형태로 만들어둘 수 있습니다. Github Action을 만들고 싶다면 다음 문서를 참고하세요. https://docs.github.com/en/actions/creating-actions

CircleCI에서는 비슷한 역할을 하는 것을 Orbs라고 부릅니다.

config 파일 이해하기

Github Action

name: learn-github-actions # workflow 이름 (class 이름 같은 느낌)
run-name: ${{ github.actor }} is learning GitHub Actions # 실행되는 workflow 이름 (instance 이름 같은 느낌)
on: [push] # event 트리거 조건 지정
jobs:
  check-bats-version: # job 이름
    runs-on: ubuntu-latest # runner 지정. 작동할 환경 세팅
    steps:
      - uses: actions/checkout@v3 # action 사용 예시
      - uses: actions/setup-node@v3
        with:
          node-version: '14' # action에 파라미터 넣을 수 있음
      - run: npm install -g bats # shell script 실행
      - run: bats -v

https://docs.github.com/ko/actions/learn-github-actions/understanding-github-actions#understanding-the-workflow-file

CircleCI

version: 2.1 # circleci yml 버전 이걸 바꿀 일은 아직 없었습니다

jobs: # 여기서 job들을 선언해둡니다
  build1: # job 이름을 붙여줍니다
    docker:
      - image: cimg/ruby:2.4-node # 어떤 도커 이미지 위에서 실행시킬지 지정
      - image: cimg/postgres:9.4.12 
    steps:
      - checkout # 기본 repo checkout 하는 예약어 입니다.
      - save_cache: # 캐시도 사용할 수 있습니다. 캐시 폴더를 수동으로 초기화할 방법은 없다고 알고 있습니다.
          key: v1-repo-{{ .Environment.CIRCLE_SHA1 }}
          paths:
            - ~/circleci-demo-workflows

  build2:
    docker:
      - image: cimg/ruby:2.4-node
      - image: cimg/postgres:9.4.12
    steps:
      - restore_cache: # Restores the cached dependency.
          key: v1-repo-{{ .Environment.CIRCLE_SHA1 }}
      - run:
          name: Running tests
          command: make test
#...
workflows: # workflow 들을 정의합니다
  build_and_test: # workflow 이름 정의
    jobs: # 어떤 job을 실행시킬지 정의 
      - build1
      - build2:
          requires:
           - build1 # build1 끝나고 build2 실행되게 할 때 사용
           # see circleci.com/docs/workflows/ for more examples.

https://circleci.com/docs/concepts/#workflows

정리

한 번에 2개의 플랫폼을 섞어서 설명했는데, 이해하는데 도움이 되면 좋겠습니다. 기본 개념들만 설명해뒀는데 자동화를 구현하다 보면 Secret 값 관리, 트리거 조건 관리 같은 것들도 꽤나 많이 들여다보게 되더라구요. 적용하면서 해당 플랫폼의 Docs 펼쳐두고 적용하는게 좋을 것 같습니다. 그리고 각 플랫폼을 위한 VSCode Extension 들이 있으니 설치해서 config 파일들을 수정하는 것을 추천합니다. YAML 파일을 다루다보니 들여쓰기가 맞아야하고, 플랫폼에서 정의해둔 예약어도 있어서 기본 텍스트 에디터로 작업하면 CI에서 에러를 출력하는 경우가 많았습니다. 결국 직접 부딪혀보면서 실행해보는게 제일 좋은 것 같습니다. 모두들 화이팅입니다 🙌

참고자료

profile
Software Engineer

2개의 댓글

comment-user-thumbnail
2023년 8월 15일

큰 도움이 되었습니다, 감사합니다.

1개의 답글