2026 Mac 클라우드 24/7 백그라운드 작업: Linux cron에서 macOS launchd로 이전하는 결정표와 환경 변수 체크리스트

Mac 클라우드 SSH는 되는데 야간 동기화나 헬스 체크를 crontab에 올리면 실행 안 됨, PATH 손실, 로그 없음이 흔합니다. 본문은 VPS처럼 운영하려는 팀을 위해 cron과 launchd 비교표, LaunchAgent와 LaunchDaemon 선택, 최소 plist, launchctl bootstrap, 5단계 검증을 정리합니다.

원격 Mac 클라우드에서 launchd로 예약 작업을 관리하는 개념도

목차

1. 세 가지 문제: crontab은 맞는 듯하지만 Mac 클라우드에서 깨지는 이유

macOS에도 cron은 남아 있지만 통합 스케줄러는 launchd입니다. 헤드리스 Mac 클라우드에서는 「SSH 수동 실행은 성공, 예약만 실패」 패턴이 흔합니다.

  1. PATH·환경 변수 단절: Linux는 crontab 안에 PATH=를 적을 수 있습니다. macOS cron 환경은 매우 빈약해 node·python3를 못 찾습니다. SSH는 .zprofile·.zshrc를 읽지만 cron/launchd는 기본적으로 읽지 않아 「수동 OK=예약 OK」로 오인하기 쉽습니다.
  2. 실행 주체와 키체인: 상대 경로, ~, 키체인 접근은 cron과 LaunchAgent에서 다르게 동작합니다. GUI 가정 작업을 무헤드에 올리면 조용히 실패합니다. 빌드 큐·디스크와 겹치면 DerivedData 정리가 때때로 로그 없이 실패합니다.
  3. 관측성 부족: StandardOutPath·StandardErrorPath가 없으면 실패가 unified logging 조각으로만 남아 CI와 시계열 대조가 어렵습니다. Runbook이 없으면 crontab만 고치는 루프에 빠집니다.

다음 표로 plist 도메인을 한 번에 정해 잘못된 층에서 시간을 쓰지 않습니다.

2. 의사결정 표: cron, LaunchAgent, LaunchDaemon

노트북의 「로그인 후 돌면 됨」과 달리 Mac 클라우드는 대개 24시간 가동·GUI 세션 없음이 많습니다. 재부팅 후에도 launchd가 읽는 배치를 우선합니다.

시나리오Linux 습관macOS 권장이유
개발기, 로그인 후 동기화user crontab~/Library/LaunchAgents사용자 도메인에서 툴체인 접근
클라우드 24/7, 로그인 없음system cronLaunchDaemon 또는 bootstrap된 AgentGUI 분리, 재부팅 후 자동 기동
root·저포트root crontabLaunchDaemon + UserName실행 사용자 명시로 감사 용이
초단위 고빈도systemd timerStartInterval + 스로틀 이해이벤트 병합 주의
일회 유지보수atlaunchctl submit / RunAtLoad장기 항목 최소화
실무: nvm·pyenv에 기대지 말고 ProgramArguments절대 경로 셸·스크립트를 쓰며, EnvironmentVariablesPATH를 고정하세요. 비밀은 plist 평문 금지, 키체인·CI 시크릿으로.

3. plist·launchctl·bootstrap·5단계 검증

SSH 권한 전제. 라벨은 제로 트러스트 SSH Runbook과 맞춥니다.

  1. 인터프리터 고정: which bash, which node 기록. Homebrew는 /opt/homebrew/bin 또는 /usr/local/bin 절대 경로로 「대화형엔 brew, 잡엔 없음」 제거.
  2. 최소 plist: Label, ProgramArguments, StartCalendarInterval(또는 StartInterval), stdout/stderr, EnvironmentVariables. 매일 03:15 예(경로 교체):
# 필수 키: Label / ProgramArguments / StartCalendarInterval 또는 StartInterval / # EnvironmentVariables.PATH / StandardOutPath / StandardErrorPath # 예: 03:15 /bin/bash -lc /usr/local/bin/run.sh # PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin, 로그 nightly.log/.err # XML plist를 ~/Library/LaunchAgents에 두고 launchctl bootstrap
  1. 배치·로드: ~/Library/LaunchAgents 또는 /Library/LaunchDaemons에 두고 launchctl bootstrap …. 변경 시 bootoutbootstrap 또는 kickstart -k.
  2. 시험·로그: launchctl kickstart -kp gui/$(id -u)/com.example.vpsmac.nightly-sync. stdout/stderr 로테이션, 파일 쓰기 시 WorkingDirectory.
  3. 환경 diff: 임시로 env | sort 파일(디버그 후 삭제) 또는 launchctl print로 대화형 SSH와 비교.
  4. CI·에이전트 공존: OpenClaw·xcodebuild 피크와 분리. Nice나 별 노드로 I/O 경쟁 완화.

1~4는 실행, 5~6은 관측·공존을 보장합니다. 장애 시 stdout/stderr 마지막 200줄, launchctl print, plist SHA-256 세트를 티켓에 첨부하면 수렴이 빨라집니다.

4. 인용·운영 파라미터

① 시스템 명령만이면 PATH=/usr/bin:/bin:/usr/sbin:/sbin로 충분한 경우가 많음. ② 캘린더 트리거는 시스템 타임존·DST 따름. ③ 로그 무로테이션은 GB까지 팽창, newsyslog 등 병행. ④ 짧은 주기는 병합될 수 있어 초당 엄격 주기 기대 금지. ⑤ plist 644 등으로 변조 어렵게.

대용량 rsyncxcodebuild 의존성 해결이 같은 시각에 겹치면 SSD가 200~400MB/s대에서 포화되어 「네트워크 장애」처럼 보이는 I/O 대기가 납니다. 10~15분만 어긋나도 재현률이 떨어지는 경우가 많습니다.

5. 임시 crontab에서 감사 가능한 Mac 클라우드로

개인 export·짧은 수명 crontab은 환경 드리프트·비밀 분산·공존 워크로드 경쟁을 부릅니다. plist를 저장소로 관리하는 것이 프로덕션 노드 예의입니다.

범용 Linux VPS에서 macOS 스케줄 전제를 억지로 맞추면 launchd 부재·키체인 서사 불일치·Xcode 체인 비정렬이 쌓입니다. 컨테이너로 경로를 흉내도 코드 서명·시뮬레이터 전제 iOS 파이프라인까지 대체하기 어렵고 제2 플랫폼 운용만 늘어납니다.

2026년 VPS형 SSH와 네이티브 macOS를 함께 원한다면 VPSMAC M4 Mac 클라우드에 launchd를 개통 Runbook에 넣고 동일 plist 정책을 노드에 복제하는 편이 장기적으로 단순합니다.

6. FAQ

crontab을 써도 되나요?

가능하지만 기본 권장은 아닙니다. PATH·절대 경로·로그 전달을 필수로 하세요.

LaunchAgent와 LaunchDaemon 차이는?

Agent는 사용자 GUI 세션 쪽, Daemon은 시스템 부트 쪽에 가깝습니다. 무헤드 호스트에서는 키체인·파일 소유 요구로 고릅니다.

plist를 바꿨는데 반영이 안 됩니다

bootout/bootstrap 순서와 Label 일치, stderr 경로 쓰기 권한을 확인하세요.