Docker容器停止后GPIO引脚仍开启,如何优雅终止容器内Python程序?
Docker容器终止后GPIO LED保持点亮的解决办法
我在Docker容器中运行一个控制GPIO LED的Python脚本,使用gpiozero库。脚本在容器内运行正常,但执行docker stop强行停止容器后,LED始终保持点亮状态。本地直接运行脚本时,按Control+C终止程序,LED能正常熄灭。
现有代码
Python脚本(bread_pi.py)
from gpiozero import PWMLED from gpiozero import LEDBoard from time import sleep leds = LEDBoard(12, 16) freq = 1 for led in leds: led.on() sleep(1000) for led in leds: led.off()
Dockerfile
from arm64v8/python:3.10-alpine3.15 RUN pip install gpiozero RUN mkdir /app COPY bread_pi.py /app/bread_pi.py WORKDIR /app CMD ["python3", "bread_pi.py"]
问题原因
docker stop默认先发送SIGTERM信号给容器内的主进程,等待10秒后发送SIGKILL强制终止。你的Python脚本未处理SIGTERM信号,进程被强制杀死时,gpiozero来不及执行GPIO引脚的清理操作。而本地Control+C会触发SIGINT信号,gpiozero默认会处理该信号并自动关闭引脚。
解决办法
1. 修改Python脚本,添加信号处理逻辑
在脚本中捕获SIGTERM和SIGINT信号,触发LED关闭的清理操作:
from gpiozero import LEDBoard from time import sleep import signal import sys leds = LEDBoard(12, 16) def cleanup(signal_num, frame): """处理终止信号,关闭所有LED""" print("收到终止信号,正在关闭LED...") leds.close() # 一次性关闭所有LED,替代逐个off() sys.exit(0) # 注册信号处理函数 signal.signal(signal.SIGINT, cleanup) # 处理Control+C的SIGINT signal.signal(signal.SIGTERM, cleanup) # 处理docker stop的SIGTERM # 点亮LED for led in leds: led.on() try: sleep(1000) finally: # 正常结束时也执行清理 leds.close()
2. 确保Docker主进程能接收信号
你的Dockerfile已经使用了exec形式的CMD(["python3", "bread_pi.py"]),这会让Python进程成为容器的PID 1,能直接接收Docker发送的信号。如果使用shell形式(如CMD python3 bread_pi.py),PID 1是shell进程,信号会被拦截,Python进程无法收到,所以要保持exec形式。
3. 可选:调整docker stop的等待时间
如果清理操作很快,可以缩短等待时间,避免不必要的10秒等待:
docker stop -t 2 <容器名或ID>
该命令会让Docker等待2秒后再发送SIGKILL,足够脚本完成LED关闭操作。
内容的提问来源于stack exchange,提问作者Sterling
相关产品推荐
相关产品推荐

