클라우드 Mac CI의 CocoaPods 재현 가능한 설치

CI/CD ·약 7분 읽기

클라우드 Mac CI의 CocoaPods 재현 가능한 설치

동일한 커밋이 개발 머신에서는 문제없이 빌드되지만 클라우드 Mac의 새 작업에서는 갑자기 다른 의존성을 해석하거나, pod install 실행 후 Podfile.lock을 조용히 다시 쓰는 경우가 있습니다. 이런 문제는 대개 Xcode 자체가 아니라 CocoaPods 도구 버전, 캐시, 설치 모드를 빌드 입력으로 관리하지 않아 발생합니다. 올바른 목표는 “매번 설치를 완료하는 것”이 아니라, 동일한 입력 집합에서 반드시 동일한 의존성 그래프를 얻고 변경이 감지되면 즉시 중단하는 것입니다.

재현 가능한 설치의 입력 정의

CocoaPods의 결과에는 최소한 다섯 가지 입력이 영향을 줍니다. Podfile, Podfile.lock, CocoaPods 버전, Ruby 및 Bundler 환경, 로컬 개발 Pod가 가리키는 소스 코드입니다. 잠금 파일만 저장소에 커밋하고 실행기가 임의의 CocoaPods 버전을 사용하도록 두면, 프로젝트 생성 형식이나 설치 동작에 여전히 차이가 생길 수 있습니다.

저장소에는 .ruby-version, Gemfile, Gemfile.lock, Podfile, Podfile.lock을 커밋해야 합니다. Gemfile에서 CocoaPods 버전을 명시하고, 머신에 전역으로 설치된 최신 버전에 의존하지 마십시오.

source ENV.fetch("BUNDLE_GEM_SOURCE")

ruby "3.3.4"
gem "cocoapods", "1.15.2"

CI 진입점에서는 항상 bundle exec pod를 사용합니다. 이렇게 하면 로그에 표시되는 버전이 잠긴 환경과 일치하며, 특정 대화형 Shell이 우연히 전역 명령을 먼저 찾는 상황도 방지할 수 있습니다.

Podfile.lock은 의존성 해석 결과를 잠글 뿐, 해석과 프로젝트 생성을 수행하는 CocoaPods 프로그램까지 잠가 주지는 않습니다.

설치 명령을 엄격 모드로 전환

일상적인 빌드에서는 pod update를 실행하면 안 됩니다. 이 명령은 버전 제약 범위 안에서 의존성을 다시 해석하므로 사람이 직접 시작하는 업그레이드 작업에는 적합하지만, 기존 커밋을 검증하는 데는 적합하지 않습니다. CI에서는 다음과 같은 설치 진입점을 사용할 수 있습니다.

#!/bin/bash
set -euo pipefail

export LANG=en_US.UTF-8
export COCOAPODS_DISABLE_STATS=true
export CP_HOME_DIR="${RUNNER_TEMP}/cocoapods-home"

bundle config set path "${RUNNER_TEMP}/bundle"
bundle check || bundle install
bundle exec pod install --deployment --clean-install
git diff --exit-code -- Podfile.lock

--deployment는 잠금 파일을 변경해야 할 때 실패하며, --clean-install은 이전 설치 상태가 문제를 가릴 가능성을 줄입니다. 마지막 git diff는 두 번째 차단 장치입니다. 설치 과정에서 어떤 스크립트가 잠금 파일을 다시 썼더라도 작업이 빌드 단계로 계속 진행되어서는 안 됩니다.

저장소에 여러 워크스페이스가 있다면 각 워크스페이스에 별도의 설치 디렉터리와 로그 파일을 사용해야 합니다. 병렬 작업에서 동일한 Pods 디렉터리를 공유하지 마십시오.

캐시는 격리하되 무조건 비활성화하지 않기

캐시 자체가 문제인 것은 아닙니다. 경계가 불분명한 것이 문제입니다. 클라우드 Mac에서 흔한 오염 경로는 여러 저장소가 CocoaPods 다운로드 캐시를 공유하거나, 두 작업이 동일한 Bundler 디렉터리를 동시에 읽고 쓰는 경우입니다. “잠금 파일 해시 + 도구 버전”으로 캐시 키를 구성하고, 설치가 성공한 뒤에만 캐시에 쓰는 방식을 권장합니다.

캐시 대상 권장 캐시 키 무효화 조건
Bundler 설치 디렉터리 Gemfile.lock 해시 + Ruby 버전 입력 중 하나라도 변경
CocoaPods 다운로드 캐시 Podfile.lock 해시 + CocoaPods 버전 잠금 파일 또는 도구 변경
Pods 디렉터리 Podfile.lock 해시 + 프로젝트 구성 해시 Podfile, 스크립트 또는 구성 변경

