惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
D
Darknet – Hacking Tools, Hacker News & Cyber Security
N
News and Events Feed by Topic
N
News | PayPal Newsroom
SecWiki News
SecWiki News
P
Privacy International News Feed
T
Troy Hunt's Blog
Attack and Defense Labs
Attack and Defense Labs
N
News and Events Feed by Topic
L
LINUX DO - 热门话题
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Security Latest
Security Latest
AWS News Blog
AWS News Blog
S
Secure Thoughts
W
WeLiveSecurity
H
Heimdal Security Blog
T
Threat Research - Cisco Blogs
I
Intezer
Application and Cybersecurity Blog
Application and Cybersecurity Blog
S
Security @ Cisco Blogs
G
GRAHAM CLULEY
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Spread Privacy
Spread Privacy
L
Lohrmann on Cybersecurity
C
CERT Recently Published Vulnerability Notes
S
Security Affairs
Hacker News - Newest:
Hacker News - Newest: "LLM"
Google Online Security Blog
Google Online Security Blog
Cisco Talos Blog
Cisco Talos Blog
雷峰网
雷峰网
Cloudbric
Cloudbric
Y
Y Combinator Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园_首页
Hacker News: Ask HN
Hacker News: Ask HN
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Google DeepMind News
Google DeepMind News
Vercel News
Vercel News
云风的 BLOG
云风的 BLOG
Latest news
Latest news
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
D
Docker
Recent Announcements
Recent Announcements
博客园 - 【当耐特】
H
Help Net Security
博客园 - 司徒正美
TaoSecurity Blog
TaoSecurity Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
C
Check Point Blog
博客园 - 叶小钗

阿尔的代码屋 | 全栈技术笔记

在 Android Termux 环境下安装 Hermes Agent 的踩坑与完美解决实践 开发日志| 阿尔的代码屋 VS Code 连接 WSL 精确每 10 分钟掉线 排坑笔记 | 阿尔的代码屋 Android 模拟器代理联网与 No Internet WiFi 锁死排坑笔记 | 阿尔的代码屋 [object Object] typing_extensions 有用(四):使用 TypeIs 替代危险的 cast,做最严谨的类型收窄 | 阿尔的代码屋 GoRouter 结合 Isar 运行 Widget 测试并发/粘性线程死锁卡死排坑笔记 | 阿尔的代码屋 typing_extensions 有用(三):使用 Unpack 结合 TypedDict 给 **kwargs 装上透视眼 | 阿尔的代码屋 typing_extensions 有用(二):使用 @override 打造重构代码时的“防呆神器” | 阿尔的代码屋 Flutter 并发测试踩坑实录 - IsarCore 动态库下载冲突与 Widget 测试 HTTP 拦截全链路解决 | 阿尔的代码屋 typing_extensions 有用(一):使用 Self 终结继承时的类型推断灾难 | 阿尔的代码屋 基于 Cloudflare Pages 的纯前端 WebAssembly 应用自动化部署实践 | 开发日志 | 阿尔的代码屋 Patrol iOS 集成测试排坑实录 - xcodebuild exit code 70 全链路解决 | 阿尔的代码屋 Flutter E2E 测试从 integration_test 迁移到 Patrol - 实践笔记 | 阿尔的代码屋 Linux/macOS 下 micromamba 报错 Shard Index not available 与极度卡顿 排坑笔记 | 阿尔的代码屋 critical libmamba Shell not initialized micromamba报错 subprocess 无法修改父 Shell - 排坑笔记 | 阿尔的代码屋 VS Code Remote-SSH: 彻底告别重复输入密码 - 排坑笔记 | 阿尔的代码屋 Git 报警: inexact rename detection was skipped - 排坑笔记 | 阿尔的代码屋 解决群晖 NAS SSL 证书自动部署难题 | 阿尔的代码屋 Windows 下 Git error: fatal: refusing to work with credential missing host field - 排坑笔记 | 阿尔的代码屋 VS Code 调试 Python 第三方库源码的配置 - 开发技巧| 阿尔的代码屋 VS Code Remote Tunnels本地连接调试Kaggle GPU - 开发技巧| 阿尔的代码屋 Windows下Git error: open(xxxx) Filename too long - 排坑笔记 | 阿尔的代码屋 记录2026年零预约港卡开户实录避坑 告别孤岛:拥抱 MCP 协议,为大模型打造标准“USB 接口” - 大模型实战 08 完结篇 | 阿尔的代码屋 从 ReAct 到 Workflow:基于云端 API 构建事件驱动的智能体 - 大模型实战 07 额外篇 | 阿尔的代码屋 基于 LlamaIndex ReAct 框架手搓全自动博客监控 Agent - 大模型实战 07 | 阿尔的代码屋 在 Kaggle 上用 Unsloth 极速微调 Qwen3 - 大模型实战 06 | 阿尔的代码屋 大模型微调实战详解 - 大模型实战 05 | 阿尔的代码屋 基于 ChromaDB 打造工程级 RAG 系统 - 大模型实战 04 | 阿尔的代码屋 拆解 Transformers 原理与图解 - 大模型实战 03 | 阿尔的代码屋 云端炼丹房 2:Kaggle 上手指南 - 大模型实战 03预备 | 阿尔的代码屋 云端炼丹房:Google Colab 免费 GPU 上手指南 - 大模型实战 03预备 | 阿尔的代码屋 Open WebUI 部署与 RAG 实战 - 大模型实战 02 | 阿尔的代码屋
基于 VS Code 远程开发的 GPU Docker 容器自动清理方案实践 开发日志| 阿尔的代码屋
Algieba · 2026-06-02 · via 阿尔的代码屋 | 全栈技术笔记

