CI/CD Git: CI 친화적인 Git 리포지토리를 위한 5가지 팁
성공을 위한 준비는 모두 리포지토리에서 시작합니다.
Sarah Goff-Dupont
주 작성자
Git 및 지속적 제공은 궁합이 아주 좋은 "초콜릿과 피넛 버터"처럼 소프트웨어 세계에서 흔히 발견할 수 없는 효과적인 조합입니다. 그래서 Bamboo 빌드가 Bitbucket 리포지토리와 잘 어울리도록 하기 위한 몇 가지 팁을 알려드립니다. 이 상호작용은 대부분 지속적 제공의 빌드 및 테스트 단계에서 이루어지므로 제 설명에서는 주로 "CD"보다는 "CI"가 나올 것입니다.
1: 대용량 파일을 리포지토리 외부에 저장
Git에 대해 자주 듣는 이야기로는 리포지토리에 바이너리, 미디어 파일, 보관된 아티팩트 등 대용량 파일을 넣지 말아야 한다는 것이 있습니다. 파일을 추가하면 파일은 리포지토리의 기록에 항상 존재하여 리포지토리를 복제할 때마다 대용량 파일이 함께 복제되기 때문입니다.
리포지토리 기록에서 파일을 추출하는 것은 까다로운 작업으로, 코드베이스에서 전두엽 절제술을 하는 것과 같습니다. 수술과도 같은 파일 추출은 리포지토리의 기록은 완전히 바꾸기 때문에 어떤 변화가 언제 이루어졌는지 더 이상 명확하게 파악할 수 없습니다. 일반적인 규칙으로 대용량 파일을 피해야 할 이유입니다. 그리고...
Git 리포지토리에서 대용량 파일을 보관하는 것은 CI에 특히 중요합니다
빌드할 때마다 CI 서버는 리포지토리를 작업 중인 빌드 디렉터리에 복제해야 합니다. 그리고 리포지토리에 대용량 아티팩트가 많으면 프로세스 속도가 느려지고 개발자가 빌드 결과를 기다리는 시간도 늘어납니다.
하지만 빌드가 다른 프로젝트의 바이너리나 대용량 아티팩트에 의존하면 어떻게 됩니까? 아주 흔한 상황이며 거의 항상 그럴 것입니다. 그렇다면 문제는 어떻게 하면 효과적으로 처리할 수 있느냐는 것입니다.
솔루션 보기
Open DevOps로 소프트웨어를 구축 및 운영
관련 자료
트렁크 기반 개발에 대해 알아보기
Artifactory(Bamboo 애드온 제작), Nexus, Archiva와 같은 외부 스토리지 시스템을 통해 사용자의 팀 또는 주변 팀에서 생성한 아티팩트를 보관할 수 있습니다. Maven 또는 Gradle을 통해 가져오는 타사 라이브러리처럼 필요한 파일을 빌드 초기에 빌드 디렉터리로 가져올 수 있습니다.
전문가 팁: 아티팩트가 자주 변경되면 매일 밤 대용량 파일을 빌드 서버에 동기화하려는 유혹을 참고 빌드 시 디스크 전체로 전송하기만 하면 됩니다. 밤마다 하는 동기화 사이에 결국 오래된 버전의 아티팩트를 가지고 빌드하게 될 것입니다. 게다가 개발자는 어차피 로컬 워크스테이션에 빌드할 때 이 파일이 필요합니다. 따라서 전반적으로 가장 깔끔한 방법은 아티팩트 다운로드를 빌드의 일부로 만드는 것입니다.
네트워크에 아직 외장 스토리지 시스템이 없다면 Git LFS(Large File Storage)를 이용하는 것이 가장 쉬운 방법입니다.
Git LSF는 리포지토리의 대용량 파일에 파일 자체를 저장하는 대신 포인터를 저장하는 확장 기능입니다. 파일 자체가 원격 서버에 저장됩니다. 이렇게 하면 복제 시간이 대폭 줄어듭니다.
Bitbucket 및 GitHub 모두 Git LFS를 지원하므로 아마 이미 액세스할 수 있을 것입니다.
2: CI에 부분 복제 사용
빌드가 실행될 때마다 빌드 서버가 리포지토리를 현재 작업 중인 디렉터리로 복제합니다. 앞서 설명한 바와 같이 Git이 리포지토리를 복제할 때는 기본적으로 리포지토리의 전체 기록이 복제됩니다. 따라서 시간이 지날수록 이 작업은 더 오래 걸릴 것입니다.
부분 복제의 경우 리포지토리의 현재 스냅샷만 가져옵니다. 따라서 특히 크거나 오래된 리포지토리의 경우 빌드 시간을 줄이는 데 아주 유용할 수 있습니다.
하지만 예를 들어 빌드의 단계 중 하나에서 POM(또는 이와 비슷한) 버전 번호를 업데이트하거나 각 빌드에 브랜치 두 개를 병합하는 경우와 같이 빌드에 전체 리포지토리 기록이 필요하다고 가정해 보겠습니다. 두 경우 모두 Bamboo가 변경 사항을 리포지토리로 다시 푸시해야 합니다.
Git을 사용하면 전체 기록 없이 간단한 파일 변경 사항(예: 버전 번호 업데이트)을 푸시할 수 있습니다. 하지만 Git은 되돌아보고 두 브랜치의 공통적인 상위 항목을 찾아야 하기 때문에 병합하려면 여전히 리포지토리의 기록이 필요합니다. 빌드에서 부분 복제를 사용하면 문제가 될 것입니다. 이 내용은 3번 팁으로 이어집니다.
3: 빌드 에이전트에 리포지토리를 캐싱
이렇게 하면 복제 작업도 훨씬 빨라지고 Bamboo는 실제로 이 작업을 기본으로 수행합니다.
참고로 리포지토리 캐싱은 빌드 간에 지속되는 에이전트를 사용하는 경우에만 도움이 됩니다. 빌드가 실행될 때마다 EC2나 다른 클라우드 제공자에서 빌드 에이전트를 만들고 해체하는 경우 비어 있는 빌드 디렉터리로 작업하고 어차피 매번 리포지토리의 전체 사본을 가져와야 하므로 리포지토리 캐싱은 중요하지 않습니다.
영구적인 에이전트와 탄력적인 에이전트로 나눠진 부분 복제 및 리포지토리 캐싱은 흥미로운 요인입니다. 전략 수립에 도움이 되는 작은 매트릭스는 다음과 같습니다.
4: 트리거를 현명하게 선택
활성화된 모든 브랜치에 CI를 실행하는 것이 좋은 생각이라는 점은 (거의) 말할 필요도 없습니다. 하지만 모든 커밋에 대해 모든 브랜치에서 모든 빌드를 실행하는 것이 좋은 생각입니까? 아마 아닐 것입니다. 이유는 다음과 같습니다.
Atlassian을 예로 들어 보겠습니다. Atlassian에는 800명 이상의 개발자가 각각 하루에 몇 번씩 리포지토리에 변경을 푸시하며 대부분은 기능 브랜치에 푸시합니다. 빌드가 아주 많습니다. 빌드 에이전트를 즉시 무한하게 확장하지 않으면 대기 시간이 너무 오래 걸립니다.
내부 Bamboo 서버 하나에 935개의 서로 다른 빌드 계획이 있습니다. 이 서버에 141개의 빌드 에이전트를 연결하고 아티팩트 통과나 테스트 병렬화와 같은 모범 사례를 사용하여 각 빌드를 최대한 효율적으로 만들었습니다. 그런데도 푸시할 때마다 빌드 작업으로 인해 작업이 막히고 있었습니다.
다른 100명 이상의 에이전트와 함께 단순히 Bamboo 인스턴스를 또 하나 설정하는 대신 한 발짝 물러나서 정말 필요한 작업인지 물었습니다. 그 답은 필요하지 않다는 것이었습니다.
그래서 개발자에게 브랜치 빌드를 항상 자동으로 트리거하는 대신 푸시 버튼으로 만들 수 있는 선택지를 제공했습니다. 엄격한 테스트와 리소스 절약의 균형을 맞출 수 있는 좋은 방법이며 브랜치는 대부분의 변경 활동이 일어나는 곳이므로 비용 절감을 위한 좋은 기회가 있었습니다.
많은 개발자는 푸시 버튼 빌드가 제공하는 추가적인 제어 기능을 마음에 들어 하고 워크플로에 자연스럽게 들어맞는다고 느낍니다. 빌드를 언제 실행할지 고민하지 않고 자동 트리거를 사용하는 것을 선호하는 개발자도 있습니다. 어느 접근 방식이든 가능합니다. 중요한 것은 처음부터 브랜치를 테스트하고 업스트림을 병합하기 전에 깨끗한 빌드를 가지고 있는지 확인하는 것입니다.
하지만 메인 및 안정적인 릴리스 브랜치와 같은 중요 브랜치는 다른 문제입니다. 그러한 브랜치에서의 빌드는 리포지토리에 변경 사항을 폴링하거나 Bitbucket에서 Bamboochet으로 푸시 알림을 보내면 자동으로 트리거됩니다. Atlassian은 진행 중인 모든 작업에 개발 브랜치를 사용하기 때문에 메인에 들어오는 유일한 커밋은 (이론적으로) 개발 브랜치가 병합되는 것입니다. 또한 이 브랜치는 우리가 릴리스하고 개발 브랜치에서 나온 코드 줄입니다. 따라서 병합할 때마다 적시에 테스트 결과를 얻는 것이 정말 중요합니다.
5: 폴링은 그만, 후크 사용 시작
몇 분에 한 번씩 리포지토리를 폴링하여 변경 사항을 찾는 일은 Bamboo의 경우 비용이 적게 드는 작업입니다. 하지만 리포지토리가 수십 개 포함된 브랜치 수천 개를 대상으로 빌드 수백 개를 확장하면 비용은 급격하게 올라갑니다. 폴링으로 인해 Bamboo에 세금을 부과하는 대신 변경이 푸시되어 빌드해야 할 때 Bitbucket을 호출할 수 있습니다.
보통 리포지토리에 후크를 추가하는 방식으로 처리되는데 그 과정에서 Bitbucket 및 Bamboo 간 통합이 모든 내부 설정을 자동으로 처리합니다. 백엔드에 연결되면 리포지토리 기반 빌드가 Just Work™를 즉시 트리거합니다. 후크나 특수 구성은 필요하지 않습니다.
도구와 상관없이 리포지토리 기반 트리거는 타겟 브랜치가 비활성 상태가 되면 자동으로 사라지는 장점이 있습니다. 즉, 버려진 수백 개의 브랜치를 폴링하는 데 CI 시스템의 CPU 사이클을 낭비하거나 브랜치 빌드를 수동으로 비활성화하는 데 시간을 낭비하지 않습니다. (그래도 폴링을 선호하는 경우 X일 동안 활동이 없을 때 브랜치를 무시하도록 Bamboo를 쉽게 설정할 수 있다는 점은 주목할 만합니다.)
CI와 함께 Git을 사용하는 것의 핵심...
이 문서 공유
다음 주제
여러분께 도움을 드릴 자료를 추천합니다.
이러한 리소스에 책갈피를 지정하여 DevOps 팀의 유형에 대해 알아보거나 Atlassian에서 DevOps에 대한 지속적인 업데이트를 확인하세요.