AWS codebuild + codecov 로 저렴하게 android CI 구축하기

회사에서 CI 도입을 위해서 aws ec2 (m4.large, 2 vcpu, 8gb ram) 에 jenkins 를 설치해서 사용하고 있었다.

사용하면서 생기는 문제는

  1. ram 이 8gb 인데도 android test build 를 동시에 3개 이상하면 메모리가 부족하다고 뜨면서 gradle daemon 이 죽어버린다.
  2. 위의 daemon 이 죽는 걸 막으려고 메모리 옵션을 주면 빌드가 오래 걸리거나 빌드 도중 죽는다.
  3. 메모리를 안줄여도 여러개의 빌드가 동시에 돌아가니 debug 빌드만 하는데도 시간이 8분 이상 걸린다.

test 도입을 위해 ci 를 설정했는데, 오히려 방해가 되는 요소가 되어버려서 개선을 진행했다.

더 좋은 서버를 쓰면

m4.large 를 온디맨드로 쓰면 한 달에 약 10만원(서울 리전) 정도가 나가는데 여기서 더 좋은 서버를 올리면 그냥 travis 를 결제하는게 더 싸다 (2 개의 동시 빌드에 $129). 그리고 CI 의 특성 상 업무시간 (10–8) 에서만 주로 사용되고 그 외의 시간에서는 사용이 되지 않아서 aws codebuild 를 사용하기로 했다.

가격

Codebuild 는 2vcpu, 3gb 인스턴스를 제공한다 (link). 가격은 build 에 소요된 시간만큼 돈을 받는다($0.005 / m). 빌드 한번에 6분 정도 걸린다고 했을 때, 1000번 빌드를 해도 $30 + a(s3 버킷이나 ECR 비용) 정도밖에 안나온다.

여기다 coverage report 를 위해 codecov 까지 연동하면 많이 잡아도 $50 정도면 충분하다.

TOC

  1. docker image build
  2. ECR 에 프로젝트 만들고 docker image push
  3. Codebuild 에서 프로젝트 만들고 github 과 연동하고 ECR 이미지로 빌드하도록 설정 및 codebuild.yml 추가하기
  4. jacoco — codecov 로 test coverage report 추가
  5. 정리

1. Android build 를 위한 Docker image 생성

일단 build 가능한 이미지를 만든다.

docker build -t android-ci ./
docker run — rm -it android-ci
docker iamges

docker image 빌드도 완료되었고, 해당 docker image 안에서 정상적으로 gradle task 가 실행되는 걸 확인했으면 이제 ECR 에 등록을 하면 된다.

2. ECR 에 docker image upload

docker hub 에는 private image 한개를 공짜로 올릴 수 있다. docker hub 를 쓰면 좋은 점은 docker image 를 {user_name}/{image_name}:{version} 형식으로 간단하게 쓸 수 있다. codebuild 에서도 외부에 올라간 이미지들을 쓸 수는 있지만 빌드이미지 크기가 600mb 정도라 이미지를 다운받고 하는데 시간이 걸리고 해서 ECR 에 이미지를 등록하기로 했다.

앞서 만든 이미지를 ECR 에 등록하기 위해서는 aws-cli 툴이 필요하다.

aws ecr get-login — no-include-email — region ap-northeast-2

위 명령어는 ~/.aws/credentials~/.aws/config 파일이 있어야 정상적으로 docker login key 를 가져온다.

aws ecr get-login 을 하면

docker login -u AWS -p {very_long_access_token} https://ecr_url

로 docker login 을 할 수 있는 명령어가 출력이 된다.

그대로 복사해서 붙여넣으면

Login Succeeded 가 출력되고 ECR 에 docker image 를 push 가능한 상태가 된다.

docker tag android-ci:latest ecr.amazonaws.com/android-ci:latest

명령어로 방금 빌드한 이미지에 tagging 을 하고

docker push ecr.amazonaws.com/ci-docker-image:latest

로 ECR 에 push 한다.

정상적으로 ECR 프로젝트에 새로 추가한 image 있어야 한다.

3. Codebuild 설정하기

codebuild 서비스로 가서 프로젝트를 구성한다.

소스: 빌드 대상

공급자는 github 로 설정했다.

