Python3脚本后台执行Kubernetes kubectl命令异常求助
问题根因
- 每次调用
os.system()都会启动独立的shell子进程,原代码把后台启动命令、pid打印拆成两个os.system()执行,第二个shell里的$!根本拿不到第一个shell中启动的后台进程pid,逻辑完全断裂 - 重定向顺序错误:原命令先写了
> {podname}_{containername}_log把标准输出指向日志文件,后面又加&>/dev/null把标准输出+标准错误重定向到空设备,后面的规则会覆盖前面的配置,日志根本写不到指定文件 - 命令末尾多余的
&&是shell逻辑与操作符,后面没有跟随其他命令,会导致命令语法异常 - 使用
nohup时如果没有提前把所有输出流(包括nohup自己的提示信息)做重定向,nohup会默认把输出写入当前目录的nohup.out,同时打印忽略输入的提示
解决方案
方案1:修正shell命令(快速修复)
把后台启动、重定向、pid写入操作合并到同一个shell调用里,修正重定向顺序,屏蔽nohup的提示,直接替换原循环内的相关逻辑即可:
import os for podname in pod_names: if "smf" in podname or "pcf" in podname or "udm" in podname: containername = 'worker' else: containername = 'cppe' log_path = f"{podname}_{containername}_log" # 单条命令完成nohup启动、流重定向、后台运行、pid写入全流程 cmd = f"nohup kubectl logs -f -n core {podname} --container={containername} < /dev/null > {log_path} 2>&1 & echo $! >> pid.txt" # 屏蔽nohup自身的提示输出 os.system(f"{cmd} 2>/dev/null")
命令逻辑说明:
< /dev/null关闭标准输入,避免kubectl进程挂在终端输入上> {log_path} 2>&1先把标准输出指向日志文件,再把标准错误重定向到和标准输出相同的位置,不会被后续规则覆盖- 末尾加
&把进程放到当前shell后台,紧接着在同一个shell内通过echo $!获取进程pid写入文件,不存在跨进程拿不到pid的问题 - 最外层把命令的标准错误丢到空设备,屏蔽nohup的提示文字
方案2:使用subprocess模块(推荐,更稳定可控)
os.system对后台进程、流重定向的控制能力很弱,推荐用Python标准库的subprocess实现,完全不需要依赖shell的后台语法,也不会产生nohup.out文件,进程托管更可靠:
import subprocess for podname in pod_names: if "smf" in podname or "pcf" in podname or "udm" in podname: containername = 'worker' else: containername = 'cppe' log_path = f"{podname}_{containername}_log" # 打开日志文件句柄用于写入kubectl日志 log_fp = open(log_path, 'ab') # 启动kubectl进程,配置为完全脱离终端静默后台运行 proc = subprocess.Popen( ["kubectl", "logs", "-f", "-n", "core", podname, f"--container={containername}"], stdin=subprocess.DEVNULL, # 关闭标准输入 stdout=log_fp, # 标准输出写入指定日志文件 stderr=subprocess.STDOUT, # 标准错误合并到标准输出,一起写入日志 start_new_session=True # 新建进程会话,完全脱离当前终端,不会随Python脚本退出被终止,等价于nohup效果 ) # 直接从进程对象获取pid写入文件,准确率100% with open('pid.txt', 'a+') as pid_file: pid_file.write(f"{proc.pid}\n")
方案优势:
- 不需要拼接shell命令,无命令注入风险,也不会出现shell语法错误
- pid直接从进程对象获取,不存在拿错、拿不到pid的问题
- 不需要依赖nohup,通过进程会话配置实现终端脱离,不会产生nohup.out文件和相关提示
- 所有日志流重定向完全由Python控制,不会出现日志打印到终端、日志写丢的问题
注意事项
- 后续需要停止后台日志收集进程时,直接读取
pid.txt中记录的进程号,执行kill <进程号>即可 - 确保运行Python脚本的用户拥有core命名空间下对应pod的日志读取权限,权限校验失败的报错会直接写入对应pod的日志文件,方便排查
kubectl logs -f会持续跟随pod日志输出,日志文件会持续追加写入,不需要长期收集时记得及时清理进程和日志文件,避免占用过多磁盘空间
内容的提问来源于stack exchange,提问作者Bhanu Sachdeva
相关产品推荐
相关产品推荐

