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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 15:10:59