환경: 빌드 방법

  • 환경 이미지 — 도커이미지 지정
  • 환경 유형 — linux
  • 사용자 지정 이미지 유형 — Amazon ECR
  • Amazon ECR 레포지토리 — android-ci
  • Amazon ECR 이미지 — latest
  • 권한이 있음 — codebuild 로 다른 도커를 빌드하지 않음으로 체크 해제
  • 빌드 사양 — 소스 코드 루트 디렉터리에서 buildspec.yml 사용

캐시

S3 에 gradle library 들을 캐싱해서 두번째 빌드부터 라이브러리를 다운 받지 않고 빠르게 빌드하도록 설정한다. S3 에 cache 용 버킷을 만들거나 기존에 사용하던 버킷이 있다면 적절하게 추가한다.

서비스 역할, VPC

등은 기존 default 설정 그대로 놔둔다.

고급 설정

제한 시간을 설정해서 빌드가 비정상적으로 오래 걸린다면 실패로 떨어트리는게 좋다. 제한 시간이 없으면 실패도 안하면서 계속 돌아서 금방 무료크레딧을 다 써버린다.

buildspec.yml 파일을 프로젝트 root 에 추가

codebuild 프로젝트가 생성되면 빌드할 project 에도 codebuild.yml 로 codebuild 가 수행 할 명령들을 작성하면 된다.

로 파일을 추가한다.

지금은 unittest 를 돌리고, debug apk 를 만들기만 하므로 build pahse 에만 명령어를 작성했다.

cache 의 경우 매번 library 들을 다운받으면 시간이 오래 걸리기 때문에 gradle 디렉토리를 캐싱한다.

buildspec.yml 을 프로젝트에 추가하면 자동으로 codebuild 에서 빌드를 시작한다. 맨 처음 빌드는 시작하면 ECR 에서 image 를 가져오는 권한이 없다고 실패하는데 ECR 레포지토리에서 CodeBuildAccess 권한을 추가 해줘야한다. 이 페이지 에서 샘플 실행 — b 단계부터 따라하면 된다.

설정을 정확하게 했으면 빌드가 시작되고

결과가 이렇게 뜬다.

4. Jacoco 와 codecov 연동하기

jacoco 는 자바 테스트의 coverage 를 보여주는 툴이다. ide 에서도 Run test with coverage 버튼을 통해서 test 의 커버리지를 볼수 있다.

jacoco 설정

jacoco plugin 을 추가하고 coverage report 를 어떤 포맷으로 export 할지, test 가 끝나면 jacoco report 를 생성하도록 하면 된다.

그 다음으로 생성된 test coverage report 를 coverage 를 보여주는 서비스에 올려주면 되는데 jenkins 의 기본 coverage report 는 보기도 힘들고, 정확이 어떤 클래스에 커버리지가 낮은지, 코드의 복잡도는 어떤지 이런 부분을 제대로 보기가 힘들다.

Codecov

codecov.io dash board

일단 sunburst 차트로 네비게이션이 가능해서 coverage 가 낮은 class 들을 쉽게 찾고 테스트를 추가할 수 있는 점이 좋다.

그리고 github comment 에서 자동으로 해당 pr 의 커버리지를 보여준다.

codecov pr comment

github marketplace 에서 쉽게 연동이 가능하다. private repository 는 $6/month 로 갯수 제한없이 사용이 가능하다.

buildspec.yml 에 codecov 추가

codebuild 에서 마지막 post build phase 에서 jacoco 로 만든 coverage report 를 codecov 쪽에 업로드를 해줘야 한다.

post build 에서 codecov 스크립트를 다운받고 jacoco report 를 업로드 하는 명령어를 추가했다.

cache 쪽에서도 codecov script 를 캐시에 추가했다.

5. 정리

기존에 있던 jenkins 기반 CI 환경에서 가장 눈에 띄게 좋아진건 빌드의 실패(= 코드의 문제가 아니라 인스턴스의 문제)가 없어졌다.

기존에는 특정 빌드가 시스템 자원을 많이 쓴다고하면 그 뒤로 들어오는 빌드들도 같이 실패를 하는 경우가 많았었는데, 그런 케이스가 없어졌다.

가격적인 면에서도 매달 100분씩 무료 크레딧이 들어오는데다가 m4.large 보다는 훨씬 저렴하게 운영이 가능하다.

다음 작업은 codebuild 를 code pipeline 과 연동시켜 내부 test apk 배포 자동화를 할 예정이다.