본문 바로가기

[Project] 프로젝트 삽질기35 (feat CI)

어가며

사이드 프로젝트에서 푸시 알림을 활용한 서비스를 개발하고 있습니다. Github Action을 활용하여 배포 자동화를 구축하는 과정에서 CI는 어떻게 구축하는 것인지 궁금증이 생겼습니다. CI란 무엇이며 CI를 어떻게 구축하는 것인지 이 글을 통해 정리해보고자 합니다. 이 글은 참고 및 출처에 있는 글들을 공부하며, 프로젝트에 적용하면서 작성된 글입니다. 

 

 

 

 

 
 
 
 
 
 
 
 
 

 

CI & CD

CI란 Continuous Integration의 약자로 지속적 통합을 의미하며, CD는 지속적인 서비스 제공(Continuous Delivery)과 배포(Continuous Deployment)를 의미합니다. 이에 대해 좀 더 자세히 알아보겠습니다.

 

CI?

위에서 CI를 지속적 통합이라는 의미로 살펴봤습니다. 지속적 통합이라는 것은 무엇일까요? 아래 예시를 통해 알아보겠습니다. 

 

 

A팀에 개발자가 5명 존재한다.
이 팀은 각각, 코드 작업을 완료하여 github에 push한다.
그리고 모인 코드는 병합을 거치게 된다.
그런데 병합 과정에서 동일한 코드를 수정한 경우 충돌이 발생하게 된다.
발생한 충돌을 해결하기 위해 수동으로 작업을 진행한다.

그 다음 배포를 해야하는데,
배포 하기에 앞서 코드에 문제가 없는 지 테스트를 진행한다.
그런데 코드에 치명적인 버그가 발생한다.
이 버그를 해결하기 위해 이 코드와 관련된 팀원이 일을 진행한다.

이처럼 A팀은 코드 푸시 -> 병합 -> 충돌 발생시 해결 -> 기능 테스트 작업을 매번 거친다.

 

위 예시에서, A팀은 코드 푸시, 병합, 충돌 발생 시 해결, 기능 테스트 작업을 매번 반복합니다. 개발 프로젝트의 규모가 커질수록 이 과정에 투자해야 하는 시간이 증가하게 됩니다. 만약 CI를 이용한다면 이 과정을 자동화시켜 시간을 절약해줄 수 있습니다. 하지만 이렇게 CI 개념을 살펴봤을 때, 아직 CI라는 개념이 무엇인지 몸으로 깨닫지 못했습니다. 지속적인 통합이란 무엇인지 조금 더 자세하게 알아보겠습니다.

 

 

 

 

 

 

It's not CI, it's just CI Theatre | GoCD Blog

The ThoughtWorks tech radar recently recommended putting a “Hold” on the tech team antipattern, “CI Theatre”. “CI theatre” describes the illusion of practising continuous integration (CI) while not really practising it. Based on continuous inte

www.gocd.org

 

[CI / CD] 당신은 정말 지속적인 통합(CI)을 하고 있는가?

안녕하세요? 제이온입니다. 과거 힐링페이퍼 면접 이후 이규원 CTO 님께서 제가 가지고 있던 CI의 오해를 바로 잡기를 권유하시며, 한 가지 포스팅을 추천해 주셨습니다. 이번 시간에는 그 포스팅

steady-coding.tistory.com

 

당신은 정말 지속적인 통합(CI)을 하고 있는가?

CI 개념을 이해하기 위해 제이온님의 '[CI/CD] 당신은 정말 지속적인 통합(CI)을 하고 있는가?' 글을 읽으며 공부했습니다. 이 글을 읽으면서 'CI 개발자는 정기적(최소한 매일)으로 모든 작업을 master 브랜치에 통합한다.'라는 문구가 인상적이었습니다. 어쩌면 CI라는 지속적인 통합이라는 것은 현재 작업하고 있는 코드를 master 브랜치에 지속적으로 통합함으로써 하루에도 여러 번 배포할 수 있도록 설계하는 방법이 아닐까 생각했습니다. 만약 master 브랜치에 코드를 안정적으로 통합하려면 통합하는 과정에서 테스트 코드를 자동으로 수행하게끔 설정해야 하겠다는 특징을 깨달았습니다. 

 

 

 

 

 

 

 

