개발 환경에서 지속적인 통합(CI)과 지속적인 배포(CD)는 코드의 품질을 유지하면서 빠르고 안정적인 배포를 가능하게 하는 핵심 요소들이다.
지속적인 통합 (Continuous Integration, CI)은 개발 팀이 자주 코드 변경사항을 중앙 리포지토리에 통합하는 프로세스를 말한다. 이러한 접근 방식의 주요 이점은 다음과 같다.
지속적인 배포 (Continuous Delivery, CD)는 CI 프로세스를 확장하여, 새로운 변경사항을 사용자에게 빠르고 안정적으로 제공하는 방법을 포함한다. 지속적인 배포의 핵심 요소들은 아래와 같다.
CI/CD 파이프라인은 일련의 자동화된 단계로 구성되며, 각 단계는 다음 단계로 진행되기 전에 성공적으로 완료되어야 한다. 아래와 같은 도구들이 파이프라인 구축에 일반적으로 사용된다.
GitHub Actions 워크플로우에 테스트 실행 단계를 추가하기 위해서는 arguments
옵션에 test
태스크를 추가한다. YAML 파일 내에 arguments: build test
라는 지시어를 통해 Gradle 빌드 과정에서 test
태스크가 호출되며 테스트가 실행된다. 아래 예시를 참고한다.
with:
arguments: build test
이 문제는 GitHub의 브랜치 보호 규칙을 사용하여 "Require status checks to pass before merging" 옵션을 활성화함으로써 해결한다. 이와 함께 필요한 상태 검사를 지정하여 빌드 실패 시 병합이 거부되도록 설정한다. 아래 예시를 참고하여 규칙을 설정한다.
Require status checks to pass before merging
Status checks that are required:
build
CI/CD 환경에서 지속적인 개발은 개별 작업 브랜치에서 작업을 완료한 후, 해당 브랜치로 풀 리퀘스트를 생성하여 main
브랜치에 병합하는 방식으로 이루어진다. 이 방법을 통해 코드 변경 사항은 테스트 및 빌드 과정을 거쳐 안정적인 main
브랜치에 병합되며, 코드의 안정성이 유지된다.
풀 리퀘스트 시에 빌드 대상은 변경 사항을 담고 있는 작업 브랜치다. 따라서, main
브랜치가 아닌 현재 작업 중인 브랜치에서 테스트와 빌드가 수행된다.
SpringBoot로 개발한 서비스에 GitHub Actions를 적용하려고 했는데, 테스트 중에 "Error: Gradle script '/home/runner/work/GitHubActionTest/GitHubActionTest/gradlew' is not executable."라는 오류를 마주쳤다. 이 문제는 Gradle 스크립트에 실행 권한이 없기 때문에 발생한 것으로 파악했고, GitHub Actions 워크플로우 내에서 chmod +x gradlew
명령을 사용하여 실행 권한을 부여함으로써 문제를 해결할 수 있었다.
그 다음 단계로 테스트를 실행하려고 했는데, 이를 위해 GitHub Actions 워크플로우의 arguments
옵션에 test
태스크를 추가해야 한다는 것을 알게 되었다. 이렇게 하면 Gradle이 프로젝트의 테스트를 자동으로 찾아 실행해 준다. 따라서 YAML 파일에 arguments: build test
를 추가하여 test
태스크를 호출할 수 있게 했다.
다만, 푸시 과정에서 몇 번의 오류 메시지를 받게 되었다. 먼저, "푸시가 거부되었다"는 메시지는 pull 작업을 생략하고 바로 push를 시도했기 때문에 발생한 것으로 파악되었다. 이 문제는 원격 저장소의 최신 변경 사항을 로컬 저장소에 먼저 pull하여 동기화한 후 push하는 방식으로 해결할 수 있었다.
또한, "Rule is invalid"라는 메시지도 마주쳤는데, 이는 규칙을 생성할 때 형식을 제대로 따르지 않아 발생한 문제였다. 규칙 설정을 정확하게 검토하고 형식에 맞게 수정함으로써 이 문제 또한 해결할 수 있었다.
이외에도 빌드 오류가 발생하더라도 코드가 main
브랜치에 푸시되는 문제에 직면했다. 이 문제는 GitHub의 브랜치 보호 규칙을 설정하여 "Require status checks to pass before merging" 옵션을 활성화함으로써 해결할 수 있었다. 이 설정을 통해 빌드가 실패하면 병합이 거부되도록 할 수 있었다.
그러나, 브랜치 보호 규칙을 설정한 후에도 빌드 실패에도 불구하고 변경 사항이 main
브랜치에 반영되는 문제가 계속 발생했다. 이유를 찾아보니 main
에서 main
으로 직접 푸시를 한 탓이었다. 일반적인 CI/CD 환경에서는 main
브랜치에 직접 푸시하지 않고, 별도의 작업 브랜치에서 작업을 완료한 후 풀 리퀘스트를 통해 main
브랜치로 병합하는 방식을 사용해야 한다는 것을 깨달았다.
이렇게 학습한 바로, CI/CD는 main
브랜치와 다른 작업 브랜치들 사이에서 주로 이루어지며, 코드 변경 사항이 작업 브랜치에서 main
브랜치로 풀 리퀘스트를 통해 병합되기 전에 반드시 테스트와 빌드 과정을 거친다는 것이다. 이 방식을 따르면 코드의 안정성을 유지할 수 있다.