1. 业务场景与核心需求

运行环境:

  • 操作系统:Ubuntu 22.04
  • 开发工具:VS Code Remote-SSH
  • 容器环境:Rootless Docker (非 root 用户权限运行)
  • 业务场景:GPU 服务部署与模型调试

核心需求:

  1. 自动释放:开发者下班合上电脑(物理断网)后,经过一段缓冲时间(例如 10 分钟),系统需自动停止该用户运行的 Docker 容器。
  2. 状态保持:在缓冲期内若用户重新连接网络,容器资源需保持运行,重置倒计时。
  3. 多开支持:支持用户同时开启多个 VS Code 窗口或 SSH 终端,只有当所有连接均断开时才触发倒计时。
  4. 常驻白名单:提供快捷指令,允许用户在特定情况下(如长时间训练任务)关闭自动清理功能。

2. 初步方案与局限性分析

初步思路:依赖 .bash_logout
最初的设计是在用户的 ~/.bash_logout 文件中添加清理逻辑。即在脚本中设定 sleep 600 (10分钟),随后执行 docker stop

遇到的问题:物理断网不触发注销流程
在实际测试中发现,当在终端手动输入 exit 时,容器能按预期被清理。但当直接合上笔记本电脑物理断网时,脚本完全未执行。

原因剖析:
通过检查服务器的 /etc/ssh/sshd_config,发现未配置 SSH 心跳检测 (#ClientAliveInterval 0)。物理断网属于异常掉线,操作系统完全依赖底层的 TCP KeepAlive 机制来判定连接断开。这一过程通常耗时 15 到 30 分钟,超时后系统会直接强制销毁 sshd 进程。这种非“优雅退出”的机制导致 .bash_logout 中的逻辑被彻底跳过。


3. 方案演进:引入后台守护进程 (Daemon)

既然无法在“退出时”触发,方案需转向“持续监控”模式。我们决定在用户登录时,静默启动一个轻量级的 Bash 守护进程,通过轮询统计用户的 sshd 会话数量来判断在线状态。

遇到的问题:Rootless Docker 守护进程失联
编写好监控脚本并通过 nohup 投入后台运行后,发现虽然触发了超时清理逻辑,但 docker ps -qdocker stop 命令执行失败,系统日志提示无法连接到 Docker 守护进程。

原因剖析:环境变量丢失
在 Rootless Docker 模式下,普通用户终端能够正常使用 docker 命令,是因为用户通过 SSH 登录时,系统自动为其分配了如 XDG_RUNTIME_DIR 等关键环境变量,指向了 /run/user/<uid>/docker.sock
而通过 nohup 和脱机运行的后台守护进程,脱离了用户的 Login Shell 上下文,导致这些特定环境变量丢失。Docker 客户端退化到去寻找默认的系统级 /var/run/docker.sock,从而引发权限或找不到文件的错误。


4. 最终实现方案

明确了所有限制条件后,最终落地的方案由两部分组成:注入了环境变量的独立守护进程脚本,以及 ~/.bashrc 中的控制逻辑。

步骤一:创建守护进程脚本

在用户根目录下创建 ~/.gpu_cleanup_daemon.sh 脚本。
注意:脚本开头的环境变量可通过在正常终端中运行 env | grep -E "DOCKER|XDG" 获取,需将 1002 替换为实际的用户 UID。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#!/bin/bash





export XDG_RUNTIME_DIR=/run/user/1002
export DOCKER_HOST=unix:///run/user/1002/docker.sock


RAW_TIME=${GPU_CLEANUP_GRACE_PERIOD:-10m}
case $RAW_TIME in
*m) GRACE_SEC=$((${RAW_TIME%m} * 60)) ;;
*h) GRACE_SEC=$((${RAW_TIME%h} * 3600)) ;;
*s) GRACE_SEC=${RAW_TIME%s} ;;
*) GRACE_SEC=$RAW_TIME ;;
esac

