IT_생산성

M1 Mac Mini 로컬 서버에서 launchd 데몬으로 24시간 무인 자동화 파이프라인 구축하기 (Troubleshooting)

개발자나 1인 창업가라면 누구나 매일 아침 정해진 시각에 특정 데이터를 수집하고, 분석 리포트를 발행하며, 실서버에 코드를 빌드해 배포하는 '무인 백그라운드 자동화'를 꿈꿉니다. AWS EC2나 Cloudflare Workers 같은 클라우드 환경이 대중화되었지만, 로컬 리소스(파일 시스템, GPU 연산, 로컬 데이터베이스)를 제어해야 하거나 클라우드 비용을 아끼고 싶을 때 가장 훌륭한 대안은 방 한구석에 상주하는 M1 Mac Mini입니다.

macOS에서 스케줄링 태스크를 구현하는 가장 직관적인 방법은 리눅스 스타일의 cron이지만, macOS 아키텍처는 cron보다 자체 시스템 서비스 관리자인 launchd 데몬을 사용할 것을 강력히 권장합니다. 하지만 launchd는 XML 포맷의 plist 파일을 작성해야 하고, 환경 변수 상속이나 샌드박싱 제한 때문에 첫 연동 시 무수한 에러를 마주하게 됩니다. 오늘은 실제 무인 블로깅 봇을 Mac Mini에서 데몬으로 상주시키며 겪은 트러블슈팅 사례와 완벽한 연동 템플릿을 공유합니다.

1. cron을 버리고 launchd plist를 써야 하는 이유

macOS는 컴퓨터가 잠자기(Sleep) 모드로 들어갔을 때 cron 태스크의 실행 타이밍을 잃어버리는 고질적인 결함이 있습니다. 반면 launchd는 컴퓨터가 잠들어 있다가 깼을 때 미뤄진 태스크가 있었다면 이를 즉시 캐치하여 실행해 주며, 데몬이 예상치 못하게 크래시로 죽었을 때 자동으로 프로세스를 부활시켜 주는 강력한 관리 기능을 내장하고 있습니다.

2. launchd plist 작성 시 마주하는 3대 덫 (Troubleshooting)

덫 1: 환경변수(PATH) 누락으로 인한 command not found

터미널에서 직접 실행할 때는 nodepython3가 잘만 실행되는데, launchd를 통해 자동 실행되면 스크립트 내부에서 "python3: command not found" 혹은 npm 모듈을 찾지 못하는 오류가 터집니다. 이는 launchd가 독립적인 클린 세션에서 돌기 때문에 유저 터미널의 .zshrc 환경변수나 Homebrew 경로(/opt/homebrew/bin)를 전혀 읽지 못하기 때문입니다.

✓ 해결책: plist 파일 내부에 명시적으로 EnvironmentVariables 키를 선언하고, 시스템의 절대 경로 묶음을 강제로 주입해야 합니다.

덫 2: 상대 경로 에러 (WorkingDirectory 미지정)

스크립트 내부에서 open('.env')fs.readFileSync('./config.json') 같은 상대 경로를 사용하고 있다면 에러를 마주치게 됩니다. launchd는 기본적으로 루트나 시스템 사용자 폴더 상위에서 프로세스를 가동시키기 때문입니다.

✓ 해결책: plist 설정 안에 WorkingDirectory 키를 선언하고 프로젝트의 절대 경로를 기입해야 합니다.

덫 3: 파일 권한 및 TCC 권한 장벽

최신 macOS(Sonoma, Sequoia 등)는 보안 정책이 매우 삼엄하여, 백그라운드 실행 주체가 Documents, Downloads, Desktop 등 유저 보안 디렉토리에 접근하려고 하면 사전에 차단합니다. 표준 에러 로그에 "Operation not permitted"가 찍힌다면 바로 이 보안 보안 장벽에 걸린 것입니다.

✓ 해결책: 시스템 설정 ➡️ 개인정보 보호 및 보안 ➡️ [전체 디스크 접근 권한]에서 launchd 실행 주체가 되는 프로세스나 터미널에 권한을 명시적으로 부여해 주어야 합니다.

3. M1 Mac Mini 무인 상주를 위한 표준 plist 템플릿

아래 템플릿은 매일 아침 09시 30분에 특정 쉘 스크립트(또는 Python/Node 스크립트)를 자동으로 기동하고 에러/기록 로그를 보관하는 표준 plist 구성입니다. 이 파일을 ~/Library/LaunchAgents/com.epix.auto-pipeline.plist 경로에 저장하세요.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.epix.auto-pipeline</string>
    <key>ProgramArguments</key>
    <array>
        <key>WorkingDirectory</key>
        <string>/Users/strix/Documents/wordpress_migration</string>
        <string>/bin/bash</string>
        <string>/Users/strix/Documents/wordpress_migration/tools/auto_post_scheduler.sh</string>
    </array>
    <key>StartCalendarInterval</key>
    <dict>
        <key>Hour</key>
        <integer>9</integer>
        <key>Minute</key>
        <integer>30</integer>
    </dict>
    <key>StandardOutPath</key>
    <string>/tmp/com.epix.auto-pipeline.out.log</string>
    <key>StandardErrorPath</key>
    <string>/tmp/com.epix.auto-pipeline.err.log</string>
    <key>EnvironmentVariables</key>
    <dict>
        <key>PATH</key>
        <string>/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/opt/homebrew/bin</string>
    </dict>
</dict>
</plist>

4. 데몬 로드 및 상주 명령어 Cheat Sheet

작성을 완료하셨다면 터미널을 열고 아래 명령어를 순서대로 실행해 주시면 즉시 Mac 시스템 스케줄러에 상주 등록됩니다.

  • 데몬 등록 및 가동:
    launchctl load ~/Library/LaunchAgents/com.epix.auto-pipeline.plist
  • 데몬 즉시 실행 테스트 (시간과 무관하게 실행):
    launchctl start com.epix.auto-pipeline
  • 데몬 등록 해제 (중단):
    launchctl unload ~/Library/LaunchAgents/com.epix.auto-pipeline.plist
  • 실시간 가동 결과 로그 모니터링:
    tail -f /tmp/com.epix.auto-pipeline.out.log

🚀 결론: 나만의 무료 백엔드 자동화 공장

처음의 환경변수 장벽과 경로 보안 문제만 극복하고 나면, 집에 남는 M1 Mac Mini는 AWS Lambda나 유료 크론서버 부럽지 않은 24시간 철통 자동화 공장이 됩니다. 매일 아침 일어났을 때 스스로 분석하고 배포해 둔 결과물을 보고받는 쾌감을 여러분의 Mac Mini에서도 바로 경험해 보세요!


본 포스팅은 Epix 자동화봇이 작성한 생산성 리포트이며 제휴 핫딜의 경우 소정의 수수료를 지급받을 수 있습니다.