9.5 KiB
install service 脚本规则与参考原则
本文档说明 shell/install_iot.sh、shell/install_efka.sh 的配置规则、安装流程和后续维护原则。
目标
安装逻辑已经按服务拆分:
install_iot.sh: 只安装并配置iot服务。install_efka.sh: 只安装并配置efka服务。
服务脚本负责:
- 下载服务发布包。
- 解压到
WORK_DIR。 - 删除下载到
WORK_DIR的压缩包。 - 创建运行所需目录。
- 生成
/etc/systemd/system/<service>.service。 - 将服务环境变量写入对应
.service文件。 - 执行
systemctl daemon-reload。 - 设置服务开机启动。
install_iot.sh会将{install_dir}/bin/iot_ctrl软链接到/usr/local/bin/iot_ctrl。
入口规则
只安装 iot:
curl -fsSL https://punchsky.cn/install_iot.sh | bash
只安装 efka:
curl -fsSL https://punchsky.cn/install_efka.sh | bash
本地执行:
sudo ./install_iot.sh
sudo ./install_efka.sh
顶部配置规则
服务配置只维护在对应拆分脚本顶部。
INSTALL_IOT / INSTALL_EFKA
install_iot.sh 维护 INSTALL_IOT,install_efka.sh 维护 INSTALL_EFKA。
格式:
INSTALL_<APP>=(
"service_name"
"download_url"
"start_command"
"stop_command"
"service_user"
"service_group"
)
字段说明:
service_name: systemd 服务名,例如iot、efka。download_url: 发布包下载地址,仅支持.tar.gz或.tgz。start_command: systemdExecStart命令。stop_command: systemdExecStop命令,可为空。service_user: 服务运行用户,可为空;为空时使用脚本默认SERVICE_USER。service_group: 服务运行组,可为空;为空时使用脚本默认SERVICE_GROUP。
命令中可使用占位符:
{install_dir}: 解压后的服务安装目录,当前为{work_dir}/{service_name},例如/opt/app/iot、/opt/app/efka。{work_dir}: 脚本工作目录。{service_name}: 当前服务名。
IOT_ENV / EFKA_ENV
IOT_ENV 和 EFKA_ENV 配置对应项目的生产环境变量,来源参考各项目 env.file 中的 [prod] 配置。
这些变量不会写入 /etc/default/*,也不会使用 EnvironmentFile=。脚本会直接将它们写入对应 systemd service:
Environment="KEY=value"
IOT_DIR_ENV_KEYS / EFKA_DIR_ENV_KEYS
IOT_DIR_ENV_KEYS 和 EFKA_DIR_ENV_KEYS 声明哪些环境变量的值是目录。
安装时脚本会:
- 从对应
*_ENV中读取变量值。 - 替换占位符。
- 要求目录必须是绝对路径。
- 如果目录不存在,则创建。
- 将目录 owner 设置为服务用户和服务组。
IOT_PARENT_DIR_ENV_KEYS
IOT_PARENT_DIR_ENV_KEYS 声明哪些环境变量的值是文件路径,脚本会创建这些文件路径的父目录。
例如 IOT_CTRL_SOCKET_PATH=/var/lib/iot/ctl.sock 是 Unix socket 文件路径,脚本应创建并授权 /var/lib/iot,不能把 /var/lib/iot/ctl.sock 当目录创建。
当前 iot 会创建:
/var/lib/endpoint/database//var/lib/endpoint/endpoint_log/var/lib/iot/mnesia//var/lib/iot,来自IOT_CTRL_SOCKET_PATH的父目录
当前 efka 会创建:
/var/lib/efka/dets//var/lib/efka/docker//var/lib/efka/mnesia
安装流程
单个服务脚本执行顺序:
- 解析命令行参数。
- 校验
WORK_DIR和服务配置。 - 检查依赖命令:
wget、dirname、ln、tar、systemctl。 - 创建
WORK_DIR。 - 安装当前服务。
- 重新加载 systemd。
- enable 已安装服务。
单个服务安装流程:
- 校验服务名、下载地址、启动命令。
- 根据服务名推导安装目录,默认是
/opt/app/<service_name>。 - 下载压缩包到临时文件。
- 保存压缩包到
WORK_DIR。 - 创建安装目录。
- 解压压缩包。
- 删除保存到
WORK_DIR的压缩包。 - 设置安装目录 owner。
- 根据
*_DIR_ENV_KEYS创建数据目录,并根据*_PARENT_DIR_ENV_KEYS创建文件路径父目录。 - iot 安装时创建
/usr/local/bin/iot_ctrl软链接。 - 生成 systemd service 文件。
- 记录服务名,后续统一 enable。
iot_ctrl 构建和打包原则
iot_ctrl 位于 iot/go_extend,应在发布包构建阶段编译,不在 install_iot.sh 中编译。
目标机器不应依赖 Go 编译环境。发布包需要提前包含:
iot/
bin/
iot
iot_ctrl
安装后脚本会检查 {install_dir}/bin/iot_ctrl 是否存在且可执行。如果不存在,安装会失败并提示需要在打包前构建该工具。
安装成功后会创建软链接:
/usr/local/bin/iot_ctrl -> /opt/app/iot/bin/iot_ctrl
构建示例:
cd iot/go_extend
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 make build
如果目标机器是 arm64:
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 make build
systemd service 生成规则
每个服务会生成:
/etc/systemd/system/<service_name>.service
service 文件包含:
UserGroupWorkingDirectory- 多行
Environment="KEY=value" ExecStartExecStopRestart=on-failureRestartSec=5
环境变量必须写入服务自己的 .service 文件,而不是外部环境文件。
目录创建原则
只有明确列入 IOT_DIR_ENV_KEYS 或 EFKA_DIR_ENV_KEYS 的环境变量才会作为目录创建。
新增目录型环境变量时,需要同时修改两处:
IOT_ENV=(
"NEW_DATA_DIR=/var/lib/iot/new_data"
)
IOT_DIR_ENV_KEYS=(
"NEW_DATA_DIR"
)
非目录型环境变量只需要加入 *_ENV,不要加入 *_DIR_ENV_KEYS。
如果环境变量是文件路径,需要把变量名加入对应的 *_PARENT_DIR_ENV_KEYS,脚本只创建父目录:
IOT_ENV=(
"IOT_CTRL_SOCKET_PATH=/var/lib/iot/ctl.sock"
)
IOT_PARENT_DIR_ENV_KEYS=(
"IOT_CTRL_SOCKET_PATH"
)
权限原则
脚本支持 root 或普通用户运行。
- 如果当前是 root,直接执行需要 root 权限的命令。
- 如果不是 root,通过
sudo执行。 - 数据目录和安装目录 owner 会设置为服务运行用户和组。
- systemd service 文件写入
/etc/systemd/system,需要 root 权限。
默认服务用户:
SERVICE_USER="${SERVICE_USER:-$CURRENT_USER}"
SERVICE_GROUP="${SERVICE_GROUP:-$(id -gn "$SERVICE_USER")}"
可通过参数覆盖:
./install_iot.sh --user app --group app
./install_efka.sh --user app --group app
占位符原则
以下位置支持占位符:
- 启动命令。
- 停止命令。
- 环境变量值。
- 目录路径。
支持的占位符:
{install_dir}{work_dir}{service_name}
如果该变量是目录,需要加入对应 *_DIR_ENV_KEYS。如果该变量是文件路径,需要加入对应 *_PARENT_DIR_ENV_KEYS。
{install_dir} 不从压缩包文件名推导,不带版本号,固定使用服务名作为目录名。
修改和扩展原则
修改环境变量
只修改对应服务脚本顶部数组:
IOT_ENV=(
"IOT_API_URL=http://127.0.0.1/api/v1"
)
修改后重新执行对应服务脚本,会重新生成 service 文件。
新增目录
同时修改:
IOT_ENV或EFKA_ENVIOT_DIR_ENV_KEYS或EFKA_DIR_ENV_KEYS
新增文件路径
同时修改:
IOT_ENV或EFKA_ENV- 对应的
*_PARENT_DIR_ENV_KEYS
修改下载包
只修改对应服务脚本:
INSTALL_IOT=(
"iot"
"https://example.com/iot-x.y.z.tar.gz"
...
)
下载包后缀必须是:
.tar.gz.tgz
新增服务
新增服务时应按现有拆分结构创建新的 install_<app>.sh:
- 新增
INSTALL_<APP>。 - 新增
<APP>_ENV。 - 新增
<APP>_DIR_ENV_KEYS。 - 在
validate_args中校验对应配置。 - 在
service_env_lines中映射服务名到 env 数组。 - 在
service_dir_env_keys中映射服务名到目录 key 数组。 - 如服务有文件路径型环境变量,在
service_parent_dir_env_keys中映射服务名到父目录 key 数组。 - 在
install_programs中调用对应配置。
兼容性原则
脚本当前兼容 Bash 3.2,不使用 local -n 等较新的 Bash 特性。
读取动态数组时使用 eval,因此数组名必须由脚本内部固定传入,不应使用用户输入构造数组名。
验证建议
修改脚本后至少执行:
bash -n shell/install_iot.sh
bash -n shell/install_efka.sh
建议额外验证 service 渲染结果:
bash -c "$(sed '$d' shell/install_iot.sh); render_service_file iot app app /opt/app/iot '/opt/app/iot/bin/iot foreground' '/opt/app/iot/bin/iot stop'"
bash -c "$(sed '$d' shell/install_efka.sh); render_service_file efka app app /opt/app/efka '/opt/app/efka/bin/efka foreground' '/opt/app/efka/bin/efka stop'"
如果目标机器有 systemd-analyze,可进一步验证生成后的 unit 文件:
systemd-analyze verify /etc/systemd/system/iot.service
systemd-analyze verify /etc/systemd/system/efka.service
注意事项
- 环境变量中如包含空格或特殊字符,需要确认 systemd
Environment=语法是否仍然正确。 - token 等敏感信息会写入 systemd service 文件,需控制
/etc/systemd/system/*.service的读取权限和服务器访问权限。 - 数据目录和文件路径型变量必须使用绝对路径。
- iot 发布包必须包含可执行的
bin/iot_ctrl,否则不会创建/usr/local/bin/iot_ctrl链接。 - 现有卸载脚本如果需要同步目录清理规则,应按
IOT_DIR_ENV_KEYS/EFKA_DIR_ENV_KEYS的思路同步调整。