[협업] 협업을 위한 Git Flow 설정하기

들어가며 Git 커밋 컨벤션을 정리한 글에 이어, 협업에 필요한 내용들을 계속해서 정리하고 있습니다. 개인적으로 저는 git 때문에 어려움을 겪었던 적이 많습니다. git 설정을 잘못해서 기존 작업

overcome-the-limits.tistory.com

 

Git-Flow와 지속적인 통합(CI)은 어울리는가? 

저는 프로젝트를 개발하면서 항상 Git-Flow를 활용했습니다. master 브랜치를 배포 서버의 브랜치로 설정하고, develop 브랜치를 개발 서버의 브랜치로 설정했으며, develop 브랜치에서 feature 브랜치로 나눠서 작업한 후 develop 브랜치에 머지하는 형식으로 개발을 진행했습니다.

 

이렇게 작업하면서 '배포'라는 것이 두려움의 상징이 되어있었습니다. develop 개발 서버는 항상 최신화되어 있는데, develop 브랜치에서 master 브랜치로 머지하는 과정에서, 예를 들어 50개의 파일 변경과 3000줄의 코드가 변경된 사항을 머지하고 있었습니다. 머지하는 과정에서 어떤 문제가 발생할 수 있을지 예측이 안되었기에 배포하는 것이 불안했습니다.

 

 

 

 

 

 

 

Github-Flow와 지속적인 통합(CI) 활용하기

위의 당신은 정말 지속적인 통합(CI)을 하고 있는가 글을 읽으면서 진정으로 CI를 구성하기 위해서는 master 브랜치를 기반으로 한 개발 방식을 선택해야겠다고 생각했습니다. 이를 위해 Github-Flow를 선택했습니다. 

 

Github-Flow는 어떻게 적용할까? 

Github-Flow에서는 master 브랜치를 언제든지 배포 가능 상태로 유지하며, master 브랜치에 merge를 하려 할 때는 Pull Request를 생성합니다. 만약 master 브랜치에 merge가 되고 push 되었을 때 즉시 배포가 될 수 있도록 설정합니다. 그리고 merge 된 브랜치는 삭제하는 과정에서 Github-Flow를 활용할 수 있습니다.

 

Git-Flow는 CI와 안 어울릴까?

이렇게 설정함으로써 Git-Flow을 활용했을 때 배포의 두려움 문제를 일정 부분 해결할 수 있습니다. 물론 Git-Flow도 좋은 브랜칭 전략이라고 생각합니다. 브랜치 별로 역할과 책임을 분리해서 활용할 수 있다는 부분이 장점입니다만, CI를 활용할 때 좋은 브랜칭 전략일까 하는 생각이 아직까지 들곤 합니다. 이 글을 읽는 여러분들은 이 부분에 대해 어떻게 생각하시는지 궁금하기도 합니다.

 

Github-Flow의 단점은 없을까?

그리고 이렇게 Github-Flow를 적용했을 때 단점이 존재합니다. Github-Flow를 적용했을 때 QA를 진행하기 어렵다는 점이 문제가 될 수 있습니다. 배포하고 있는 master 브랜치로 코드를 통합하다 보니, 코드를 통합하는 과정에서 QA를 진행하기 어려울 수 있습니다. 이 문제를 해결하기 위해서는 QA 과정을 진행하기 위해 수동 배포하는 것도 생각해볼 필요가 있습니다. 먼저 QA를 진행하기 위해 테스트 서버에 수동 배포를 진행해서, 테스트 후 문제가 없다면 master 브랜치로 머지하는 과정을 거치는 것이 어떠할까 라는 생각이 들었습니다. 

 

 

 

 

