Laminar 1.4 常用 CLI 命令与运维实践

Laminar 1.4 的 laminarc 8 个子命令逐条实测:queue/start/run 的返回时机与退出码、--next 插队、abort 与 job 内 set、错误输出清单,以及 git hook、cron、systemd、备份升级与排障实践。

LaminarLaminar持续集成CIC++自动化运维2026/10/27

Laminar 1.4 常用 CLI 命令与运维实践

目标:把 laminarc 的 8 个子命令讲透,并给出真实服务器上的退出码、错误输出与排障路径;再进一步,把 Laminar 接进 git hook、cron 与 systemd 的日常运维。文中 20 余条命令回显均来自 Ubuntu 24.04.5 + Laminar 1.4 的实机执行。

一、环境信息

项目实测值
操作系统Ubuntu 24.04.5 LTS
主机名ci.example.com
Laminar 版本1.4-1~upstream-ubuntu2404
客户端/usr/bin/laminarc(108848 字节)
守护进程/usr/sbin/laminard
RPC 通道unix:/var/lib/laminar/laminar.sock
数据目录/var/lib/laminar
Webhttp://127.0.0.1:8080

本文所有 laminarc 命令都在导出了 LAMINAR_HOST 的 shell 中执行:

export LAMINAR_HOST=unix:/var/lib/laminar/laminar.sock

如果沿用默认的抽象 socket,则不需要这个变量(连接细节见第二节)。

二、命令总览

2.1 完整帮助

不带参数执行 laminarc 会打印版本与全部子命令:

$ laminarc
laminarc version 1.4-1~upstream-ubuntu2404
Usage: laminarc [-h|--help] COMMAND
  -h|--help       show this help message
where COMMAND is:
  queue JOB_LIST...     queues one or more jobs for execution and returns immediately.
  start JOB_LIST...     queues one or more jobs for execution and blocks until it starts.
  run JOB_LIST...       queues one or more jobs for execution and blocks until it finishes.
                        JOB_LIST may be prepended with --next, in this case the job will
                        be pushed to the front of the queue instead of the end.
  set PARAMETER_LIST... sets the given parameters as environment variables in the currently
                        running job. Fails if run outside of a job context.
  abort NAME NUMBER     aborts the run identified by NAME and NUMBER.
  show-jobs             lists all known jobs.
  show-queued           lists currently queued jobs.
  show-running          lists currently running jobs.
JOB_LIST is of the form:
  [JOB_NAME [PARAMETER_LIST...]]...
PARAMETER_LIST is of the form:
  [KEY=VALUE]...
Example:
  laminarc start \
    nightly-build branch=master type=release \
    nightly-build branch=master type=debug

1.4 的客户端只有这 8 个子命令,没有 log、status、cancel 之类的扩展。日志与状态全部走 HTTP,这一点决定了后面的运维方式:控制走 CLI,观测走 HTTP/journal。

2.2 三个触发命令的区别

命令行为返回时机典型用途
queue入队后立即返回入队完成git hook、定时任务
start入队并等待开始执行任务真正开跑需要拿到运行号后做后置动作
run入队并等待执行结束构建结束(退出码反映结果)手工验证、脚本串联

三者都支持 --next 把任务插到队列最前,也都支持一次传多个 job 和 KEY=VALUE 参数。

2.3 客户端连接方式

laminarc 通过 RPC 找守护进程,地址由客户端环境变量 LAMINAR_HOST 指定,未设置时用编译默认值 unix-abstract:laminar。把服务端改成文件 socket 后(见配置篇),客户端必须同步:

$ LAMINAR_HOST=unix:/var/lib/laminar/laminar.sock laminarc show-jobs
env-demo
fail
hello

不匹配时的报错非常直接,且是进程崩溃而非友好提示:

$ laminarc show-jobs
exit=134
terminate called after throwing an instance of 'kj::ExceptionImpl'
  what():  kj/async-io-unix.c++:1517: disconnected: connect(): Connection refused; address = unix-abstract:laminar

所以凡是切换过 RPC 地址的机器,都要同步修改所有调用方(cron、git hook、CI 脚本)的环境变量。

三、查询类命令

3.1 show-jobs

列出 cfg/jobs/ 下所有 job 名,一行一个:

$ laminarc show-jobs
env-demo
fail
hello
hooks
init-demo
inspect
setdemo
single-env
slow
timeout-demo

它只反映当前配置目录里的 job 定义,不包含历史。job 文件是热加载的,新增后立刻出现在列表里。

3.2 show-queued

$ laminarc show-queued

队列为空时没有任何输出,退出码 0。有内容时按「job:运行号」逐行打印。

3.3 show-running

$ laminarc show-running
slow:9

同样的「job:运行号」格式,只显示正在执行的 run。它和 show-queued 一起用,就能判断「是没触发、还是触发了但排不上队」。

四、触发类命令

4.1 queue:入队即返回

$ laminarc queue slow
slow:9

输出即「job:本次运行号」。命令本身不等待构建,适合放在 git hook、cron 里。

带参数触发也很常见,参数会注入脚本环境:

$ laminarc queue inspect os=ubuntu arch=x86_64
inspect:13

job 侧用 env | grep 验证参数确实生效:

$ curl -s http://127.0.0.1:8080/log/inspect/13
[laminar] Executing cfg/before
[global before] time=15:18:48 job=inspect
[laminar] Executing cfg/jobs/inspect.run
+ echo 'JOB=inspect RUN=13 CONTEXT=default'
JOB=inspect RUN=13 CONTEXT=default
+ env
+ sort
+ grep -E '^(os|arch|branch)='
arch=x86_64
os=ubuntu
[laminar] Executing cfg/after
[global after] job=inspect run=13 result=success last=success context=default

💡 提示:命令行参数不会覆盖 env 文件里已定义的变量(优先级见配置篇),同名变量只以文件为准。

4.2 start:等到开跑

$ laminarc start inspect
inspect:11

start 会阻塞到该 run 真正拿到执行槽位为止,然后打印运行号返回。适合「拿到运行号后立即轮询日志」的场景。

4.3 run:等到结束

$ laminarc run init-demo
init-demo:1

成功时退出码为 0。失败任务退出码为 3,超时任务同样是 3(但结果字段是 aborted):

$ laminarc run timeout-demo
timeout-demo:2
$ echo $?
3

这是把 Laminar 接进 shell 脚本时最重要的约定:判断结果看退出码,区分失败/超时看日志或 Web 结果字段。

4.4 一次触发多个 job

$ laminarc run inspect hello
inspect:12
hello:10
$ echo $?
0

按参数顺序逐个入队,每行一个运行号;全部成功才返回 0。

4.5 --next:插队

single 上下文只有一个执行槽,slow 每条要跑 60 秒,正好用来观察队列顺序:

$ laminarc queue slow
slow:9
$ laminarc queue slow
slow:10
$ laminarc queue --next slow
slow:11

$ laminarc show-running
slow:9
$ laminarc show-queued
slow:11
slow:10

后入队的 11 排在 10 前面,说明 --next 是插入队首而不是队尾。它不影响正在运行的 9。

4.6 记录触发原因

LAMINAR_REASON 是客户端环境变量,会被写入本次 run 并在 Web 与 SSE 中展示:

$ LAMINAR_REASON="nightly trigger" laminarc queue hello
hello:11

抓 SSE 中的 recent 数组验证:

$ curl -s -N --max-time 2 -H "Accept: text/event-stream" http://127.0.0.1:8080/ | grep -o '{"name":"hello","number":11[^}]*}'
{"name":"hello","number":11,"context":"default","queued":1793114344,"started":1793114344,"completed":1793114344,"result":"success","reason":"nightly trigger"}

把「谁触发的」写进 reason,是排查「这条构建为什么跑」的最低成本手段。

五、控制类命令

5.1 abort:中止运行

语法是 abort NAME NUMBER,两个参数缺一不可:

$ laminarc abort slow 9
$ echo $?
0

中止后队列立刻推进:

$ laminarc show-running
slow:11
$ laminarc show-queued
slow:10

中止不存在的运行时,命令无输出、退出码 2:

$ laminarc abort nosuchjob 1
$ echo $?
2

5.2 set:在 job 内部传值

set 只能在 job 上下文里用,它会通过隐藏管道把变量写回同一个 run 的后续脚本。实测 job:

