증상 → 가장 빠른 해결법
SSH로 맥에는 다시 접속되지만 GitLab Runner가 오프라인이라면, 바로 재설치하지 말고 맥 호스트, 그래픽 사용자 세션, LaunchAgent, Runner 등록, 네트워크 순서로 위치를 좁혀야 합니다. macOS에서 지원되는 상시 실행 방식은 사용자 수준 LaunchAgent이며, 서명이나 시뮬레이터 작업은 올바른 그래픽 로그인 세션에서 복구해야 합니다. GitLab의 macOS 서비스 방식도 시스템 수준 LaunchDaemon을 대체 방식으로 안내하지 않습니다.
이 글은 원격 맥 한 대를 CI 노드로 운영하다가 재시작 후 수동 복구가 반복되는 개발자와 운영자를 위한 런북입니다. 여러 프로젝트의 GitLab Runner, 코드 서명, 시뮬레이터 작업을 담당하는 DevOps 및 릴리스 엔지니어도 대상입니다. 플랫폼 팀이라면 마지막의 재시작 검수 항목을 인수 기준으로 사용할 수 있습니다.
장애 위치부터 분리하기
“맥은 살아 있는데 Runner만 오프라인”이라는 실패 사례에서 가장 흔한 실수는 서비스 설치부터 다시 하는 것입니다. SSH 연결이 된다는 사실은 호스트의 네트워크와 원격 로그인만 증명합니다. Runner 프로세스가 실행 중인지, GitLab과 연결됐는지, 작업 태그가 맞는지는 별도 상태입니다.
다음 순서로 확인합니다.
- SSH로 호스트에 접속합니다.
- 현재 사용자와 홈 경로를 확인합니다.
- Runner 프로세스와 로그를 확인합니다.
- GitLab 화면의 마지막 접속 시각과 상태를 비교합니다.
- 대기 중인 작업의 태그와 Runner 태그를 비교합니다.
호스트에 접속할 수 없으면 CI 설정을 조사하지 말고 원격 접근부터 복구합니다. 프로세스가 없으면 LaunchAgent와 사용자 세션을 봅니다. 프로세스가 있는데 마지막 접속 시각만 멈췄다면 네트워크, 프록시, 인증서, 등록 상태로 이동합니다. 온라인인데 작업만 대기하면 서비스 재시작을 중단하고 태그와 보호 조건을 확인합니다.
사용자 세션과 LaunchAgent 확인
macOS의 GitLab Runner는 로그인한 사용자의 LaunchAgent로 실행됩니다. 맥이 켜져 있고 SSH가 열려 있어도 해당 사용자가 그래픽 세션에 로그인하지 않았다면 Runner가 자동으로 올라오지 않을 수 있습니다. Apple의 Service Management 설명은 LaunchAgent가 로그인한 사용자와 연결되어 실행되는 구조를 설명합니다.
일반적인 명령줄 빌드만 수행한다면 사용자 세션 복구가 상대적으로 단순합니다. 반면 다음 작업은 그래픽 세션과 사용자 보안 저장소를 별도로 검증해야 합니다.
- 코드 서명과 인증서 접근
- Keychain에 저장된 서명 자격 증명 사용
- iOS Simulator 실행
- 그래픽 권한이나 사용자별 개발 도구를 요구하는 Xcode 작업
SSH에서 설치나 시작을 시도한 뒤 launchctl failed: Could not find domain for가 나타났다면, 잘못된 세션 영역에 LaunchAgent를 등록했을 가능성이 있습니다. SSH에서 설정 파일을 삭제하고 다시 만드는 방식은 원인을 숨길 수 있습니다. VNC 또는 웹 콘솔로 실제 사용자 그래픽 세션에 들어간 뒤, 그 세션의 터미널에서 설치와 시작을 다시 수행합니다.
자동 로그인은 편리하지만 기본 해법이 아닙니다. Apple의 자동 로그인 제한 안내에 따르면 FileVault와 조직 관리 정책이 자동 로그인에 영향을 줄 수 있습니다. 보안 정책상 자동 로그인을 허용할 수 없다면, 원격 콘솔에서 디스크 잠금 해제와 사용자 로그인을 수행하는 복구 절차를 문서화해야 합니다. LaunchAgent 문제를 해결하기 위해 FileVault를 끄는 방식은 권장하지 않습니다.
파일과 권한 증거 수집
사용자 영역에서 다음 항목을 확인합니다.
- LaunchAgent plist가 예상한 사용자 홈 아래에 있는지
- plist 안의 Runner 실행 파일 경로가 실제 경로와 일치하는지
- Runner 설정 파일의 소유자와 권한이 현재 사용자 기준인지
- 로그 디렉터리가 존재하고 현재 사용자에게 쓰기 권한이 있는지
- 바이너리와 설정 파일이 재시작 뒤에도 같은 위치에 남아 있는지
오류 문구마다 수집할 증거가 다릅니다.
killed: 9가 보이면 프로세스가 종료된 시점의 로그, 바이너리 경로, 실행 권한, 시스템 보안 차단 여부를 보존합니다. exit status 134는 설정 파일과 실행 인자, 직전 로그를 먼저 확보합니다. Load failed: 5는 LaunchAgent의 등록 영역, plist 문법, 파일 경로를 함께 확인합니다. GitLab의 macOS Runner 문제 해결 항목에도 이 오류 유형별 점검 방향이 정리되어 있습니다.
재설치는 마지막 단계입니다. 실행 파일이 손상됐다는 증거가 있을 때만 기존 설정 파일과 등록 정보의 백업을 남기고 진행합니다. 설정 파일을 먼저 삭제하면 토큰과 실행기 설정을 잃고, 원래 문제가 사용자 영역인지 파일 손상인지 구분할 수 없게 됩니다. 명령과 설정 위치는 GitLab Runner 명령 문서의 현재 안내와 대조합니다.
연결과 작업 예약 분리
Runner가 프로세스로 실행 중이어도 GitLab에 연결되지 않을 수 있습니다. 프록시 변경, 방화벽, 인증서 검증, 등록 토큰 만료 또는 잘못된 서버 주소가 원인일 수 있습니다. 프로세스 로그의 연결 시각과 GitLab 화면의 마지막 접속 시각을 비교하면 상주 실패와 통신 실패를 분리하기 쉽습니다.
등록 상태가 의심되면 곧바로 새 Runner를 만들지 말고 현재 설정과 프로젝트 연결 범위를 보존합니다. 등록 정보를 다시 만들면 오래된 노드와 새 노드가 동시에 남아 운영자가 잘못된 대상을 고칠 수 있습니다. 고급 설정은 GitLab Runner 설정 문서에 맞춰 확인합니다.
온라인 상태인데 작업이 대기하면 다음을 봅니다.
- 작업의
tags와 Runner에 지정된 태그가 일치하는지 - Runner가 해당 프로젝트 또는 그룹에서 작업을 받을 수 있는지
- 보호 브랜치와 보호 태그 조건이 맞는지
- Runner가 일시 중지 상태가 아닌지
- Shell executor가 필요한 명령과 현재 맥 환경이 맞는지
GitLab의 Runner 태그 매칭 규칙에 따라 태그가 맞지 않으면 온라인 Runner도 해당 작업을 받지 않습니다. 이 경우 Runner를 재시작해도 대기 상태는 바뀌지 않습니다.
Shell executor는 Runner 사용자 권한으로 명령을 실행합니다. 신뢰하지 않는 프로젝트를 공유 노드에서 실행하면 소스 코드, 환경 변수, 인증서, Keychain 접근 권한이 노출될 수 있습니다. GitLab의 Shell executor 보안 안내에 따라 프로젝트 신뢰 범위와 노드 분리 여부를 정해야 합니다.
재시작 복구 FAQ
맥 재시작 뒤 Runner가 다시 나타나지 않는 구조적 원인
사용자 그래픽 세션이 복구되지 않았거나 LaunchAgent가 올바른 사용자 영역에 등록되지 않은 경우가 핵심입니다. SSH가 열려 있다는 사실만으로 사용자 기반 서비스가 시작됐다고 볼 수 없습니다. 특히 FileVault가 활성화된 원격 노드는 디스크 잠금 해제, 사용자 로그인, LaunchAgent 시작을 각각 확인해야 합니다.
SSH에서 launchctl domain을 찾지 못하는 경우
순수 SSH 세션은 그래픽 로그인 세션의 사용자 bootstrap domain과 다를 수 있습니다. 따라서 SSH에서 LaunchAgent를 설치하거나 시작하면 domain을 찾지 못하는 오류가 발생할 수 있습니다. VNC 또는 웹 콘솔로 실제 사용자 세션에 진입한 뒤 같은 작업을 반복하고, 기존 plist와 설정 파일을 먼저 보존해야 합니다.
온라인 Runner에 작업이 배정되지 않는 경우
온라인은 연결 상태를 뜻할 뿐 작업 조건이 충족됐다는 뜻은 아닙니다. 태그 불일치, 보호 브랜치 설정, 프로젝트 연결 범위, 일시 중지 상태를 확인해야 합니다. 작업 화면의 태그와 Runner 설정을 나란히 비교하고, 조건이 맞는 작은 테스트 작업으로 예약 여부를 확인합니다.
FileVault 환경의 복구 판단
FileVault를 끄는 것은 Runner 복구 절차가 아닙니다. 조직 정책과 보안 요구를 먼저 확인하고, 원격 콘솔에서 잠금 해제와 사용자 로그인을 수행할 수 있는지 검증합니다. 그래픽 세션이 반드시 필요한 서명과 시뮬레이터 작업은 해당 세션까지 복구된 뒤 실행해야 하며, 명령줄 전용 작업과 결과를 분리해 기록합니다.
재시작 검수 체크리스트
복구가 끝났다면 화면의 온라인 표시만 보고 완료 처리하지 않습니다. 다음 항목을 실제로 실행하고 결과와 시각을 기록합니다.
- [ ] 정상 CI 작업을 종료한 뒤 현재 Runner 로그와 GitLab 접속 상태를 저장합니다.
- [ ] 원격 콘솔과 SSH 접속 경로가 각각 준비됐는지 확인합니다.
- [ ] 맥을 정상적인 방식으로 재시작합니다.
- [ ] 디스크 잠금 해제와 대상 사용자의 그래픽 로그인을 수행합니다.
- [ ] LaunchAgent가 현재 사용자 영역에서 실행됐는지 확인합니다.
- [ ] Runner 프로세스, 로그, GitLab의 마지막 접속 시각을 대조합니다.
- [ ] 태그가 맞는 간단한 macOS CI 작업을 실행합니다.
- [ ] 코드 서명과 Keychain이 필요한 작업을 별도로 실행합니다.
- [ ] iOS Simulator가 필요한 작업을 별도로 실행합니다.
- [ ] 그래픽 세션 없이 가능한 작업과 수동 복구가 필요한 작업을 구분합니다.
- [ ] 복구 실패 시 사용할 VNC, 웹 콘솔, SSH 순서를 문서에 남깁니다.
이 과정을 마치면 결론은 세 가지 중 하나입니다. 모든 작업이 자동 복구되면 운영에 투입합니다. 일반 빌드만 복구되면 서명과 시뮬레이터 작업에 수동 승인 절차를 둡니다. 그래픽 세션을 안정적으로 되살릴 수 없으면 생산 작업을 옮기기 전에 별도 노드나 다른 전달 방식을 검토합니다.
처음부터 재현 가능한 노드를 만들고 싶다면 원격 맥 CI 환경의 기본 구성을 먼저 확인할 수 있습니다. 코드 서명 자격 증명을 프로젝트별로 분리해야 한다면 맥 미니 원격 운영 방식과 함께 접근 경로와 사용자 권한을 설계하는 편이 안전합니다.
현재 Windows나 Linux 장비에 SSH만 붙이고 가상 환경으로 대체하는 방식은 macOS 전용 도구를 실행할 수 없고, 서명과 시뮬레이터에서 사용자 세션 문제가 반복되며, 재시작 뒤 복구 경로도 운영자가 직접 관리해야 한다는 단점이 있습니다. 로컬 Mac 한 대를 상시 켜 두는 방식도 하드웨어 장애와 원격 접근 단절에 취약합니다. 재시작 복구를 먼저 검증해야 한다면 그래픽 콘솔과 SSH를 함께 제공하는 MACCOME 원격 맥으로 격리 노드를 구성해 보십시오. Runner, 서명, Simulator가 실제로 복구되는지 확인한 뒤 생산 작업을 옮기는 순서가 비용과 장애 위험을 함께 줄이는 방법입니다.