Skip to content

Latest commit

 

History

History
365 lines (271 loc) · 9.8 KB

File metadata and controls

365 lines (271 loc) · 9.8 KB

lark-push 部署运维手册

本文以 Ubuntu 24.04、systemd、Nginx 和单台服务器为标准生产环境。 项目同时运行定时调度器和 HTTP 回调服务,因此生产环境只能启动一个 lark-push 进程。不要使用 Gunicorn 多 worker,也不要在多台服务器上同时 启动 scheduler,否则同一任务可能被重复发送。

1. 部署模型

  • 代码:/opt/lark-push
  • Python 虚拟环境:/opt/lark-push/.venv
  • 密钥配置:/etc/lark-push/lark-push.env
  • 运行状态:/var/lib/lark-push/state.json
  • 后台渠道配置:/var/lib/lark-push/managed_recipients.json
  • 服务账户:lark-push
  • 应用监听:127.0.0.1:3000
  • 公网入口:Nginx HTTPS

生产环境推荐设置 LARK_ADMIN_READ_ONLY=true。任务变更通过功能分支、 Pull Request 和部署完成,避免管理页直接修改仓库文件导致服务器工作树变脏。

2. 前置条件

  • Ubuntu 24.04 或提供 Python 3.12 以上版本的兼容 Debian 系统
  • Python 3.12 以上
  • 一个指向服务器的域名,例如 lark-push.example.com
  • 服务器可以访问 GitHub、PyPI、飞书开放平台和 ZenMux API
  • GitHub 仓库 tenlywu/lark-push 的只读 Deploy Key
  • 飞书应用 ID、Secret、接收者 ID 和回调配置

安装系统依赖:

sudo apt update
sudo apt install -y git python3 python3-venv nginx certbot python3-certbot-nginx

创建服务账户和目录:

sudo useradd \
  --system \
  --create-home \
  --home-dir /var/lib/lark-push \
  --shell /usr/sbin/nologin \
  lark-push

sudo install -d -o lark-push -g lark-push -m 0750 /opt/lark-push
sudo install -d -o root -g lark-push -m 0750 /etc/lark-push
sudo install -d -o lark-push -g lark-push -m 0750 /var/lib/lark-push

3. 配置 GitHub Deploy Key

生成专用于该仓库的 SSH Key:

sudo -u lark-push install -d -m 0700 /var/lib/lark-push/.ssh
sudo -u lark-push ssh-keygen \
  -t ed25519 \
  -N '' \
  -C 'lark-push production deploy key' \
  -f /var/lib/lark-push/.ssh/id_ed25519

sudo -u lark-push ssh-keyscan github.com \
  | sudo -u lark-push tee /var/lib/lark-push/.ssh/known_hosts >/dev/null
sudo -u lark-push chmod 0600 /var/lib/lark-push/.ssh/known_hosts
sudo cat /var/lib/lark-push/.ssh/id_ed25519.pub

将公钥添加到 GitHub 仓库:

Settings -> Deploy keys -> Add deploy key

只需要读取权限,不要勾选写权限。验证连接:

sudo -u lark-push ssh -T git@github.com

GitHub 会返回认证成功但不提供 shell,这是正常结果。

4. 首次安装

克隆代码并安装依赖:

sudo -u lark-push git clone \
  git@github.com:tenlywu/lark-push.git \
  /opt/lark-push

sudo -u lark-push python3 -m venv /opt/lark-push/.venv
sudo -u lark-push /opt/lark-push/.venv/bin/python -m pip install --upgrade pip
sudo -u lark-push /opt/lark-push/.venv/bin/python -m pip install \
  -r /opt/lark-push/requirements.txt

创建生产配置:

sudo install \
  -o root \
  -g lark-push \
  -m 0640 \
  /opt/lark-push/.env.example \
  /etc/lark-push/lark-push.env

sudo editor /etc/lark-push/lark-push.env