그래서 어떻게 적용했는가?

저는 위의 내용을 기반으로 Github-Flow를 기반으로 master 브랜치에 코드가 머지될 경우 자동 배포하는 Github Actions의 workflow를 적용했습니다. 그리고 master 브랜치에 코드를 머지할 때 안정성을 높이기 위해 CI workflow를 적용했습니다.

 

 

name: Integration Test
on:
  pull_request:
    branches:
      - 'master'

jobs:
  ci:
    runs-on: ubuntu-latest
    container: node:16-alpine
    env:
      NODE_ENV: CI
      PORT: ${{ secrets.PORT }}

    services:
      rdb:
        image: bitnami/mysql:8.0.20
        env:
          MYSQL_ROOT_PASSWORD: triplepassword
          MYSQL_AUTHENTICATION_PLUGIN: mysql_native_password
        ports:
          - 3306/tcp
        options: >-
          --health-cmd="mysqladmin ping"
          --health-interval=10s
          --health-timeout=5s
          --health-retries=3

    steps:
      - name: Checkout source code
        uses: actions/checkout@v2

      - name: Install RDB Dependencies
        run: apk add mysql-client

      - name: Setup Node Environment
        run: npm ci --force

      - name: Test with DB
        run: npx jest --coverage  --runInBand --forceExit

      - name: Success
        run: echo Test Completed Successfully.

 

 

위와 같이 설정하여 master 브랜치로 코드가 통합되는 상황에서 문제는 없는지 자동으로 체크할 수 있도록 설정했습니다.

 

 

아쉬운 점

위의 workflow대로 진행되다 보면 master 브랜치에 코드를 병합하기 위해 PR을 올리면, 테스트 코드가 실행되고, 테스트 코드가 성공적으로 완료된다면 master 브랜치에 머지합니다. 그 과정에서 배포 환경에 바로 새로 작성된 코드를 바탕으로 새롭게 배포되기 때문에 배포 환경에서는 QA를 제대로 진행하지 하지 못하는 문제가 발생했습니다. 

 

그래서 이 문제를 해결하려면 뱅크 샐러드의 '하루에 1000번 배포하는 조직되기' 포스팅에서 설명하는 Commit-Train Based Deployment를 적용하면 좋겠다고 생각했습니다. 

 

 

Commit-Train Based Deployment

뱅크 샐러드의 글에서는 Commit-Train Based Deployment를 아래와 같이 설명하고 있습니다. 

 

master branch만 존재하고 이를 base로 새로운 branch를 따서 작은 단위로 작업하고, Pull Request를 열어 리뷰를 받은 뒤 master branch에 바로 squash merge 하고 merge 된 commit들을 모아 배포하는 방식으로 일합니다. 이때 master에는 배포 가능한 단위의 여러 커밋이 나열되게 됩니다. 이런 배포되지 않은 커밋들을 여러 개를 모아서 한 번에 배포하게 됩니다.
이 모습이 마치 역에서 여러 량의 기차가 정차해 있다가 출발하는 모양과 비슷해서 Commit-Train Based Deployment라는 명칭이 붙었다고 합니다. 물론 아무리 작은 단위의 PR이라지만 commit을 쌓아놨다가 배포하려고 할 때 발생할 수 있는 사이드 이펙트나 커뮤니케이션 비용을 줄이기 위해 master에 merge 된 commit은 최대한 빠르게 배포하는 것을 권장하고 있습니다. 이렇게 master branch에서 각기 다른 commit들이 production, staging, development, testing 등 여러 환경에 배포됩니다.

 

 