Pods/Manifest.lock을 캐시한 뒤 새 설치 결과 위에 덮어쓰지 마십시오. 이 파일은 현재 샌드박스에 실제로 설치된 상태를 기록하므로 이번 설치에서 생성되어야 합니다. 캐시 복원 후 이상이 발생하면 먼저 격리된 디렉터리에서 캐시 없이 설치해 보십시오. 캐시를 사용하지 않은 결과가 정상일 때만 문제의 원인을 캐시로 판단할 수 있습니다.

빌드 전에 의존성 그래프 검증

설치가 성공했다고 해서 의존성 그래프가 올바른 것은 아닙니다. 최소한 Podfile.lock과 Pods/Manifest.lock이 일치하는지 확인하고, 커밋되지 않은 변경이 없는지도 검증해야 합니다.

test -f Podfile.lock
test -f Pods/Manifest.lock

cmp -s Podfile.lock Pods/Manifest.lock || {
  echo "CocoaPods sandbox differs from Podfile.lock" >&2
  exit 1
}

git status --porcelain -- Podfile Podfile.lock Gemfile Gemfile.lock

마지막 명령에서 출력이 발생하면 경고만 표시할 것이 아니라 작업을 실패 처리해야 합니다. :path를 사용하는 로컬 Pod의 경우 대상 디렉터리의 커밋 ID나 콘텐츠 해시도 별도로 기록해야 합니다. 그렇지 않으면 잠금 파일이 그대로인 상태에서도 디렉터리 내용이 달라질 수 있으므로 재현 가능성을 확보할 수 없습니다.

업그레이드 전용 경로 마련

의존성 업그레이드 작업에서는 특정 대상을 지정한 pod update SomePod를 실행할 수 있지만, 세 가지 차이를 반드시 출력해야 합니다. 잠금 파일의 버전 변경, SPEC CHECKSUMS 변경, 새로 추가되거나 제거된 전이 의존성입니다. 업그레이드 커밋에는 의존성 변경만 포함하고 비즈니스 코드를 함께 섞지 마십시오. 그래야 롤백할 때 이전 잠금 파일을 그대로 복원할 수 있습니다.

실패 현장을 보존하고 순서대로 진단

실패 직후 모든 캐시를 삭제하지 마십시오. 먼저 CocoaPods 버전, Ruby 버전, 잠금 파일 해시, 설치 로그, git status를 보존한 다음 어느 계층의 문제인지 판단해야 합니다.

  1. bundle check가 실패하면 먼저 Ruby와 Gemfile.lock의 플랫폼을 확인합니다.
  2. 엄격 설치에서 잠금 파일 변경을 요구한다면 누군가 Podfile을 수정하고 잠금 파일을 커밋하지 않았는지 확인합니다.
  3. 캐시를 복원한 작업에서만 실패한다면 별도의 디렉터리에서 캐시 없이 설치하고 결과를 비교합니다.
  4. Manifest.lock이 일치하지 않는다면 설치가 중단되었는지, 또는 여러 작업이 Pods를 공유하는지 확인합니다.
  5. 로컬 Pod의 내용이 변동한다면 소스 디렉터리에 커밋 ID 또는 해시 검증을 추가합니다.

안정적인 CocoaPods 프로세스는 결국 지루할 정도로 예측 가능해야 합니다. 입력이 바뀌지 않으면 설치 결과도 바뀌지 않고, 입력이 변경되면 그 차이가 코드 리뷰에 포함되며, 캐시가 손상되더라도 속도에만 영향을 줄 뿐 의존성 그래프는 달라지지 않아야 합니다. 이러한 검사를 Xcode 빌드 전에 배치하면 수십 분 뒤에 모호한 오류를 마주하는 대신 대개 수십 초 안에 작업을 실패시킬 수 있습니다.

자주 묻는 질문

CI에서는 pod install과 pod update 중 무엇을 사용해야 하나요?

일반 CI 작업은 pod install --deployment를 사용합니다. pod update는 별도 의존성 갱신 작업에서 실행하고 Podfile.lock 변경을 검토해야 합니다.

Podfile.lock이 있는데도 결과가 달라지는 이유는 무엇인가요?

Ruby 또는 CocoaPods 버전 차이, 변경 가능한 로컬 Pod, 손상된 캐시, 설치 전에 Podfile을 수정하는 스크립트가 대표적인 원인입니다.

Pods 디렉터리를 Git에 커밋해야 하나요?

일반적으로 필요하지 않습니다. Podfile, Podfile.lock, Gemfile, Gemfile.lock을 커밋하고 CI가 고정된 입력에서 의존성을 복원하도록 구성합니다.

전용 물리 노드

작업 기간에 맞춰 LemonVM 클라우드 Mac 선택

Lemon M4와 Lemon M4 Pro는 싱가포르, 도쿄, 서울, 홍콩, 미국 서부에 제공되며 일간, 주간, 월간, 분기별 결제를 지원합니다.

클라우드 Mac 지금 대여