ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Github Actions을 활용한 CI 안정성 확보하기
    Contribution 2022. 6. 26. 20:08
    반응형

    1) 서론

    혹시 요리를 자주 하시나요?

     

    저는 가끔 이것저것 남은 재료를 가지고 요리를 하곤 하는데요. 하지만 요리 실력은 마음처럼 잘 따라주지 않습니다. 그래서 간혹 참사가 벌어지고는 하는데요. 

     

    맛있는 재료들만 넣고 만들었는데 완성하고 보니 맛이 이상한 경우가 많습니다. 분명히 맛있을 수밖에 없는 재료들만 넣고 합쳤는데, 왜 맛이 없을까요? 아마도 각각의 재료들은 아주 뛰어나지만 이것들을 잘 조화롭게 합쳐서 요리하지 못한 게 문제일 것 같습니다.

     

    개발할 때의 CI(Continuous Integration)도 비슷할 것 같습니다. 최근 각각의 PR단위에서는 문제가 없었지만, 배포 시 빌드가 되지 않던 경험이 있었습니다. 이를 사전에 해결하기 위해 도입한 Github Actions 내용을 공유드립니다.

     

    내가 살아있는 한 그딴 걸 main 브랜치에 merge하지 않을거야!


    2) 배포 시 빌드 실패

    사실 회사에서 엄격한 의미의 CI/CD를 구축하고 있지는 않았었습니다. 아무래도 빠르게 실행해야 하는 스타트업 특성상 일단 동작하고 서비스에 반영되는것이 우선이었을것이라고 추측합니다.

     

    기존에는 아래와 같이 CI/CD가 이루어졌습니다.

    • Github PR
    • Main 브랜치 merge
    • Jenkins를 이용해서 최종 배포

     

    문제는 이랬습니다.

    • 각각의 여러 PR들이 존재
    • 여러 PR 중 하나는 간단한 애플리케이션 설정 변경하는 것이 존재
    • 문제 없다고 판단되어, 여러 PR이 동시다발적으로 Main 브랜치 merge
    • Jenkins 배포 중 컴파일 에러 발생

     

    열심히 작업을 했지만 Jenkins에서 컴파일 에러와 함께 빌드가 되지 않았습니다.


    3) Jenkins에서 빌드 실패가 되면 괜찮은거 아닌가요?

    아직 서비스가 배포되지 않았고, Jenkins에서 빌드 실패를 잘 알려주면 괜찮은거 아닐까요? 오히려 서비스 반영 전 알게되서, 다행이라고 생각할 수도 있습니다.

     

    CI/CD 중 CI의 관점에서 바라보려고 합니다.

     

    CI는 Continuous Integration, 즉 '지속적 통합'이라는 의미를 가지고 있습니다. 그렇다면 무엇을 지속적으로 통합하는 걸까요?

     

    현대의 거대한 프로젝트들은 많은 사람의 코드 기여(contribution)를 통해서 이루어집니다. 하나의 프로젝트에 수많은 사람들의 코드가 test, build 그리고 run되는 과정이 지속적으로 이루어지는 것을 의미하는데요.

     

    하지만 CI는 단순히 배포 과정에서 실제 애플리케이션이 run될 때 검증하는 것이 아니라고 생각합니다. Git으로 형상관리할 때 중심이 되는 것, 보통 main(master) 브랜치라고 불리는 곳에 코드가 통합될 때 검증이 되어야 한다고 생각합니다.

     

    위의 상황에서는 불안정한 코드가 검증되지 않은 채 이미 main 브랜치에 반영됐고, 이를 모른 채 pull 후 사용하는 사람들도 모두 장애를 맞이하게 됩니다. 즉 엄격한 의미의 CI에 실패했다고 생각합니다.

     

    물론 revert 같은 기능을 활용하면 쉽게 rollback할 수 있습니다. 하지만 CI라는 관점에서 봤을 때 main이라는 중심이 되는 형상에는 반드시 문제없는것만 반영되어야 한다고 생각합니다.

     

    심지어 현재는 -x test 옵션을 활용해서 테스트 코드는 동작하지 않게 되어있습니다. 사실상 동작하지 않는 불필요한 테스트 코드들이 무겁게 존재하고, 이들이 통합되고 있었습니다.

     

    개인적으로는 동작하지 않는 테스트 코드라면

    • 동작하게 만들던가
    • 과거의 히스토리 차원에서 주석처리하던가
    • 과감히 삭제해야 한다고 생각합니다.

    4) Github Actions 도입

    위의 장애 상황을 겪고 Github Actions를 통해서 CI를 적용해봤습니다.

    (모든 이미지 및 설정들은 회사와 무관한 내용입니다)

     

    Java with Gradle이라는 workflow입니다.

     

    • Gradle을 활용해서 build, test를 수행하는 workflow입니다.
    • Github팀에서 만들었기 때문에 믿고 사용할 수 있을 것 같습니다.

    4. 1) workflow yaml 파일 작성

    name: Java CI with Gradle
    
    on:
      // commit push 시
      push:
        branches: [ "main" ]
      
      // PR 생성 시  
      pull_request:
        branches: [ "main" ]
    
    permissions:
      contents: read
    
    jobs:
      build:
        runs-on: ubuntu-latest
    
        steps:
          - uses: actions/checkout@v3
          - uses: actions/setup-java@v3
            
            // temurin jdk 11 적용
            with:
              distribution: temurin
              java-version: 11
    
          // Gradle build 실행
          - name: Execute Gradle build
            run: ./gradlew clean build

    매우 간단한 workflow입니다.

     

    아래의 경우에 workflow가 동작합니다.

    • main 브랜치에 PR 생성 시
    • 해당 PR에 commit이 push 되었을 때

    어떤 job이 동작할까요?

    • temurin사의 JDK 11을 사용합니다.
    • ./gradlew clean build를 이용해서 프로젝트 빌드합니다.
      • -x test 옵션이 없으므로 테스트 코드도 모두 동작하게 됩니다.

    4. 2) Github branch protection rule 설정

    • branch rule을 추가합니다.
    • workflow가 성공적으로 동작하지 않는다면 merge를 막습니다.

    • PR 생성 및 commit push 시 정의된 workflow가 실행됩니다.
    • workflow가 성공하지 않았으므로 merge는 막혀있습니다.

    • 성공적으로 pass 후 merge가 가능해졌습니다.

    5) Test coverage는 볼 수 없을까요?

    테스트 코드도 본격적으로 검증하게 됐습니다. 하지만 테스트 수행에 대한 coverage를 확인할 수 없다는 것이 아쉽습니다.

     

    물론 Codecov를 이용해서 테스트에 대한 결과를 UI를 활용해 보여줄 수 있습니다. 하지만 외부 서비스에 Github 토큰을 등록해줘야 하고, 불필요한 연동이 발생한다는 점에서 적용하지 않았습니다. 만약 해당 서비스의 보안 혹은 운영적인 문제가 발생한다면 큰 위험이 될 것이라고 생각했기 때문입니다.

     

    아쉽게도 당분간은 인텔리제이에서 제공하는 coverage 기능을 사용하기로 결정했습니다. 

     

    CI 구축 시 test coverage를 UI로서 제공하는 좋은 방법을 아신다면, 알려주시면 감사하겠습니다.


    6) 무료에요?

    사실 세상에 좋은 도구는 많습니다. 하지만 언제나 문제는 돈 인데요.

     

    Github Actions도 무료는 아닙니다. 아래와 같은 가격 정책을 가지고 있는데요. 아쉽게도 이러한 가격 정책 때문에 작은 단위의 프로젝트에만 적용해볼 수 있었습니다. 

     

     

    다만 Github Actions를 통한 CI/CD 구축이 정말로 효율적이라고 판단되면, 과감히 도입을 검토할 수 있지 않을까 생각합니다.


    7) 결론

    간단한 workflow를 구성해서 CI를 구축했습니다. 그리고 아래의 작은 성과를 달성할 수 있었는데요.

    • 최소한의 컴파일 시점 오류 방지
    • 동작하지 않는 테스트 코드 push 방지
    • 불안정한 코드의 main 브랜치 merge 방지

     

    CI의 문제점을 해결하고, 위의 내용을 도입하며 CI/CD에 대한 새로운 시야가 생길 수 있어서 좋았습니다. 하지만 분명히 더 많은 기능 추가를 통해서 CI를 구축하는 방법이 있을것 같습니다. 노하우가 쌓인다면 기존의 내용을 조금 더 개선해보고 싶습니다. 

     

    이를 통해서 추가적인 목표가 생겼는데요. 그리고 최종적으로는 현재 회사 클라우드 환경인 Docker + K8s + GCP로의 CD(Continuous Deployment) 즉 지속적 제공을 효율적으로 구축해보고 싶다는 생각이 듭니다.

    반응형

    댓글

Designed by Tistory.