뱅크 샐러드의 글을 읽으면서, 아직 테스트 코드를 명확하게 작성하지 못한 상태에서 작성한 코드를 바로 배포하기엔 문제가 있다고 생각했습니다. 그래서 QA를 할 수 있도록 서버 배포를 수동으로 하는 방법으로 수정해야겠다고 생각했습니다. 또한 master 브랜치로 코드를 병합하는 과정에서 문제를 최소화시키기 위해 정적 코드 분석 툴인 소나 큐브 혹은 소나 클라우드를 적용해야겠다고 생각했습니다.

 

 

Commit-Train Based Deployment와 CD

만약 Commit-Train Based Deployment를 수행하기 위해 수동 배포를 한다면, CD를 제대로 하고 있다고 말할 수 있을까 하는 고민이 듭니다. 지속적인 제공의 개념에서의 CD는 개발자들이 애플리케이션에 적용한 변경 사항이 버그 테스트를 거쳐 리포지토리에 자동으로 업로드되는 것을 뜻합니다. 그리고 지속적인 배포의 개념에서의 CD는 리포지토리에 저장된 변경 사항이 프로덕션 환경까지 자동으로 릴리스 되는 것을 의미합니다. 이때 Commit-Train Based Deployment를 수행하면 지속적인 제공의 의미인 CD는 잘 지킬 수 있지만 프로덕션 환경까지 자동으로 릴리스 되는 지속적인 배포의 의미에서의 CD는 제대로 지키지 못하는 것이 아닐까 생각이 듭니다.

 

아직까지 명확한 저만의 답을 내지 못했지만, 앞으로 개발해가면서 저만의 관점을 갖고 싶습니다.

 

 

 

 

 

 

 


 

 

 

 

 

 

 

마치며

앞으로도 팀의 발전을 돕는 개발자가 되기 위해 노력하려 합니다. 팀에 필요한 부분이 무엇일지 고민하면서, 팀에 도움이 된다면, 열심히 공부해서 실무에 적용할 수 있는 개발자가 되기 위해 노력하고 싶습니다. 팀의 성장에 기여할 수 있는 개발자가 되겠습니다. 

 

 

 

 

 


 

 

 

 

 

 

참고 및 출처

 

CI/CD는 무엇일까 (with. github actions)

1. CI/CD는 무엇일까? 1) CI, CD란? CI/CD는 코드 병합, 테스트, 배포를 자동화하는 걸 이야기한다. CI (Continuous Integration)는 지속적 통합을 의미하며, CD 는 지속적인 서비스 제공(Continuous Delivery),..

mong-blog.tistory.com

 

[CI / CD] 당신은 정말 지속적인 통합(CI)을 하고 있는가?

안녕하세요? 제이온입니다. 과거 힐링페이퍼 면접 이후 이규원 CTO 님께서 제가 가지고 있던 CI의 오해를 바로 잡기를 권유하시며, 한 가지 포스팅을 추천해 주셨습니다. 이번 시간에는 그 포스팅

steady-coding.tistory.com

 

하루에 1000번 배포하는 조직 되기 | 뱅크샐러드

안녕하세요, 뱅크샐러드 Engineering Foundation의 Framework Team 소속 Server Engineer…

blog.banksalad.com

 

[Git] 브랜치 전략 - Github flow

브랜치 전략이란? 브랜치 전략이란 여러 개발자가 1개의 저장소를 사용하는 환경에서 효과적으로 활용하기 위해 나온 개념입니다. 브랜치 생성, 병합 등의 git 구조를 활용해 보다 효율적으로 소

brownbears.tistory.com

 

CI/CD(지속적 통합/지속적 제공): 개념, 방법, 장점, 구현 과정

CI/CD는 애플리케이션의 통합 및 테스트부터 제공 및 배포까지 전체 라이프사이클에서 지속적인 자동화와 모니터링을 제공합니다. 개념, 차이점, 학습방법(인강)을 보세요.

www.redhat.com

 

 

Git Flow에서 트렁크 기반 개발으로 나아가기 - 맘시터 기술블로그

트렁크 기반 개발 방식으로 나아가며 배운 점들을 공유합니다.

tech.mfort.co.kr