GitLab Runner의 macOS 지원 문서에서 상주 방식은 시스템 데몬이 아니라 사용자 모드 LaunchAgent로 명시되어 있습니다. 즉, Runner가 GitLab 화면에 온라인으로 보인다는 사실만으로는 운영 배포가 끝난 것이 아닙니다. macOS GitLab Runner 배포는 전용 일반 계정, Shell executor, 사용자 세션, Xcode 도구 체인, 서명 자산, 재시작 복구를 모두 검증한 뒤 완료해야 합니다. (GitLab의 macOS 설치 방식)
이번 주에는 먼저 서명 없는 Xcode 빌드와 테스트를 통과시키십시오. 그다음 재시작 후 복구를 확인하고, 마지막에만 배포 인증서와 키체인을 연결하는 순서가 안전합니다.
01이 글이 필요한 개발자
수동으로 iOS 앱을 패키징하는 과정을 GitLab CI로 옮기려는 개발자라면 첫 번째 재현 가능한 파이프라인에 집중해야 합니다.
여러 운영 체제를 함께 관리하는 DevOps 엔지니어라면 Runner의 상주 방식, 권한 경계와 복구 절차를 확인해야 합니다. 장기간 켜 둘 실제 Mac이 없는 팀이라면 원격 Mac의 계정 구성, 도구 체인 설치와 유지 조건을 임대 전에 확인해야 합니다.
02배포 전에 작업 범위를 먼저 고정합니다
원격 Mac은 다음 작업에서 의미가 있습니다.
- Xcode와 Apple SDK가 필요한 iOS 또는 macOS 빌드
- iOS Simulator 또는 실제 기기 대상 테스트
- Apple 서명 인증서와 프로비저닝 프로파일을 사용하는 패키징
- macOS에서만 실행되는 도구를 포함한 지속적 통합 작업
반대로 일반적인 서버 빌드, 리눅스 컨테이너 작업과 순수한 백엔드 테스트라면 Mac Runner가 필요하지 않을 수 있습니다. 이 구분을 하지 않으면 비싼 macOS 노드에서 처리할 필요가 없는 작업까지 실행하게 됩니다.
또 하나의 기준은 코드 신뢰도입니다. Shell executor는 작업을 호스트의 셸에서 직접 실행합니다. GitLab은 이 방식이 다른 프로젝트의 코드나 Runner 사용자의 권한에 접근할 수 있어 신뢰하는 코드에만 사용해야 한다고 설명합니다. (Shell executor의 보안 경계)
프로젝트 범위별 선택
| 선택 범위 | 적합한 상황 | 주의할 점 |
|---|---|---|
| 프로젝트 Runner | 하나의 iOS 저장소만 처리할 때 | 다른 프로젝트와 작업 디렉터리를 공유하지 않도록 구성합니다 |
| 그룹 Runner | 같은 조직의 여러 앱이 공통 도구를 사용할 때 | 그룹 내 모든 저장소의 코드 신뢰도를 확인해야 합니다 |
| 공유 또는 인스턴스 Runner | 여러 팀이 공통으로 사용할 때 | Shell executor와 서명 키체인을 함께 쓰기에는 위험도가 높습니다 |
처음 배포하는 팀은 프로젝트 Runner로 시작하는 편이 좋습니다. 실제 작업이 안정된 뒤 그룹 범위로 넓히십시오. 공개 저장소, 외부 기여자가 수정할 수 있는 파이프라인 또는 검토되지 않은 분기에는 서명 자산이 있는 Runner를 연결하지 않는 것이 원칙입니다.
03첫 번째 단계는 전용 계정과 아키텍처 확인입니다
macOS GitLab Runner 배포에서 가장 먼저 만들 계정은 개인 개발 계정이 아닙니다. CI 작업만 실행하는 전용 일반 사용자 계정을 준비하십시오. 관리자 권한을 계속 부여하지 말고, 필요한 설치 작업만 별도로 승인합니다.
이렇게 분리하면 다음 문제가 줄어듭니다.
- 개인 SSH 키와 CI 작업이 같은 홈 디렉터리에 놓이는 문제
- 개발자의 로그인 키체인과 배포 키체인이 섞이는 문제
- 빌드 스크립트가 개인 설정 파일을 읽는 문제
- 작업 실패 후 남은 파일이 다음 프로젝트에 노출되는 문제
Apple Silicon인지 Intel인지도 확인해야 합니다. GitLab은 macOS에서 두 아키텍처용 Runner 설치 방식을 따로 제공합니다. Apple Silicon 장비에서는 해당 아키텍처의 실행 파일을 선택하고, 설치 후 다음 명령으로 기본 상태를 확인하십시오.
uname -m
whoami
echo "$SHELL"
gitlab-runner --version
GitLab의 현재 등록 방식에서는 Runner 인증 토큰을 사용합니다. 인증 토큰은 일반적으로 glrt- 접두사를 가지며, 토큰은 저장소에 넣지 않아야 합니다. 새 Runner는 GitLab 화면에서 프로젝트나 그룹 범위를 먼저 만들고, 화면에서 발급한 인증 정보를 사용하십시오. 예전 등록 토큰 방식은 환경에 따라 비활성화될 수 있습니다. (Runner 등록 절차)
gitlab-runner register \
--url "https://gitlab.example.com/" \
--token "$RUNNER_AUTHENTICATION_TOKEN"
등록 화면에서는 이름을 ios-macos-arm64-prod처럼 역할과 아키텍처가 드러나게 정하십시오. 작업 태그는 예를 들어 macos, xcode, ios-signing처럼 설정할 수 있습니다. GitLab 작업은 태그를 기준으로 실행할 Runner를 선택하므로, .gitlab-ci.yml에서도 같은 태그를 명시해야 합니다.
Shell executor와 사용자 세션을 함께 구성합니다
Xcode와 Simulator를 사용하는 macOS 작업에는 Shell executor가 자연스럽습니다. 컨테이너 안에 macOS 도구 체인을 넣는 방식이 아니기 때문입니다. 대신 격리 수준은 낮습니다. 신뢰할 수 있는 프로젝트만 연결하고, 여러 프로젝트가 하나의 호스트에서 작업 디렉터리와 캐시를 공유하지 않도록 관리하십시오.
GitLab Runner의 macOS 설정 파일은 기본적으로 다음 경로에 저장됩니다.
~/.gitlab-runner/config.toml
macOS에서는 Runner가 현재 로그인한 사용자 세션에서 실행됩니다. GitLab 문서에 따르면 LaunchAgent는 사용자가 로그인할 때 시작되고 로그아웃하면 멈추며, 키체인과 화면 세션에 접근할 수 있습니다. 반대로 시스템 수준 LaunchDaemon은 공식 지원 방식이 아니며 사용자 세션과 키체인 접근에 적합하지 않습니다. (macOS 서비스 모드)
GitLab Runner를 원격 Mac에서 장기간 실행하려면 무엇을 확인해야 합니까?
먼저 전용 계정으로 GUI 로그인을 완료한 뒤 Runner를 설치하고 서비스를 시작해야 합니다. SSH 접속만으로 설치하고 로그아웃하면, 화면에서는 Runner가 등록되어 있어도 실제 작업을 받을 사용자 세션이 사라질 수 있습니다.
cd ~
gitlab-runner install
gitlab-runner start
gitlab-runner verify
그다음 SSH 연결을 종료하고 GitLab의 Runner 상태를 확인하십시오. 네트워크를 잠시 끊었다가 복구하는 시험도 진행합니다. 마지막으로 Mac을 재시작합니다. 재시작 뒤 온라인 상태가 돌아오지 않으면 자동 로그인, 사용자 세션 유지, 원격 접속 방식과 보안 정책을 다시 검토해야 합니다.
자동 로그인은 편의성과 보안의 교환입니다. 장비가 통제된 데이터센터에 있고 물리 접근 위험을 별도로 관리한다면 검토할 수 있습니다. 반대로 물리 접근이 가능한 장소라면 자동 로그인을 무조건 활성화해서는 안 됩니다. 이때는 관리자가 재부팅 후 직접 세션을 복구하는 절차를 운영 문서에 남겨야 합니다.
| 상태 | 화면에서 보이는 것 | 실제 확인 방법 | 통과 기준 |
|---|---|---|---|
| 등록 완료 | Runner가 목록에 표시됨 | gitlab-runner verify 실행 |
GitLab 연결 성공 |
| 서비스 실행 | 온라인으로 표시됨 | 간단한 셸 작업 실행 | 작업 로그와 종료 코드 확인 |
| SSH 종료 | 계속 온라인처럼 보일 수 있음 | SSH 종료 후 새 작업 실행 | 작업이 실제로 시작됨 |
| 재시작 후 | 잠시 오프라인일 수 있음 | Mac 재부팅 후 상태 확인 | 수동 개입 없이 복구되거나 복구 절차가 명확함 |
| 키체인 접근 | 빌드는 실행됨 | 서명 없는 테스트와 서명 작업 분리 | 권한 오류 원인을 로그로 확인 |
Xcode 작업은 작은 파이프라인부터 시작합니다
Xcode 명령줄 도구에는 xcodebuild, simctl, devicectl, xcresulttool 등이 포함됩니다. Apple은 터미널에서 이 명령을 사용하려면 Xcode를 설치하고 활성 개발자 디렉터리로 지정해야 한다고 설명합니다. (Xcode 명령줄 도구)
먼저 Runner 사용자로 다음 상태를 확인하십시오.
xcode-select -p
xcodebuild -version
xcrun simctl list devices
활성 개발자 디렉터리가 잘못되었다면 운영 중인 Xcode 경로에 맞춰 수정합니다.
sudo xcode-select --switch /Applications/Xcode.app
sudo xcodebuild -runFirstLaunch
명령 실행 여부만 보지 말고 실제 프로젝트로 검증해야 합니다. 첫 파이프라인은 다음 순서가 좋습니다.
- 저장소를 내려받습니다.
- 의존성을 복원합니다.
- 서명 없는 빌드를 실행합니다.
- 테스트와 결과 묶음을 저장합니다.
- 아카이브 작업을 별도 단계로 추가합니다.
- 마지막에 배포 서명을 연결합니다.
예시는 프로젝트에 맞게 수정해야 합니다.
stages:
- build
- test
- archive
variables:
LC_ALL: "en_US.UTF-8"
build_ios:
stage: build
tags:
- macos
- xcode
script:
- xcodebuild -workspace "App.xcworkspace" -scheme "App" -configuration Debug -sdk iphonesimulator build CODE_SIGNING_ALLOWED=NO
test_ios:
stage: test
tags:
- macos
- xcode
script:
- xcodebuild test -workspace "App.xcworkspace" -scheme "App" -destination 'platform=iOS Simulator,name=시뮬레이터이름'
artifacts:
when: always
paths:
- "*.xcresult"
archive_ios:
stage: archive
tags:
- macos
- xcode
script:
- xcodebuild archive -workspace "App.xcworkspace" -scheme "App" -archivePath "build/App.xcarchive"
artifacts:
when: always
paths:
- "build/"
GitLab CI에서 Xcode 빌드를 안정적으로 호출하려면 무엇이 필요합니까?
Runner 사용자의 Xcode 경로, 프로젝트 의존성, 시뮬레이터 상태, 작업 태그가 모두 일치해야 합니다. GitLab 화면에서 Runner가 온라인인지보다 xcodebuild의 종료 코드, 테스트 결과 묶음과 아카이브 산출물이 남았는지를 확인해야 합니다.
Apple은 아카이브와 배포 내보내기를 xcodebuild archive와 xcodebuild -exportArchive로 자동화할 수 있다고 설명합니다. 다만 프로젝트의 서명 방식과 내보내기 설정은 앱마다 다르므로, 처음부터 배포 작업을 한 단계에 섞지 마십시오. (Apple의 명령줄 배포 서명 안내)
인증서와 키체인은 마지막에 연결합니다
서명 없는 빌드가 통과한 뒤에만 인증서와 프로비저닝 프로파일을 추가하십시오. 테스트와 배포를 같은 작업으로 묶으면 실패 원인을 구분하기 어렵고, 외부 기여 코드가 민감한 자산에 접근할 가능성도 커집니다.
원격 Mac Runner의 서명 구성은 다음 원칙을 따릅니다.
- 전용 키체인을 사용합니다.
- 키체인 비밀번호와 인증서 파일을 저장소에 넣지 않습니다.
- GitLab 보호 변수와 보호 브랜치를 사용합니다.
- 배포 작업은 신뢰된 브랜치와 승인된 Runner에만 연결합니다.
- 작업 종료 후 임시 인증서, 프로파일과 내보내기 파일을 정리합니다.
- 로그에 비밀번호, 토큰, 인증서 내용을 출력하지 않습니다.
Apple의 인증서 문서에서는 개발 인증서와 배포 인증서의 용도가 다르다고 설명합니다. 프로비저닝 프로파일도 앱 ID, 인증서와 대상 기기 조건에 따라 만들어집니다. 따라서 개발 테스트에 필요한 자산과 App Store 배포용 자산을 같은 변수 묶음으로 관리하지 않는 편이 안전합니다. (Apple 인증서 개요) (개발 프로비저닝 프로파일)
원격 Mac Runner에서 인증서와 키체인은 어떻게 분리해야 합니까?
배포 작업에서만 보호 변수를 불러오고, 전용 사용자 키체인을 잠시 열어 작업하는 구조가 적합합니다. 실제 명령과 파일 형식은 사용하는 서명 방식에 따라 달라지므로, 인증서 설치가 끝났다고 바로 성공으로 판단하지 말고 codesign, security find-identity와 최종 아카이브 검증을 함께 실행해야 합니다.
외부 기여자가 수정할 수 있는 파이프라인은 배포 Runner에 태그를 지정하지 않도록 하십시오. Shell executor는 작업이 호스트 권한으로 실행되므로, 저장소 코드가 곧 호스트에서 실행되는 명령이 될 수 있습니다. (자체 관리 Runner 보안 문서)
07첫 주에는 실제 작업으로 운영 여부를 판정합니다
빈 저장소나 단순한 성공 스크립트는 Runner의 생산성을 증명하지 못합니다. 실제 앱의 빌드, 테스트, 아카이브와 실패 복구를 관찰해야 합니다.
다음 항목을 기록하십시오.
- 대기열에 머무는 시간
- 빌드 성공과 실패의 원인
- 작업 디렉터리와 캐시의 증가
- 동시에 실행되는 작업의 충돌 여부
- 네트워크 단절 후 재연결 상태
- 재시작 후 Runner와 키체인의 복구 상태
- 테스트 결과 묶음과 아카이브의 보존 여부
Runner 하나에 여러 작업을 동시에 허용하면 Xcode 프로젝트, Simulator와 키체인 상태가 충돌할 수 있습니다. concurrent 설정은 전체 동시 실행 수를 제한하지만, 숫자를 높인다고 실제 처리량이 선형으로 증가하지는 않습니다. 먼저 하나의 Runner에서 순차 실행을 안정화한 뒤, 독립된 노드로 확장하는 편이 예측하기 쉽습니다. (고급 Runner 설정)
다음 기준으로 계속 사용 여부를 결정하십시오.
- 계속 사용: 실제 프로젝트가 반복 실행되고, 재시작 후 복구되며, 서명 자산이 로그와 저장소에 노출되지 않습니다.
- 정리 후 재검증: 빌드는 되지만 캐시와 작업 디렉터리가 계속 쌓이거나 Simulator 상태가 누적됩니다.
- 노드 추가: 대기열이 길고 작업 간 충돌이 발생하지만 프로젝트와 서명 경계는 명확합니다.
- 수동 빌드로 회귀: 재시작 복구가 불안정하거나 외부 코드가 서명 자산이 있는 호스트에 접근할 가능성이 있습니다.
운영 책임도 나누어야 합니다. 개발 팀은 .gitlab-ci.yml, Xcode 프로젝트와 테스트 결과를 관리합니다. DevOps 팀은 Runner 버전, 계정 권한, 디스크 정리, 네트워크와 재시작 절차를 관리합니다. 배포 담당자는 인증서와 프로파일의 만료, 교체와 폐기를 책임져야 합니다.
원격 Mac을 선택할 때 확인할 조건
현재 Windows나 Linux 장비에서 SSH로 작업하고, 별도의 Linux 서버에서 대부분의 CI를 처리하는 방식은 일반 백엔드에는 효율적입니다. 그러나 Xcode와 Apple SDK 의존성은 해결하지 못합니다. 개인 Mac을 공유하면 로그인 세션, 키체인, 작업 충돌이 생기고, Mac mini를 직접 구매하면 사용하지 않는 기간에도 하드웨어와 유지 관리 비용이 남습니다.
반면 원격 Mac은 장기간 켜 둔 실제 macOS 환경을 제공하므로, 프로젝트별 Runner와 전용 계정을 구성하기 쉽습니다. 단, 네트워크 지연, 물리 기기 연결 필요성, 장기간의 고정 부하와 보안 정책은 사전에 확인해야 합니다.
이미 사용할 Mac이 있다면 원격 Mac 개발 환경 구성 안내에서 접속 방식과 운영 조건을 먼저 확인하십시오. Mac mini를 직접 주문할지 임대할지 비교하려면 Mac mini 주문 선택지를 살펴볼 수 있습니다. 서명 자산을 별도 계정으로 나누는 방식은 Mac mini 개인정보 보호 원칙과 함께 검토하면 좋습니다.
장기적으로 안정된 고정 부하와 물리 기기 연결이 필요하다면 직접 보유한 Mac이 더 적합할 수 있습니다. 반대로 출시 기간, 마이그레이션, 테스트 기간처럼 사용량이 변하는 팀이라면 장기간 유휴 상태인 하드웨어를 먼저 구매하는 것보다 원격 Mac 임대로 실제 Runner 부하를 검증하는 편이 낫습니다. 특히 전용 일반 계정, 완전한 Xcode 도구 체인, 재시작 후 사용자 세션 복구를 제공받지 못한다면 온라인 상태만 보고 계약해서는 안 됩니다.
macOS GitLab Runner 배포의 완료 조건은 등록 성공이 아닙니다. 실제 Xcode 작업이 반복 실행되고, 재시작 뒤 복구되며, 서명 자산이 격리되고, 실패한 작업의 흔적까지 정리되는 상태입니다. 이 네 가지를 확인한 뒤에야 해당 원격 Mac을 운영 CI 노드로 분류할 수 있습니다.