ELAPSED=0
CHECK_INTERVAL=10

while true; do

if [ -f "$HOME/.skip_gpu_cleanup" ]; then
ELAPSED=0
sleep $CHECK_INTERVAL
continue
fi


SESSION_COUNT=$(pgrep -u "${USER}" -x sshd | wc -l)

if [ "${SESSION_COUNT}" -gt 0 ]; then

ELAPSED=0
else

ELAPSED=$((ELAPSED + CHECK_INTERVAL))


if [ "$ELAPSED" -ge "$GRACE_SEC" ]; then
CONTAINER_IDS=$(docker ps -q)
if [ -n "${CONTAINER_IDS}" ]; then
docker stop ${CONTAINER_IDS}
fi


exit 0
fi
fi
sleep $CHECK_INTERVAL
done

赋予脚本执行权限:chmod +x ~/.gpu_cleanup_daemon.sh

步骤二:配置终端环境与快捷指令

~/.bashrc 尾部添加以下配置。除了静默启动守护进程外,还封装了开关指令供日常调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17





export GPU_CLEANUP_GRACE_PERIOD="10m"


alias gpu-keep-on="touch ~/.skip_gpu_cleanup && echo -e '\033[32m[Long-run Mode Enabled]\033[0m Your Docker containers will NOT be stopped upon disconnection.'"
alias gpu-keep-off="rm -f ~/.skip_gpu_cleanup && echo -e '\033[33m[Auto-Cleanup Mode Restored]\033[0m Your Docker containers will be automatically stopped after disconnection.'"
alias gpu-status="[ -f ~/.skip_gpu_cleanup ] && echo 'Current Mode: Long-running task (No cleanup)' || echo 'Current Mode: Auto-cleanup'"


if ! pgrep -u "${USER}" -f "gpu_cleanup_daemon.sh" > /dev/null; then
nohup bash ~/.gpu_cleanup_daemon.sh > /dev/null 2>&1 &
disown
fi

执行 source ~/.bashrc 使配置生效。


5. 总结与实践建议

  1. 实际资源释放延迟:由于 Ubuntu 默认依赖底层的 TCP 机制判断异常断线,实际的容器停止时间等于 TCP 释放延迟(约 15~30 分钟)+ 脚本缓冲时间(10 分钟)。这种物理延迟恰好提供了业务上的双重缓冲冗余。
  2. 数据安全性:采用 Rootless Docker 环境时,执行 docker ps -q 只能获取当前用户空间下的容器,因此直接进行 docker stop 操作是安全的,不存在误操作其他用户资源的风险。
  3. 资源占用极低:Bash 守护进程配合 10 秒级别的 sleep 轮询,对系统资源的消耗几乎为零。且完成清理任务后进程会自我销毁,避免了僵尸进程的累积。