# cfg/jobs/setdemo.before
#!/bin/bash
laminarc set STAGE=prepare

# cfg/jobs/setdemo.run
#!/bin/bash -ex
echo "STAGE=$STAGE"

运行日志:

[laminar] Executing cfg/jobs/setdemo.before
[laminar] Executing cfg/jobs/setdemo.run
+ echo STAGE=prepare
STAGE=prepare

在普通 shell 里调用则直接失败:

$ laminarc set foo=bar
Must be run from within a laminar job
$ echo $?
1

六、错误输出与退出码

场景命令输出退出码
未知子命令laminarc bogusUnknown command bogus1
用选项查版本laminarc --versionUnknown command --version1
触发不存在的 joblaminarc queue nosuchjobFailed to queue job 'nosuchjob'2
中止不存在的 runlaminarc abort nosuchjob 1无输出2
job 外调用 setlaminarc set foo=barMust be run from within a laminar job1
RPC 连不上laminarc show-jobsterminate called ... Connection refused134
构建失败/超时laminarc run <job>正常打印运行号3

守护进程侧没有 --version 选项,传了会先提示再打印版本与用法:

$ /usr/sbin/laminard --version
Unknown argument --version
laminard version 1.4-1~upstream-ubuntu2404
Usage:
  -h|--help       show this help message
  -v              enable verbose output

七、日志与观测

7.1 按 run 取日志

$ curl -s http://127.0.0.1:8080/log/hello/12 | head -3
[laminar] Executing cfg/before
[global before] time=15:19:32 job=hello
[laminar] Executing cfg/jobs/hello.run

latest 是特殊运行号,取最近一次:

$ curl -s http://127.0.0.1:8080/log/hello/latest | head -2
[laminar] Executing cfg/before
[global before] time=15:19:32 job=hello

注意:每个 job 是独立编号的,latest 只对存在的 job 有效;job 被删除或该编号不存在时返回 Not Found。

7.2 journald

调度器视角的记录在 journald 里,适合排查「任务为什么没跑」:

$ journalctl -u laminar --no-pager -n 6 -o cat
rpc.cpp:55: info: RPC queue; jobName = hello
laminar.cpp:714: info: Started job; run->name = hello; run->build = 12; ctx->name = default
laminar.cpp:755: info: Run completed; r->name = hello; to_string(r->result) = success
run.cpp:83: info: Run destroyed
laminar.cpp:755: info: Run completed; r->name = slow; to_string(r->result) = success
run.cpp:83: info: Run destroyed

RPC queue 与 Started job 之间的时间差就是排队时长;只有 RPC queue 没有 Started job,基本可以判定是上下文槽位或归属配置问题。

7.3 状态徽章与产物

$ curl -s --compressed http://127.0.0.1:8080/badge/hello.svg | grep -o 'success\|failed'
success

$ curl -s http://127.0.0.1:8080/archive/hello/8/build-time.txt
2026-10-27T14:47:44Z

徽章适合贴到 README,产物链接适合贴到发布记录;两者都不需要登录。

7.4 备份

需要备份的只有三样:配置、历史库、归档。实测打包:

$ tar czf /tmp/laminar-backup.tgz -C /var/lib/laminar cfg archive laminar.sqlite
$ ls -lh /tmp/laminar-backup.tgz
-rw-r--r-- 1 root root 6.9K Oct 27 15:19 /tmp/laminar-backup.tgz

run/ 不需要备份(临时目录与可重建的 workspace),但 laminar.sqlite 与 archive/ 一旦丢失,历史与产物就不可恢复。

八、运维集成实践

8.1 git post-receive hook(实测)

最省事的 SCM 集成方式:在裸仓库里挂一个 hook,推送到位就触发构建。

# /srv/demo.git/hooks/post-receive
#!/bin/bash
export LAMINAR_HOST=unix:/var/lib/laminar/laminar.sock
laminarc queue hello

给执行位后,从工作副本推送,构建号会直接回显在 push 输出里:

$ git push -q origin master
warning: You appear to have cloned an empty repository.
remote: hello:12
$ echo $?
0

