云计算百科
云计算领域专业知识百科平台

AI多Agent协作系统实战(五十四):装个Linux版,四个坑排队等着

系列第54篇 | zip丢了权限、venv忘了家、logs没建、sudo卡住——一个安装脚本的血泪

背景

事情要从一台刚买的Ubuntu服务器说起。系统装好,IP还是动态的——重启一次IP就换一次,SSH配置全废。

为了固定IP,我在 /etc/netplan/50-cloud-init.yaml 里折腾了半天,最后还专门写了个 99-disable-network-config.cfg 把cloud-init的网络配置关掉,才算把静态IP钉死。

然后我开始装产品——Linux版安装包。

我以为"装个Linux版"就是 bash install.sh 回车、回车、完事。结果一个下午,四个坑排队等着我。


坑一:zip解压完,脚本全都"不能执行"

安装包是zip格式。解压、部署、跑安装核心——一切正常。直到安装完成,我执行 bash start.sh:

bash: start.sh: Permission denied

什么?start.sh是我刚生成的,权限明明是755啊?

再仔细一看——不只是start.sh,整个 runtime/venv316/bin/ 和 runtime/node/bin/ 下的所有可执行文件,权限位全丢了。

根因:zip格式不保存Unix权限位。打包机上 venv316/bin/python 是755,zip压缩再解压到另一台机器,就变成了644——能看,不能执行。

修复:部署时遍历所有bin目录,统一补回可执行权限:

for d in ["venv316/bin", "node/bin", "npm-global/bin"]:
for f in os.listdir(os.path.join(rt_dst, d)):
p = os.path.join(rt_dst, d, f)
if os.path.isfile(p):
os.chmod(p, os.stat(p).st_mode | 0o111)

教训:Linux下分发Python/Node运行时,tar.gz保留权限位,zip不保留。如果你打包选zip,部署时"补权限"这一步一个都不能少。


坑二:venv忘了"家"在哪——pyvenv.cfg还指着打包机

权限补好了,再跑:

$ runtime/venv316/bin/python –version
Fatal Python error: init_fs_encoding: failed to get the Python codec of the filesystem encoding

Python直接崩了。

根因:Python虚拟环境的 pyvenv.cfg 里有个 home = 字段,记录的是创建venv时用的解释器路径。我的venv是在打包机上用uv创建的,home 指向打包机的路径(比如 /root/.local/share/uv/python/…)。zip部署到新机器后,这个路径根本不存在——Python找不到自己的家,启动即崩溃。

修复:部署时重写 pyvenv.cfg 的home,指向部署位置的python:

for line in open(pv, encoding="utf-8"):
if line.startswith("home ="):
lines.append(f"home = {os.path.join(rt_dst, 'venv316/bin')}\\n")
else:
lines.append(line)
open(pv, "w", encoding="utf-8").writelines(lines)

教训:venv是"路径敏感"的——打包、分发、换目录,必须检查 pyvenv.cfg。你以为venv是自包含的,其实它带着一个"回不去的家"。


坑三:logs目录没建——服务"启动成功"了,其实根本没起来

前两个坑修完,bash start.sh:

已启动 Web(8899) / WS(9000)

然后我访问 http://服务器IP:8899——连接被拒绝。

根因:启动脚本里是这么写的:

nohup python app/web_server.py > logs/web.log 2>&1 &

> logs/web.log 是 shell重定向——在启动Python之前,shell先去打开 logs/web.log。但部署目录里根本没有 logs/ 文件夹——于是shell直接报错:

bash: logs/web.log: No such file or directory

nohup … & 整个命令失败,Python压根没启动。但脚本后面还有 echo "已启动…"——echo照样执行,看起来就像启动成功了。

修复:启动脚本里先建目录:

mkdir -p logs

教训:"启动成功"的提示 ≠ 服务真的起来了。重定向路径的父目录不存在,命令会在程序运行前就失败,而你的脚本还会若无其事地打印成功。启动脚本必须 mkdir -p 兜底。


坑四:sudo静默安装,卡在密码输入

安装核心在检测到缺Node.js时,会尝试自动安装:

cmds = [
f"{sudo}apt-get update",
f"{sudo}apt-get install -y nodejs npm",
]
for c in cmds:
r = subprocess.run(c, shell=True, capture_output=True, text=True)

这里有个隐藏炸弹:如果当前用户不是root,sudo 会弹密码输入。而 subprocess.run 没有提供 stdin——sudo等密码等不到,直接失败;或者在某些环境下挂起不动,安装进程就这么卡死。

根因:安装脚本假设了"要么root,要么sudo免密",但实际部署的服务器两者都不一定满足。

修复:要么检测到非root且sudo需要密码时明确提示(而不是静默卡住),要么干脆内置运行时——把Node/Python全打进包,部署后不依赖系统apt。

教训:安装脚本最怕"静默"——sudo要密码、包管理器要交互、权限不足——每一种都应该明确提示用户怎么处理,而不是悄悄失败或卡死。


经验总结

  • zip不保留Unix权限位——部署必须补chmod
  • venv的 pyvenv.cfg 指向打包机——换机器必须重写home
  • 重定向 > logs/web.log 的父目录不存在——服务静默起不来,还打印"已启动"
  • sudo/apt交互——非root环境必须显式处理,不能静默卡死

装完Linux版,我最大的感受是:"安装包能装上"和"安装包能跑起来"之间,隔着一条河。河底下全是权限、路径、目录这些没人写进README的小坑。

而它们每一个,都只差一行代码就能避免。

赞(0)
未经允许不得转载:网硕互联帮助中心 » AI多Agent协作系统实战(五十四):装个Linux版,四个坑排队等着
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!