TL;DR
Jenkins は Daemon ではなく Agent として起動しなければならない.また, Agent を起動したローカルユーザがログインしている状態を保持しなければならない.
プログラム自動実行の仕組み
Mac にはプログラムを自動実行させる仕組みとして Daemon と Agent が用意されている. Daemon はシステム (OS) 起動時に実行される. Agent はユーザログイン時に実行される.自動実行させたいプログラムごとに .plist ファイルを用意し,所定のディレクトリに保存して launchctl で登録すればよい. Daemon は GUI に対応していないため, GUI が必要なプログラムは Agent として実行する必要がある.
項目 | Daemon | Agent |
---|---|---|
実行者 | システム | ユーザ |
実行タイミング | システム起動時 | ユーザログイン時 |
.plist 保存先 | /Library/LaunchDaemons/ | ~/Library/LaunchAgents/ |
プログラムの GUI 対応 | 非対応 | 対応 |
Agent の補足
Agent には 2 種類ある. .plist の保存先によって動作が異なり, ~/Library/LaunchAgents/
であれば当該ユーザが GUI ログインした際に実行され, /Library/LaunchAgents/
であればユーザを問わず GUI ログインした際に実行される.
なお, Agent 実行のためにはユーザは GUI でログインしなければならない. SSH 等の CLI によるログインでは実行されない
プログラムの登録
Jenkins をユーザ john の Agent として自動実行させたい場合の例を示す.
まず .plist ファイル (XML) を作成して所定のディレクトリに保存する (~/Library/LaunchAgents/homebrew.mxcl.jenkins.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>UserName</key>
<string>john</string>
<key>GroupName</key>
<string>staff</string>
<key>Label</key>
<string>homebrew.mxcl.jenkins</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/java</string>
<string>-XX:MaxPermSize=512m</string>
<string>-Xms512m</string>
<string>-Xmx1024m</string>
<string>-Dmail.smtp.starttls.enable=true</string>
<string>-Dorg.jenkinsci.plugins.gitclient.Git.timeOut=120</string>
<string>-jar</string>
<string>/usr/local/opt/jenkins/libexec/jenkins.war</string>
<string>--logfile=/var/log/jenkins/jenkins.log</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
次に launchctl コマンドで .plist ファイルの内容を登録する.
launchctl load -w ~/Library/LaunchAgents/homebrew.mxcl.jenkins.plist
あとはユーザ john が GUI ログインすれば Jenkins が起動する.
Agent ではなく Daemon として起動させたい場合は,上記 .plist ファイルを Daemon 用のディレクトリに保存し, launchctl コマンドを sudo で実行すればよい.
Agent の注意点
Agent として実行されたプログラムはユーザが GUI ログインしているときにしか動作しない.ユーザがログアウトすればプログラムも停止する. GUI ログインしていない状態でコマンドから起動しようとしてもエラーが出てしまう.
launchctl start homebrew.mxcl.jenkins
Could not find domain for
よって,常時実行させておきたいプログラム (Jenkins) は Agent ではなく Daemon として実行したいが,残念ながら Jenkins は Agent で実行する必要がある.なぜなら Jenkins から起動する Unity が GUI を必要としているからである. Jenkins を Daemon として起動させた場合, Unity が下記のようなエラーを吐いて正常に動作しなくなることがある.
CFPasteboardRef CFPasteboardCreate(CFAllocatorRef, CFStringRef) : failed to create global data
Agent として実行されたプログラムはユーザがログアウトすると停止してしまうため, Jenkins を実行させたままにしておきたい場合はユーザのログイン状態を維持する必要がある.