노드는 오프라인인데 SSH는 연결됩니다. 이때 노드를 먼저 지우거나 재설치하지 마세요.
가장 빠른 해결 순서는 Jenkins의 작업 배정 상태 → 연결 경로 → Java Agent 과정 → macOS 상주 세션 → 작업 공간과 Xcode 도구 체인입니다. 한 번 발생한 과정 종료는 원상 복구할 수 있지만, 반복적인 연결 끊김과 환경 변화가 확인되면 노드를 격리한 뒤 새 원격 Mac으로 재구축하는 편이 안전합니다.
이 글은 Jenkins와 원격 Mac 빌드 노드를 운영하며 장애 복구 시간을 줄여야 하는 DevOps 엔지니어를 위한 내용입니다. Xcode 자동 빌드·테스트·서명 작업을 관리하거나 장기 실행 macOS CI 노드를 추가하려는 플랫폼 담당자도 대상입니다.
01장애 범위 확정
먼저 Jenkins macOS Agent 연결 끊김이 실제 단절인지 확인합니다. 노드 화면의 상태만 보고 결론을 내리면 작업 대기 문제와 환경 오류를 놓치기 쉽습니다.
다음 자료를 같은 시각 기준으로 저장합니다.
- 컨트롤러 로그의 연결 종료와 재연결 기록
- 해당 노드 로그의 마지막 메시지와 오류 문구
- 대기 중인 작업의 배정 사유
- 최근 성공한 Xcode CI 작업과 첫 실패 작업
- 원격 Mac에서 실행 중인 Java 및 Agent 과정 상태
- 노드의 레이블, 실행기, 원격 루트 경로
Jenkins의 노드 관리 문서는 노드, 실행기, 레이블과 연결 상태를 별도로 다룹니다. 따라서 오프라인, 작업 대기, 온라인이지만 실행 불가를 먼저 분리해야 합니다. Jenkins 노드 관리 문서를 기준으로 컨트롤러 화면의 상태와 로그를 함께 대조하세요.
| 관찰된 상태 | 먼저 볼 위치 | 우선 판단 |
|---|---|---|
| 노드가 오프라인 | 컨트롤러 로그, 노드 로그 | 연결 또는 Agent 과정 |
| 작업이 계속 대기 | 큐 사유, 레이블, 실행기 | 배정 조건과 용량 |
| 노드는 온라인이나 작업 실패 | 작업 공간, 사용자 환경, Xcode | 실행 환경 |
| SSH만 연결됨 | macOS 원격 로그인과 Jenkins 경로 | 서로 다른 통신 경로 |
연결 경로와 실행 방식
SSH가 연결된다는 사실은 macOS의 Remote Login 서비스가 응답한다는 의미입니다. Jenkins가 실제로 사용하는 Agent 전송 경로가 정상이라는 뜻은 아닙니다. Apple의 Remote Login 공식 설명도 시스템 SSH 접속 설정을 설명할 뿐, Jenkins Agent의 연결 상태를 보장하지 않습니다.
사용 중인 Launch Method를 먼저 확인합니다.
- SSH 방식: 컨트롤러에서 원격 Mac의 시스템 SSH로 접속한 뒤 Agent를 시작합니다.
- 입장 연결 방식: 원격 Mac의 Agent가 컨트롤러로 연결을 시작합니다.
- WebSocket 기반 연결: 프록시와 TLS 종료 지점이 Jenkins Agent 통신을 방해할 수 있습니다.
세 경로를 섞어 확인하지 마세요. 컨트롤러의 SSH 서비스, macOS의 Remote Login, Jenkins Agent 전송 채널은 서로 다른 계층입니다. Jenkins가 공개한 서비스와 포트 문서에서 현재 배포의 통신 방향과 노출 범위를 대조해야 합니다.
확인 순서는 다음과 같습니다.
- 컨트롤러에서 원격 Mac의 호스트 이름이 올바른 주소로 해석되는지 확인합니다.
- 프록시와 방화벽이 해당 Launch Method의 통신 방향을 허용하는지 확인합니다.
- 인증서가 바뀌었거나 컨트롤러 주소가 변경되지 않았는지 확인합니다.
- Jenkins 자격 증명과 Agent 비밀값이 최근 교체되지 않았는지 확인합니다.
- 연결 복구 뒤 컨트롤러를 재시동해 자동 재연결을 시험합니다.
안정적인 복구의 증거는 화면에 잠시 온라인으로 표시되는 것이 아닙니다. 핸드셰이크가 완료되고, 하트비트가 유지되며, 컨트롤러 재시동 뒤 같은 노드가 자동으로 다시 연결되어야 합니다.
03Java Agent 과정과 버전 경계
연결 경로가 정상인데 노드가 계속 내려가면 원격 Mac에서 Agent 과정 자체를 확인합니다. SSH로 접속한 뒤 실행 사용자와 과정 목록을 확인하고, Java 과정의 표준 오류와 종료 상태를 분리해 기록합니다.
whoami
ps aux | grep -i agent
java -version
위 명령은 원인 확정용이 아니라 증거 수집용입니다. 다음 경우를 각각 나눠야 합니다.
- Agent 파일과 컨트롤러가 기대하는 버전이 맞지 않는 경우
- Java 실행 파일의 경로가 로그인 셸과 자동 실행 환경에서 다른 경우
- 시작 인자 또는 원격 작업 디렉터리가 잘못된 경우
- 자격 증명이나 비밀값이 변경된 경우
- macOS가 과정 종료를 기록한 경우
Jenkins는 Java 지원 범위를 고정된 상식으로 판단하면 안 됩니다. Jenkins 버전과 운영 중인 Java 조합을 공식 Java 지원 정책에서 작성 시점에 다시 확인하세요. 다운로드 주소나 Java 버전을 문서에 영구적으로 박아 넣기보다, 운영 중인 Jenkins 버전의 공식 안내에서 확인하도록 절차를 남기는 편이 안전합니다.
원격 Mac에서 수동으로 Agent가 시작되더라도 자동 실행 경로가 같은지 확인합니다. PATH, Java 경로, Agent 파일 위치, 작업 디렉터리, 실행 사용자가 달라지면 수동 시험은 성공하고 Jenkins 작업은 실패할 수 있습니다.
macOS 세션과 상주 구성
수동 SSH에서 Agent가 올라오는 것은 복구 증거가 아닙니다. 로그아웃, VNC 연결 종료, 재시동 뒤에도 같은 사용자 맥락으로 과정이 살아 있어야 합니다.
특히 다음 항목을 확인합니다.
- Agent를 실행하는 macOS 사용자
- 해당 사용자의 홈 디렉터리와 파일 권한
- 로그인 세션에 의존하는 환경 변수
- 자동 시작을 담당하는 launchd 구성
- launchd 로그에 남은 종료와 재시작 기록
- 재시동 뒤 네트워크와 원격 루트 경로가 준비되는 시점
launchd 설정은 macOS 버전과 실제 배포 방식에 맞춰 확인해야 합니다. 검증하지 않은 범용 plist를 복사하면 잘못된 사용자, 파일 권한, 실행 경로를 고정할 수 있습니다. 운영 중인 구성 파일과 로그를 먼저 보존하고, 수정 뒤에는 반드시 무인 상태에서 재연결을 시험하세요.
05주의: SSH 세션을 열어 둔 동안 Agent가 온라인이라는 결과는 세션 의존성을 숨길 수 있습니다. SSH를 종료하고 로그아웃한 뒤에도 과정이 유지되는지 확인해야 합니다.
온라인 노드와 Xcode 환경
Jenkins Agent가 온라인인데 Xcode CI 작업이 대기한다면 연결 장애로 단정하지 마세요. 레이블 불일치, 사용 가능한 실행기 부족, 원격 루트 경로 오류, 작업 공간 권한 문제가 더 직접적인 원인일 수 있습니다.
| 점검 항목 | 관찰할 증상 | 확인할 증거 |
|---|---|---|
| 레이블 | 작업이 특정 노드에 배정되지 않음 | 작업 조건과 노드 레이블 |
| 실행기 | 노드는 온라인이나 큐가 줄지 않음 | 실행기 상태와 동시 작업 |
| 원격 루트 | 작업 시작 직후 디렉터리 오류 | 노드 설정과 파일 권한 |
| Xcode 선택 | 빌드 도구를 찾지 못함 | xcode-select 경로와 작업 로그 |
| 서명 자산 | 빌드 또는 아카이브에서 실패 | 실행 사용자와 키체인 상태 |
Xcode의 명령 줄 도구 경로는 Apple의 Xcode 설정 문서와 Command Line Tools 설치 문서에 맞춰 확인합니다.
최소 확인 작업은 서로 분리합니다.
- 일반 셸 작업으로 작업 공간 생성과 파일 쓰기를 확인합니다.
- 일반 Xcode 빌드로 선택된 도구 체인과 프로젝트 의존성을 확인합니다.
- 테스트 작업으로 테스트 실행과 결과 수집을 확인합니다. 테스트 결과 문서를 참고하세요.
- 서명과 아카이브 작업으로 인증서, 프로비저닝 자산, 키체인 접근을 확인합니다.
- 서명된 결과물의 보관과 다음 작업의 작업 공간 정리를 확인합니다.
단순한 echo 성공은 생산 가능한 Xcode CI 상태를 뜻하지 않습니다. 빌드, 테스트, 서명은 각각 다른 권한과 도구 체인을 사용합니다. macOS 서명 아카이브의 요구 조건은 Apple의 서명 코드 생성 문서에서 확인하세요.
복구와 격리 판단
장애를 고친 뒤에는 같은 원인이 다시 나타나는 조건을 재현해야 합니다. 컨트롤러 재시동, 원격 Mac 재시동, 짧은 네트워크 중단, 동시 작업, 장시간 유휴 상태를 각각 시험합니다. 복구 시각과 수동 개입 여부를 기록하되, 근거 없는 평균 복구 시간을 성능 수치처럼 사용하지 마세요.
| 조건 | 통과 기준 | 실패 시 조치 |
|---|---|---|
| 컨트롤러 재시동 | Agent 자동 재연결 | 연결 방식과 비밀값 재검토 |
| 원격 Mac 재시동 | 무인 상태에서 자동 실행 | 사용자 세션과 launchd 점검 |
| 네트워크 중단 | 연결 회복 뒤 작업 수신 | 프록시와 하트비트 경로 점검 |
| 동시 작업 | 레이블과 실행기 규칙대로 배정 | 큐 조건과 실행기 설정 조정 |
| 장시간 유휴 | 수동 접속 없이 온라인 유지 | 과정 종료와 절전 정책 조사 |
다음은 복구 판정에 사용하는 실행 목록입니다.
- [ ] 오프라인 시각과 마지막 성공 작업을 저장했습니다.
- [ ] 컨트롤러, 노드, 원격 Mac의 로그를 같은 시간대에 대조했습니다.
- [ ] 실제 Launch Method의 통신 방향과 방화벽 규칙을 확인했습니다.
- [ ] Agent 과정의 실행 사용자, Java 경로, 종료 상태를 기록했습니다.
- [ ] 로그아웃과 VNC 종료 뒤에도 Agent가 유지되는지 확인했습니다.
- [ ] 원격 루트 경로, 레이블, 실행기, 작업 공간 권한을 검증했습니다.
- [ ] 일반 빌드, 테스트, 서명 작업을 각각 실행했습니다.
- [ ] 컨트롤러 재시동과 원격 Mac 재시동 뒤 자동 재연결을 시험했습니다.
- [ ] 반복 실패가 있으면 노드를 격리하고 재구축 사유를 남겼습니다.
한 번의 Java 과정 종료처럼 증거가 분명하고 재현되지 않는 문제는 원상 복구할 수 있습니다. 반대로 연결 끊김이 반복되거나, 실행 사용자와 Xcode 서명 환경이 계속 변하거나, 재시동 때마다 사람이 개입해야 한다면 노드를 생산 작업에서 격리하세요. 그 상태에서 새 노드로 재구축하거나 독립된 원격 Mac 빌드 노드를 추가하는 편이 임시 스크립트를 계속 늘리는 것보다 관리하기 쉽습니다.
| 현재 상태 | 권장 선택 | 이유 |
|---|---|---|
| 단일 과정 오류, 환경 변화 없음 | 원상 복구 | 원인과 수정 범위가 분명함 |
| 재시동 뒤 자동 실행 실패 | 구성 수정 후 재검증 | 상주 방식이 생산 조건을 충족하지 않음 |
| 연결과 도구 체인 오류가 반복됨 | 노드 격리 후 재구축 | 환경 드리프트가 누적됨 |
| 작업량과 장애 영향이 커짐 | 독립 원격 Mac 추가 | 장애 범위를 분리할 수 있음 |
운영 구조와 다음 선택
현재 사내 장비나 개인 Mac mini를 Jenkins 노드로 쓰는 방식은 물리 접근, 재시동 권한, 전원 상태, 단일 장비 의존성 때문에 장애 때 확인할 항목이 많습니다. 일반 클라우드 서버는 Linux 중심으로 구성되어 Xcode와 macOS 전용 서명 도구를 같은 조건에서 실행하기 어렵습니다. 가상 macOS 환경도 장치 접근과 도구 체인 호환성을 별도로 검증해야 합니다.
반면 장기 온라인 상태와 독립 재시동 권한이 필요한 경우에는 원격 Mac을 별도 빌드 노드로 분리하는 구성이 더 예측 가능합니다. 먼저 원격 Mac 기반 Jenkins Agent 구성 안내를 확인하고, 장비 선택이 필요하면 Mac mini 원격 운영 방식을 비교해 보세요. Xcode 서명 환경을 분리해야 한다면 운영 노드마다 사용자와 자산의 경계를 명확히 두는 것이 좋습니다.
다만 지속적인 고부하 작업을 장기간 수행하거나 물리 포트와 로컬 장치가 꼭 필요하다면 직접 구매가 더 적합할 수 있습니다. 현재 방식의 재시동 의존성, 단일 노드 장애, 원격 접근 권한 부족이 반복된다면 VpsMesh의 원격 Mac을 임시 테스트 환경이나 독립 Jenkins 노드로 검토할 가치가 있습니다. 기존 장비를 즉시 폐기하기보다, 같은 검증 작업과 재연결 조건으로 비교한 뒤 전환 여부를 결정하세요. 자세한 원격 Mac 선택지는 VpsMesh의 Mac 원격 운영 옵션에서 확인할 수 있습니다.
08자주 묻는 문제
FAQ에서는 SSH 연결과 Jenkins 연결을 분리하고, 재시동 뒤 상주 여부와 Xcode 작업의 실제 실행 가능성을 별도로 확인해야 합니다. 노드 화면의 온라인 표시만으로 복구를 선언하지 않는 것이 핵심입니다.