生产环境至少需要调整以下内容:

LARK_APP_ID='cli_xxx'
LARK_APP_SECRET='xxx'
LARK_RECIPIENTS_JSON='{"personal":{"receive_id_type":"open_id","receive_id":"ou_xxx","label":"Personal"},"group":{"receive_id_type":"chat_id","receive_id":"oc_xxx","label":"Group"}}'
LARK_ADMIN_PASSWORD='replace-with-a-strong-password'
LARK_ADMIN_SESSION_SECRET='replace-with-a-random-secret'
ZENMUX_MANAGEMENT_API_KEY='xxx'

LARK_CALLBACK_HOST=127.0.0.1
LARK_CALLBACK_PORT=3000
LARK_HTTP_TIMEOUT_SECONDS=15
LARK_REPORT_TIMEZONE=Asia/Shanghai
LARK_WEB_THREADS=8
LARK_ADMIN_READ_ONLY=true
LARK_SESSION_COOKIE_SECURE=true

LARK_TASKS_DIR=/opt/lark-push/tasks
LARK_STATE_FILE=/var/lib/lark-push/state.json
LARK_MANAGED_RECIPIENTS_FILE=/var/lib/lark-push/managed_recipients.json

可通过以下命令生成 session secret:

openssl rand -hex 32

配置文件不得提交到 Git,也不要复制到工单或聊天记录。

使用真实生产配置做只读校验。该命令不会启动 scheduler,也不会发送消息:

sudo -u lark-push bash -c '
  set -a
  source /etc/lark-push/lark-push.env
  set +a
  exec /opt/lark-push/.venv/bin/python -m lark_push.check_config
'

成功时会输出任务数、启用任务数和渠道数,不会输出任何密钥。

5. 发布前验证

统一验证脚本使用测试凭据、临时运行目录和全部禁用的任务副本,不会调用真实 飞书发送接口,也不会修改生产状态:

cd /opt/lark-push
sudo -u lark-push env \
  PYTHON_BIN=/opt/lark-push/.venv/bin/python \
  bash scripts/verify.sh

成功标志:

service smoke: ok
verification: ok

任何一步失败都不要启动或重启生产服务。

6. 安装 systemd 服务

sudo install \
  -o root \
  -g root \
  -m 0644 \
  /opt/lark-push/deploy/systemd/lark-push.service \
  /etc/systemd/system/lark-push.service

sudo systemctl daemon-reload
sudo systemctl enable --now lark-push
sudo systemctl status lark-push --no-pager

检查本机健康状态:

curl --fail --silent http://127.0.0.1:3000/healthz | python3 -m json.tool

查看日志:

sudo journalctl -u lark-push -n 200 --no-pager
sudo journalctl -u lark-push -f

首次启动会根据任务状态执行 bootstrap。启用中的任务如果没有现存状态,可能 立即发送卡片,因此必须先确认任务配置、接收者和生产环境变量正确。

7. 配置 Nginx 和 HTTPS

先复制模板并替换域名:

sudo cp \
  /opt/lark-push/deploy/nginx/lark-push.conf \
  /etc/nginx/sites-available/lark-push.conf

sudo sed -i \
  's/lark-push.example.com/你的实际域名/g' \
  /etc/nginx/sites-available/lark-push.conf

sudo ln -s \
  /etc/nginx/sites-available/lark-push.conf \
  /etc/nginx/sites-enabled/lark-push.conf

sudo nginx -t
sudo systemctl reload nginx
sudo certbot --nginx -d 你的实际域名
sudo nginx -t
sudo systemctl reload nginx

公网验证:

curl --fail --silent https://你的实际域名/healthz | python3 -m json.tool
curl --fail --silent \
  -H 'Content-Type: application/json' \
  -d '{"challenge":"deploy-check"}' \
  https://你的实际域名/feishu/callback

在飞书开放平台将回调地址配置为:

https://你的实际域名/feishu/callback

/admin 应仅允许可信网络访问。推荐通过 VPN、Nginx IP allowlist 或额外的 SSO/访问网关限制入口,不应只依赖应用密码暴露在公网。

8. 日常升级

记录当前版本并备份运行状态:

cd /opt/lark-push
sudo -u lark-push git status --short
sudo -u lark-push git rev-parse HEAD

sudo install -d -o root -g lark-push -m 0750 /var/backups/lark-push
sudo tar -C /var/lib \
  -czf "/var/backups/lark-push/lark-push-$(date +%Y%m%d-%H%M%S).tar.gz" \
  lark-push

工作树必须为空。然后拉取、安装和验证:

sudo -u lark-push git -C /opt/lark-push pull --ff-only
sudo -u lark-push /opt/lark-push/.venv/bin/python -m pip install \
  -r /opt/lark-push/requirements.txt

cd /opt/lark-push
sudo -u lark-push env \
  PYTHON_BIN=/opt/lark-push/.venv/bin/python \
  bash scripts/verify.sh

验证成功后重启:

sudo systemctl restart lark-push
sudo systemctl status lark-push --no-pager
curl --fail --silent http://127.0.0.1:3000/healthz | python3 -m json.tool
sudo journalctl -u lark-push -n 100 --no-pager

9. 回滚

切换到升级前记录的提交:

sudo systemctl stop lark-push
sudo -u lark-push git -C /opt/lark-push switch --detach 升级前提交SHA
sudo -u lark-push /opt/lark-push/.venv/bin/python -m pip install \
  -r /opt/lark-push/requirements.txt
sudo systemctl start lark-push

如果需要恢复运行状态:

sudo systemctl stop lark-push
sudo tar -C /var/lib -xzf /var/backups/lark-push/对应备份文件.tar.gz
sudo chown -R lark-push:lark-push /var/lib/lark-push
sudo systemctl start lark-push

恢复到主分支:

sudo -u lark-push git -C /opt/lark-push switch main

10. 常见故障

服务启动失败

sudo systemctl status lark-push --no-pager
sudo journalctl -u lark-push -n 200 --no-pager
sudo -u lark-push test -r /etc/lark-push/lark-push.env

重点检查必填环境变量、JSON 格式、任务引用的渠道以及运行目录权限。

健康检查正常但没有发送

  • 检查任务 enabled
  • 检查任务 channel.target_refs 是否存在于渠道配置。
  • 查看 state.json 中是否已有活动消息。
  • 检查飞书应用权限和应用可见范围。
  • 查看 ZenMux API Key 是否有效。
  • 查看 systemd 日志中的 Lark API 错误。

重复发送

立即检查是否有多个实例:

pgrep -af 'python.*-m lark_push'
systemctl status lark-push

生产环境只能运行一个实例。不要同时保留手工启动进程、多个 systemd unit、 容器副本或 Gunicorn workers。

管理页无法保存

生产默认 LARK_ADMIN_READ_ONLY=true,这是预期行为。任务应在 Git 分支中修改 并通过正常发布流程部署。若临时允许管理页写入,会直接修改仓库中的 tasks/ 文件并造成工作树变脏,不推荐在生产使用。

状态文件损坏

停止服务,备份损坏文件,再从最近备份恢复。直接删除 state.json 会导致服务 认为没有活动消息,下一次启动可能重新发送所有启用任务。

11. 安全与备份

  • /etc/lark-push/lark-push.env 权限保持 0640 root:lark-push
  • Deploy Key 保持只读。
  • 定期轮换飞书 Secret、ZenMux Key、管理密码和 session secret。
  • 定期备份 /var/lib/lark-push,并测试恢复流程。
  • 仅通过 HTTPS 暴露回调与管理页面。
  • 升级必须使用 git pull --ff-only,禁止服务器上直接开发或强制覆盖工作树。