remote: hello:12 就是 hook 里 laminarc queue 的输出,说明整条链路(push → hook → RPC → 调度)已经打通。生产环境建议在 hook 里带上分支等信息,例如 laminarc queue build branch=$(git rev-parse --abbrev-ref HEAD)。

8.2 cron 定时触发

Laminar 没有内置定时器,定时任务交给 cron:

# /etc/cron.d/laminar-nightly
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
15 2 * * * root LAMINAR_HOST=unix:/var/lib/laminar/laminar.sock laminarc queue nightly-build reason=scheduled

用 queue 而不是 run,避免 cron 进程被长时间构建占住;触发原因通过参数或 LAMINAR_REASON 写进数据库,方便回溯。

8.3 systemd 日常

$ systemctl status laminar --no-pager
$ sudo systemctl restart laminar
$ sudo systemctl disable --now laminar

restart 前必须确认队列为空——内存队列重启即丢:

$ laminarc show-queued

有输出就先等它跑完,或明确接受丢弃。

8.4 升级与回滚

升级流程(发行包方式):

  1. laminarc show-queued 确认没有排队任务;
  2. systemctl stop laminar;
  3. tar czf 备份 cfg、archive、laminar.sqlite;
  4. 安装新版本包,systemctl start laminar;
  5. systemctl status laminar、laminarc show-jobs、curl / 三项验收。

回滚就是把上一版包重新装上并恢复备份的数据库与归档。跨大版本回滚前必须先恢复 laminar.sqlite,否则旧版二进制可能读不了新结构。

九、排障手册

9.1 laminarc 连接失败并 core dump(退出码 134)

terminate called after throwing an instance of 'kj::ExceptionImpl'
  what():  kj/async-io-unix.c++:1517: disconnected: connect(): Connection refused; address = unix-abstract:laminar

按顺序检查:

  1. systemctl is-active laminar 是否为 active;
  2. 服务端 LAMINAR_BIND_RPC 与客户端 LAMINAR_HOST 是否一致;
  3. 文件 socket 模式下 ls -l 权限是否为 srw-rw---- laminar laminar,当前用户是否在 laminar 组。

9.2 服务起不来:socket 权限被拒

fatal: ::bind(sockfd, &addr.generic, addrlen): Permission denied; toString() = unix:/var/run/laminar.sock

/run 归 root,laminar 用户无权建 socket。把 socket 放到 /var/lib/laminar 下,或预建目录并 chown laminar:laminar。

9.3 任务一直排队、日志无报错

先看两处:

$ laminarc show-queued
$ laminarc show-running
  • 两者都有内容 → 正常排队,等槽位;
  • show-queued 有、show-running 长期为空 → 上下文归属问题,检查 cfg/contexts/*.conf 是否存在但缺少 default,或 job 的 CONTEXTS= 写错。

9.4 触发成功但 log 返回 Not Found

三个常见原因:

  • job 名拼错(区分大小写);
  • 运行号不存在(latest 只指向真实存在的最近一次);
  • 服务刚重启且该次 run 被中断,记录未落库。

9.5 构建结果与预期不符

同时看三个字段:

$ curl -s http://127.0.0.1:8080/log/<job>/latest | tail -3
$ journalctl -u laminar -n 20 -o cat
$ laminarc show-jobs

result=aborted 优先怀疑超时配置($JOB.conf 的 TIMEOUT);result=failed 看脚本退出码与 bash -ex 日志最后一条命令。

十、命令速查表

目的命令关键输出/退出码
查看帮助laminarc8 个子命令清单
列出 joblaminarc show-jobs每行一个 job 名
看排队laminarc show-queuedjob:run,空则无输出
看运行laminarc show-runningjob:run
入队laminarc queue <job> [k=v...]job:run
插队laminarc queue --next <job>队列最前
等开跑laminarc start <job>job:run
等结束laminarc run <job>退出码 0/3
中止laminarc abort <job> <run>0;不存在为 2
job 内传值laminarc set K=Vjob 外调用退出码 1
取日志curl /log/<job>/<run|latest>纯文本
看徽章curl /badge/<job>.svgSVG
取产物curl /archive/<job>/<run>/<file>文件内容
看调度日志journalctl -u laminar -o catRPC queue / Started job
备份tar czf ... cfg archive laminar.sqlite归档文件

十一、参考链接

系列导航: