You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SSH远程执行Python脚本时K8s Pod日志未生成问题排查

问题:远程执行K8s运维脚本无法生成日志文件

我是一名想转型DevOps的系统管理员,编写了kube_reload.py脚本用于检查Kubernetes Pod,当Pod挂起时记录其日志并删除该Pod,计划将监控脚本check_radio加入Cron自动处理挂起Pod。本地在Kube Master执行kube_reload.py时功能完全正常(可生成日志并删除Pod);但从Nginx服务器通过SSH远程执行该脚本时,仅Pod被成功删除,却未生成对应的日志文件,且无任何报错信息。我使用Python 3.6,脚本及所在目录权限均为777,目前暂未掌握K8s API的使用方法,希望先解决当前问题,同时欢迎针对运维工作的优化建议。

相关脚本

kube_reload.py(Kube Master上的脚本)

#!/bin/python3

import sys
import os
import re
import subprocess as sp
from contextlib import redirect_stdout as r_stdout


marker = False
pod_nums = ''
pod_nums_int = []
for_reload = []

get_pods = sp.check_output(['kubectl', 'get', 'pods'])
get_pods = str(get_pods)
get_pods = get_pods.split()

pods = []


'''write garbage pod names in array'''

for word in get_pods:
    if 'radio-hls' in word:
        pods.append(word) 

'''make usual pod names from garbage names'''

for num in range(len(pods)):

    while marker == False:
        if pods[num][:5] != 'radio':
            pods[num] = pods[num][1:]
        if pods[num][:5] == 'radio':
            break


'''Function that lists all pods'''

def pod_list():

    sp.run('clear')
    print('PODS LIST:\n')
    for num in range(len(pods)):
        print(num+1, '.\t', pods[num])

    print(len(pods)+1, '.\t Reload all')

'''Function for recursion in try-except statement in 'input_nums()' function'''

def return_for_except():
    pod_list()
    print('Error input. Try again\n\n')
    input_nums()

'''Function that asks which pods you want to reload'''

def input_nums():
    pod_nums = str(input('Select which pods you want to reload (type all numbers with a space):\nExample: 1 2 3 10\n\n'))
    pod_nums = pod_nums.split()

    try:
        global pod_nums_int
        pod_nums_int = [eval(i) for i in pod_nums]
    except:
        return return_for_except()

'''Function to write pod logs to a file'''

def write_logs():

    global for_reload

    if len(pods)+1 in pod_nums_int:

        all_reload = input('You selected "Reload all". To continue, press Enter\n')

        if all_reload == '':
            for i in range(len(pods)):
                with open (f'{pods[i-1][10:-17]}.log', 'w') as pod_log:
                                    sp.run(['kubectl', 'logs', f'{pods[i-1]}'], stdout=pod_log)
                print(f'{pods[i-1]} logged successfully')
                for_reload.append(i)
        else:
            print('Something went wrong')
            quit()
    else:
        for i in pod_nums_int:

            with open (f'{pods[i-1][10:-17]}.log', 'w') as pod_log:
                sp.run(['kubectl', 'logs', f'{pods[i-1]}'], stdout=pod_log)
            print(f'{pods[i-1]} logged successfully')
            for_reload.append(i)


'''Function that reloads streams'''

def reload_pods(for_reload, pods):
    for i in for_reload:
        sp.run(['kubectl', 'delete', 'pod', f'{pods[i-1]}'])
        print(f'{pods[i-1]}', 'deleted')





'''Start'''

'''manual (with no arguments)'''
if len(sys.argv) == 1:
    pod_list()
    input_nums()
    write_logs()
    reload_pods(for_reload, pods)
    sp.run(['kubectl', 'get', 'pods'])
    print()
    sp.run(['ls', '-lah'])

'''auto (from nginx srver)'''

if len(sys.argv) > 1:
    for arg in sys.argv:
        if arg == './kube_reload.py':
            continue
        else:
            for pod in pods:
                if arg in pod:
                    #write logs
                    with open (f'{arg}.log', 'w') as log:
                        sp.run(['kubectl', 'logs', f'{pod}'], stdout=log)
                    #reload pods
                    sp.run(['kubectl', 'delete', 'pod', f'{pod}'])
                else:
                    continue

check_radio(Nginx服务器上的脚本)

#!/bin/python3


import requests as r
import subprocess as sp
import sys

'''IN CASE OF ADDING ADDITIONAL STREAM ADD IT TO "streams" '''

