React Native 배포 자동화

Kim Ethan·2023년 6월 1일
0

앱의 다음 업데이트 출시를 위해 한창 바쁘게 개발을 하던 중에 팀원한테 배포를 자동화해서 시간을 줄여보는 게 어떻겠냐고 제안을 받았다.

지금까지는 개발이 끝나면 iOS, Android 각각 수동으로 빌드를 하고 QA 팀에서 테스트 앱을 다운로드할 수 있도록 firebase에 배포를 했다. 기획이나 디자인이 변경되는 상황이 매우 많기 때문에 개발이 완전히 끝나기 전에도 중간 점검을 위해 배포를 하는 일이 많았다. 이 과정을 매번 수동으로 진행하다 보니까 흐름이 끊기기도 하고 평균적으로 OS마다 20분 정도 소요되었으니 시간도 많이 부족하다고 느껴졌다.

Fastlane

공식 홈페이지 설명에 따르면, Fastlane은 Android 및 iOS 배포를 단순화하기 위한 오픈 소스 플랫폼이다. Fastlane을 사용하면 development 및 release 워크플로우의 모든 측면을 자동화할 수 있다. 이 포스팅에서는 개발용 테스트 앱 배포에 대해서만 다룬다.

Fastlane은 이미 사용 중이었지만, 빌드 파일을 firebase에 직접 업로드를 하느냐 하지 않느냐의 차이였고 마찬가지로 Fastlane이 실행되는 중에는 개발을 할 수 없었기에 단축되는 시간도 체감상 크게 느껴지지 않았다. 이러한 불편함을 해소하기 위해서는 개발과 완전히 분리되어 배포를 자동화할 필요가 있다고 판단했다. 이를 위해 Fastlane과 Github Actions을 조합해서 사용하게 되었다.

Fastlane은 레거시 코드를 다 뒤엎고 단계별 lane을 새롭게 개발했다. 우선, 팀원마다 iOS Provisioning Profile 인증서를 별도로 발급해서 사용하고 있었는데 팀 전체에서 certificates와 profiles를 쉽게 동기화 할 수 있도록 match를 사용하기로 했다. fastfile은 android와 ios 각각 존재하고 사용법에 약간의 차이가 있다. 아래는 ios fastfile 예시 코드이다.

default_platform(:ios)

platform :ios do
  desc
  lane :firebase do
    match(
      type: "development",
      git_url: "{git 저장소 주소}",
      storage_mode: "git",
      readonly: true,
    )
    clear_derived_data

    latest_release = firebase_app_distribution_get_latest_release(
      app: '{firebase 앱 id}',
      firebase_cli_token: "{firebase 인증용 토큰}",
    )
    increment_build_number({build_number: latest_release[:buildVersion].to_i+1})

    build_app(
      workspace: "{프로젝트 이름}.xcworkspace",
      scheme: "{앱 scheme}",
      silent: true,
      clean: true,
      output_directory: ".",
      output_name: "{빌드파일이름}.ipa",
      export_team_id: CredentialsManager::AppfileConfig.try_fetch_value(:team_id),
      export_options: {
        method: 'development',
        provisioningProfiles: {
          "bundle id": "com.alphabridge.tangopick",
        }
      }
    )

    firebase_app_distribution(
      app: "1:32734331599:ios:f6d9fa7cf137a301cd6dba",
      testers: "ap.alphabridge@gmail.com",
      ipa_path: "{빌드파일경로}",
      firebase_cli_token: "{firebase 인증용 토큰}",
      groups: "{테스터 그룹}",
      release_notes: "{출시 노트}",
    )
  end
end

match는 Github Repository에 공용으로 사용할 인증서를 저장하고, 명령어를 통해 간단하게 인증서 갱신 및 공유가 가능하다. 배포를 할 때는 match를 사용해서 인증이 가능하기 때문에 프로젝트에 인증서 파일을 포함하지 않아도 된다.

clear_derived_data는 예기치 않은 문제의 발생을 최소화하기 위해 사용한다. clean을 하는 과정이 필수는 아니지만 derived data를 지우면 오래된 빌드 아티팩트로 인한 빌드 관련 문제를 해결하는 데 도움이 될 수 있고, 프로젝트에 참여하는 모든 사람이 동일한 환경에서 시작할 수 있다.

build_app은 lane에 정의된 옵션에 따라 앱을 빌드한다. lane 중에서 export_team_id는 fastlane의 모듈인 CredentialsManager를 통해서 프로젝트 내에 Fastfile과 함께 생성된 Appfile에 있는 tead_id 값을 가져오려고 시도한다.

마지막으로 firebase_app_distribution는 빌드가 끝나면 앱을 firebase를 통해서 테스터에게 배포하는 역할을 한다. 테스터 그룹을 지정할 수 있고, 출시 노트를 작성하여 해당 빌드에 대한 간략한 설명이 가능하다.

GitHub Actions

GitHub Actions는 GitHub에서 제공하는 워크플로우 자동화 및 CI/CD 플랫폼이다. 다양한 작업을 자동화하고 GitHub 리포지토리에서 직접 코드를 빌드 및 배포할 수 있다.

Github Actions는 워크플로우를 실행할 runner가 필요한데, github-hosted runner와 self-hosted runner가 있다. github-hosted runner는 github에서 리소스를 빌려 작업을 수행하기 때문에 유료이다. 팀에 사용하지 않는 PC가 하나 있어서 self-hosted runner로 사용했다.

특정 브랜치에 push 또는 pull request 이벤트가 생기면, fastlane을 실행해 firabase에 테스트 앱을 배포하는 워크플로우를 만들었다. 브랜치는 하나만 지정할 수도 있고, 여러 개 혹은 모든 브랜치를 포함할 수 있다. 변경사항이 생길 때마다 매번 배포하는 것은 비효율적이므로, 이벤트의 발생을 내가 컨트롤할 수 있도록 commit message를 확인하는 조건을 포함했다.

결과적으로, fastlane만 실행했을 때 배포에 소요되는 평균 시간이 OS별로 20분에서 5분으로 단축되었고 프로젝트 내에 모듈의 업데이트나 추가 등 변경사항이 생겼을 때 발생할 수 있는 문제를 방지하기 위해 node_modules와 pod을 clean하는 워크플로우가 추가되었다. 워크플로우가 실행되는데 소요되는 총 시간은 OS별 15분이지만 자동으로 배포가 이루어지고 총 배포 시간이 10분 줄어들었다는 것 만으로도 충분히 많은 성과가 있었다고 생각한다.

개선점

node_modules를 clean하는 워크플로우가 OS별로 총 2번 실행되는데, 워크플로우가 실행되는 순서를 제어할 수 있다면 중복되는 워크플로우를 줄일 수 있기 때문에 그만큼 시간을 단축할 수 있을 것 같다.

++

  • 브랜치가 새롭게 생성된 경우 runner가 원격 브랜치에 접근하지 못하는 경우가 있어서 git remote를 갱신해 주는 워크플로우를 추가했다.
  • 워크플로우가 명시되어 있는 각 yml파일은 독립적이고 github actions는 이를 병렬로 처리하기 때문에 순서를 제어할 순 없다고 판단해서 하나의 yml파일로 워크플로우를 통합했다. 이 방법은 OS 둘 중 하나만 빌드에 문제가 생겨도 둘 다 배포가 되지 않기 때문에 워크플로우를 조금 더 보완할 필요가 있을 것 같다.
profile
프론트엔드 엔지니어

0개의 댓글