streams = [
'gold',
'tophits',
'worldchart',
'ukraine',
'rock',
'chill',
'rap',
'retromusic',
'elektro',
'sport',
'radionv',
'edyninov',
'hromadske'
]

'''IF IF THERE IS NO NEED TO CHECK SOME STREAMS YOU CAN ADD IT TO "streams_not_to_check" '''

streams_not_to_check = [
'radionv',
'edyninov',
'hromadske'
]

streams_to_delete = []

#CLUSTER_API = 'https://host_ip:6443'
#auth_header = 'Authorization: '

for stream in streams:
    check_stream = r.get(f'https://host.host/stream/{stream}/status/health').json()

    if check_stream['metadata'] == 'UNHEALTHY':
        streams_to_delete.append(stream)

for stream in streams_not_to_check:
    if stream in streams_to_delete:
        streams_to_delete.remove(stream)

print(streams_to_delete)



if len(streams_to_delete) >= 1:

    for stream in streams_to_delete:

        sp.Popen(f'ssh developer@radio1 python3 ~/deekly/kube_reload.py {stream}', shell=True).communicate()

执行结果对比

1. Nginx服务器远程执行

[developer@radio-lb1 deekly]$ ./check_radio
['rap', 'rock']
pod "radio-hls-rap-f4b86bd77-jpmr4" deleted
pod "radio-hls-rock-57fc8fcd64-m54k5" deleted
[developer@radio-lb1 deekly]$

Kube Master上无日志文件生成

2. Kube Master本地执行

[developer@radio1 deekly]$ ./kube_reload.py rap rock
pod "radio-hls-rap-f4b86bd77-4bvcs" deleted
pod "radio-hls-rock-57fc8fcd64-g5j96" deleted
[developer@radio1 deekly]$ ls -la
total 32
drwxrwxrwx  2 developer developer   59 Aug  5 16:38 .
drwx------ 14 developer developer 4096 Aug  4 20:26 ..
-rwxrwxrwx  1 developer developer 2850 Aug  4 19:51 kube_reload.py
-rw-rw-r--  1 developer developer 8303 Aug  5 16:38 rap.log
-rw-rw-r--  1 developer developer 8345 Aug  5 16:38 rock.log

成功生成对应日志文件

问题原因及解决方法

核心原因

远程执行时,脚本的工作目录不是你预期的~/deekly/。SSH远程执行命令时,默认工作目录是用户的home目录(/home/developer),而不是脚本所在的~/deekly/。所以日志文件其实生成在了/home/developer/目录下,而不是~/deekly/里,你没找到而已。

解决方法

有两种简单的修复方式:

  1. 修改远程执行命令,先切换到脚本目录再执行
    修改check_radio里的SSH命令:

    sp.Popen(f'ssh developer@radio1 "cd ~/deekly && python3 kube_reload.py {stream}"', shell=True).communicate()
    

    用双引号把命令包起来,先cd到脚本所在目录再执行。

  2. 修改kube_reload.py,指定日志文件的绝对路径
    在脚本开头定义日志目录的绝对路径,比如:

    LOG_DIR = '/home/developer/deekly/'
    

    然后在写日志的地方改成:

    with open (f'{LOG_DIR}{arg}.log', 'w') as log:
    

    这样不管工作目录在哪,都会把日志写到指定的绝对路径下。

运维优化建议

  1. 避免使用eval():input_nums()里的eval(i)存在安全风险,换成int(i)即可,因为输入的是数字。
  2. 日志文件按时间命名:避免同名日志被覆盖,比如用f"{arg}_{datetime.datetime.now().strftime('%Y%m%d_%H%M%S')}.log"来命名。
  3. 加入错误处理:当前脚本里sp.run()没有处理异常,比如kubectl logs可能因为Pod不存在失败,应该添加try-except块捕获并记录错误。
  4. 用systemd定时器替代Cron(可选):如果是Linux系统,systemd定时器比Cron更灵活,支持秒级调度,还能记录执行日志。
  5. 日志集中管理:把Pod日志和脚本执行日志收集到ELK或Promtail+Loki里,方便后续排查问题,不用登录服务器找日志。
  6. Pod健康检查交给K8s自身:可以给Pod配置livenessProbe和readinessProbe,让K8s自动重启不健康的Pod,减少自定义脚本的维护成本。
  7. 学习Kubernetes API:长期来看,直接调用K8s API比执行kubectl子进程更可靠、高效,也更容易捕获错误,是DevOps转型的必备技能。

内容的提问来源于stack exchange,提问作者Deekly

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 04:55:55