02 · 重建与修复手册(新服务器 playbook)
用途:下次在新机器上把整套东西重新搭起来,并逐步验证 ,避免再出现"四层连环故障"。
标注:【已验证】 = 2026-10-21 在真机上跑通过;【未验证】 = 依据 DRfC 源码推导,首次执行需留意。
配套:
01-事件与根因复盘.md(为什么有这些步骤)、04-源码与配置存档.md(要抄的代码)。
0. 开工前先定 5 件事
| # | 决策 | 建议 | 理由 |
|---|---|---|---|
| 1 | 要不要 GPU | 要。至少 T4 / 2080 级、8GB+ 显存 | 原机器 4 vCPU 无 GPU,而节奏表按 GPU 45min/轮设计,CPU 上 180 episodes 跑不满 → 每轮白烧 1 小时【已证实】 |
| 2 | swarm 还是 compose | 单机就 swarm (DR_DOCKER_STYLE=swarm) |
与现有脚本一致;compose 要改 DR_MINIO_COMPOSE_FILE 等多处 |
| 3 | 数据放哪 | MinIO 数据目录挂独立数据盘,不与系统盘共用 | 原机器 40G 系统盘,一轮训练 +843M,整机释放即全丢 |
| 4 | 镜像从哪来 | 国内拉 Docker Hub 慢时,先 docker pull 到私有 registry,或 docker save/load 离线包 |
曾出现"镜像 tag 变 <none> 导致 swarm 拒绝调度" |
| 5 | 代码放哪 | 自研代码先建 git 仓库(本地或私有远端) | 这次整机释放,AutoTrainTools 差点永久丢失 |
新机规格参考(原机纪录) :Ubuntu 22.04.2 LTS / 4 vCPU / 15GB / 40GB,Docker 24.0.2,Python 3.10.6。
1. 系统准备【未验证:本次未重装系统】
bash
# 1.1 基础工具
apt update && apt install -y git curl jq unzip python3-pip python3-venv \
openssl net-tools htop ncdu
# 1.2 Docker
curl -fsSL https://get.docker.com | sh
systemctl enable --now docker
docker version # 期望:Client/Server 都有版本号
# 1.3 Docker Swarm(单节点)
docker swarm init --advertise-addr <本机内网IP>
docker node ls # 期望:本节点 Ready / Active / Leader
# 1.4 关键:placement label(DRfC 的 stack 硬依赖)
NODE=$(docker node inspect self --format '{{.ID}}')
docker node update --label-add Sagemaker=true $NODE
docker node update --label-add Robomaker=true $NODE
docker node inspect self --format '{{json .Spec.Labels}}'
# 期望:{"Robomaker":"true","Sagemaker":"true"}
# 1.5 关键:swarm 作用域 overlay 网络(compose 里声明为 external)
docker network create sagemaker-local -d overlay --attachable --scope swarm
docker network ls | grep sagemaker-local # 期望:sagemaker-local overlay swarm
# 1.6 AWS CLI(DRfC 用它访问 MinIO)
apt install -y awscli || pip3 install awscli
aws --version
为什么 1.4 / 1.5 要单独做 :
bin/init.sh里也会做这两件事,但它同时会重建网络、重置 env、重新 pull 镜像,属于破坏性操作。手动做这两步可以反复执行,不会误删东西。
2. 部署 DRfC 框架【部分已验证:源可用;安装步骤未在新机验证】
bash
# 2.1 拿代码(三选一)
# a) 本地已有副本(推荐,省流量):把 E:\Deepracer\deepracer-for-cloud 打包上传
# b) 官方仓库
git clone https://github.com/aws-deepracer-community/deepracer-for-cloud.git
# c) 与服务端同版本(当时是 v5.1.0-4-g6ac72fd)
cd deepracer-for-cloud && git checkout v5.1.0
# 2.2 放到约定路径(脚本里写死了 /home/rambo)
mkdir -p /home/rambo
mv deepracer-for-cloud /home/rambo/
# 2.3 配 system.env(部署级)------ 完整内容见 04 文档
cd /home/rambo/deepracer-for-cloud
cp system.env system.env.bak
# DR_CLOUD=local
# DR_DOCKER_STYLE=swarm
# DR_SAGEMAKER_IMAGE=5.1.0-cpu ← 有 GPU 改成 5.1.0-gpu
# DR_ROBOMAKER_IMAGE=5.1.0-cpu-avx2 ← 有 GPU 改成 5.1.0-gpu
# DR_COACH_IMAGE=5.1.0
# DR_MINIO_IMAGE=RELEASE.2023-06-23T20-26-00Z ← 本地固定 tag,不能 pull latest
# DR_LOCAL_S3_BUCKET=bucket
# DR_LOCAL_S3_PROFILE=minio
# DR_WORKERS=1
# 2.4 配 run.env(实验级)------ 完整内容见 04 文档
# DR_WORLD_NAME=reinvent_base
# DR_LOCAL_S3_MODEL_PREFIX=reinvent_base-10000
# DR_LOCAL_S3_PRETRAINED=False
# DR_EVAL_NUMBER_OF_TRIALS=3
# ★ term_cond_max_episodes 在 hyperparameters 模板里(CPU 上建议 30~50)
# 2.5 目录与 S3 凭据
mkdir -p data/minio/bucket custom_files log
aws configure --profile minio # 填任意 AccessKey/Secret,region=us-east-1
# (bin/init.sh 也会用 openssl rand 自动生成并写入该 profile)
# 2.6 Python 依赖
python3 -m venv /root/.virtualenvs/deepracer
source /root/.virtualenvs/deepracer/bin/activate
pip install -r requirements.txt
pip install imap-tools beautifulsoup4 glob2 openpyxl matplotlib pandas numpy
deactivate
3. 恢复自研 tools【代码需从 04 文档抄】
目标目录结构(脚本里的绝对路径都指向这里):
/home/rambo/tools/
├── AutoTrainTools/
│ ├── AutomaticSignal.py ← 主控状态机(04 有 ~95% 骨架)
│ ├── DeepracerFunction.py ← 业务函数库(04 有 ~80%)
│ ├── reward_function_define.py ← 奖励算法(04 近乎全文)
│ ├── reward_function_format.py ← 奖励模板(需重写,接口见 04)
│ ├── model_metadata.json ← 模板(04 全文)
│ ├── hyperparameters.json ← 模板(04 全文)
│ ├── __init__.py
│ └── log/ ← 运行时自动创建
├── CalculateLine/ ← 本地 E:\Deepracer\Deepracer\CalculateLine 可直接上传
├── Competition/ ← 同上
├── bashAPI.sh ← Shell 状态 API(04 有 ~90%)
├── init.sh ← Shell 函数库(04 有 ~60%)
├── HouseKeeping.sh ← 每日清理(04 有 ~30%,其余按功能重写)
├── APIFunction.py ← 邮件/日志/IO(04 全文)
├── receiveMail.py ← 邮件指令入口(04 全文,**建议不要启用**)
├── UserDefineFunction.py ← 几何库(Deepracer\CalculateLine\UserDefineFunction.py 有)
└── LICENSE
3.1 环境变量(每个登录 shell 生效)
bash
cat > /etc/profile.d/deepracer.sh <<'EOF'
#!/usr/bin/bash
export WORKON_HOME=/root/.virtualenvs
export TOOL_HOME=/home/rambo/tools
export TOOL_LOG=/home/rambo/tools/AutoTrainTools/log
export DR_HOME=/home/rambo/deepracer-for-cloud
export DR_BUCKET=$DR_HOME/data/minio/bucket
EOF
chmod +x /etc/profile.d/deepracer.sh
原文件里还有
virtualenvwrapper包装和source $TOOL_HOME/init.sh自动加载,属于便利性封装;最小可用只需上面 5 个变量。
3.2 可执行权限
bash
chmod +x /home/rambo/tools/*.sh /home/rambo/deepracer-for-cloud/*.sh
4. 启动 / 修复流程(本次实战验证过的顺序)
每一步都有"期望输出"。不满足期望就别往下走,否则后面的现象会像另一起故障。
Step 1 · swarm 健康
bash
docker info 2>&1 | grep -A4 -i '^ *Swarm:'
期望 :Swarm: active + Is Manager: true。不是 → 做第 5 节"swarm 重建"。
Step 2 · 网络与 label
bash
docker network ls | grep sagemaker-local
docker node inspect self --format '{{json .Spec.Labels}}'
期望 :sagemaker-local overlay swarm;{"Robomaker":"true","Sagemaker":"true"}。
缺哪个补哪个(1.4 / 1.5 的命令)。
Step 3 · 镜像齐全
bash
docker images | grep -E 'deepracer|minio'
期望 :4 个镜像都有非 <none> 的 tag 。
是 <none> → docker tag <IMAGE_ID> <repo>:<tag>(别指望 swarm 自动 pull)。
Step 4 · 起 MinIO
bash
cd /home/rambo/deepracer-for-cloud
source /etc/profile.d/deepracer.sh
source bin/activate.sh # 会自动 docker stack deploy ... s3
docker service ls | grep s3_minio
nc -zv 127.0.0.1 9000
期望 :s3_minio 1/1 + 9000 端口通。
0/1 → docker service ps s3_minio --no-trunc,看 ERROR 列(多为 No such image)。
Step 5 · 起训练栈
bash
dr-start-training -w # ⚠ -w = 清空 s3://bucket/<MODEL_PREFIX>!
docker service ls
期望 :deepracer-0_rl_coach / deepracer-0_robomaker 都是 1/1(首次可能先 0/1,等 1-2 分钟)。
rl_coach 起不来 → docker service logs deepracer-0_rl_coach --tail 30,最常见是连不上 http://minio:9000。
Step 6 · 确认 algo-1 出现(这一步才算真在训练)
bash
docker ps --format '{{.Names}} | {{.Status}}' | grep algo
/home/rambo/tools/bashAPI.sh getDRFCode
期望 :有 tmpXXXX_algo-1-XXXX_1 在跑;状态码 1110 。
1000 → algo 未起(看 rl_coach 日志);0110 → robomaker 掉了(docker service update --force deepracer-0_robomaker)。
Step 7 · 挂上自动化
bash
crontab -e
# */1 * * * * /home/rambo/deepracer-for-cloud/keepAlive.sh
# 00 00 * * * /home/rambo/tools/HouseKeeping.sh
tail -f /home/rambo/tools/AutoTrainTools/log/$(date +%F).log
期望 :出现 2.upload-custom-files → 3. code is [1110] → 3.1 training 3600s, in sleep。
Step 8 · 前 10 分钟观察点
bash
uptime # load 应 4~8;接近 0 说明没在仿真
top -bn1 | head -8 # 应看到 gzserver 吃满 1 核
docker logs --tail 20 $(docker ps -q -f name=algo)
期望 :saved intermediate frozen graph: .../model_0.pb、[s3] Successfully uploaded .ready。
5. 故障时的定向修复(本次实战路径)
5.1 Swarm 重建(拆房子级操作,先备份)
bash
mkdir -p /root/backup
tar -czf /root/backup/swarm-state-$(date +%Y%m%d-%H%M%S).tgz -C /var/lib/docker swarm
docker swarm leave -f
docker swarm init --advertise-addr <内网IP>
# 重建后三件事必须补齐,缺一不可:
NODE=$(docker node inspect self --format '{{.ID}}')
docker node update --label-add Sagemaker=true $NODE
docker node update --label-add Robomaker=true $NODE
docker network create sagemaker-local -d overlay --attachable --scope swarm
leave -f 会删掉:swarm 作用域网络、节点 label、集群成员关系。这三样全要重建。
5.2 服务起来了但 0/1
bash
docker service ps <svc> --no-trunc # 只有这个能看到 Rejected 原因
| ERROR | 处置 |
|---|---|
No such image: minio/minio:latest |
docker tag <img_id> minio/minio:latest |
| 无 ERROR 但一直 0/1 | 查 label 是否齐全 |
| 容器反复重启 | docker service logs <svc> 看业务报错 |
5.3 rl_coach 报 EndpointConnectionError
bash
docker service ls | grep s3_minio # 必须 1/1
nc -zv 127.0.0.1 9000
docker exec <minio容器> sh -c 'ls /data'
MinIO 没起来或网络没建 → 回到 Step 4。
5.4 robomaker 报 Master node could be dead / exit 143
顺序错了:robomaker 依赖 rl_coach 的 ROS master。正确顺序:
bash
docker service update --force deepracer-0_rl_coach # 先
sleep 30
docker service update --force deepracer-0_robomaker # 后
6. 必须补的巡检(这次事故的直接产物)
教训:证书过期 3 年无人发现,重启才暴露。没有巡检的系统等于没上监控。
建议写 tools/HealthCheck.sh,挂 cron 每天一次(或每小时),检查项与告警条件:
| 检查项 | 命令 | 告警条件 |
|---|---|---|
| swarm 状态 | `docker info | grep 'Swarm:'` |
| 节点证书剩余天数 | openssl x509 -in /var/lib/docker/swarm/certificates/swarm-node.crt -noout -enddate |
< 30 天 |
| 节点 label | docker node inspect self --format '{``{json .Spec.Labels}}' |
缺 Sagemaker/Robomaker |
| 网络存在 | `docker network ls | grep sagemaker-local` |
| 服务 replicas | docker service ls --format '{``{.Name}} {``{.Replicas}}' |
任一不是 1/1 |
| 训练状态码 | bashAPI.sh getDRFCode |
连续 N 次不是 1110/1001 |
| 自动化进程 | `ps -eo cmd | grep -c AutomaticSignal` |
| 磁盘 | `df -h / | tail -1` |
| 数据备份 | 检查最近备份时间戳 | > 7 天 |
复用现成的 APIFunction.sendmail(subject, content) 发邮件即可。
7. 数据备份(血的教训)
原机器整机释放 → data/minio/bucket(843M 模型/轨迹/指标)、/home/rambo 全部代码、tools.tar.zip 一起消失。
"同一台机器上的备份等于没有备份。"
新机器的最低要求:
bash
# 7.1 代码进 git(最重要,注意排除大目录)
cd /home/rambo/tools && git init && cat > .gitignore <<'EOF'
__pycache__/
*.pyc
AutoTrainTools/log/
CalculateLine/image/
CalculateLine/routes/
EOF
git add -A && git commit -m "init: restore AutoTrainTools"
git remote add origin <你的私有仓库> && git push -u origin master
# 7.2 MinIO 数据定期打包到**本机之外**
tar -czf /mnt/backup/bucket-$(date +%F).tgz -C /home/rambo/deepracer-for-cloud/data/minio bucket
# /mnt/backup 必须是独立云盘 / OSS 挂载点 / rsync 到另一台机器
# 7.3 关键产物单独取回(模型 .pb 才是最终成果)
aws --profile minio --endpoint-url http://localhost:9000 \
s3 sync s3://bucket/<MODEL_PREFIX>/model /mnt/backup/model-<MODEL_PREFIX>/
注意 gzip 压缩比 :bucket 里大量是 CSV/JSON 文本,压缩后大约 1/8 ~ 1/10(843M → 100M 左右),适合打包。
8. 优化待办(重建时直接做掉,不要先复现故障)
P0 · 稳定性(必须在第一次训练前完成)
-
handler.sh不要吞 stderr
现状:coproc startTrain { dr-start-training -w ; }→ 报错全丢
改法:coproc startTrain { dr-start-training -w >>$DR_HOME/log/dr-actions.log 2>&1; } -
AutomaticSignal.py失败策略改成退避 + 单次告警
现状:连续 30 次失败 →sendmail+sys.exit()→ cron 1 分钟内重启 → 每 30 分钟一封邮件死循环
改法:指数退避 + 只在"状态发生变化"时发一封 + 用一个state文件记录是否已告警 - 加
HealthCheck.sh+ cron(第 6 节清单)
P1 · 效果(决定训练有没有意义)
-
term_cond_max_episodes按算力设定:CPU 上 30~50;GPU 上可保持 180 - 启用完整几何奖励函数 :确认
generateFormatFile()用Py/Py4/<track>-<N>.py的 waypoint,而不是占位版 -
handleTraining的相对路径改成绝对路径 :rootFoler已经在全局定义,直接拼绝对路径,避免依赖 CWD
P2 · 安全与整洁
- 邮箱授权码出源码(改环境变量 / 权限 600 的配置文件)
-
eval(readFile(json))→json.loads -
receiveMail.py(邮件当指令入口)默认不启用 - 删除死代码
killAutomaticIterate(引用的AutomaticIterate.py并不存在) - SSH:仅密钥认证 + 安全组按需放行(注意 :本次就是因为把 IP 锁死 + ISP 换 IP 导致
Connection timed out,建议放通网段或加动态 IP 更新脚本)
9. 附录 · 一键整备脚本骨架【未验证,首次运行请分步执行】
bash
#!/bin/bash
# bootstrap.sh ------ 新机器一次性整备(建议逐段执行,不要整体盲跑)
set -euo pipefail
INNER_IP=${1:?用法: bootstrap.sh <内网IP>}
DR_HOME=/home/rambo/deepracer-for-cloud
TOOL_HOME=/home/rambo/tools
echo "== 1. 基础工具 =="
apt update && apt install -y git curl jq unzip python3-pip python3-venv openssl net-tools
echo "== 2. Docker + Swarm =="
curl -fsSL https://get.docker.com | sh
systemctl enable --now docker
docker info | grep -q 'Swarm: active' || docker swarm init --advertise-addr "$INNER_IP"
echo "== 3. placement label =="
NODE=$(docker node inspect self --format '{{.ID}}')
docker node update --label-add Sagemaker=true "$NODE"
docker node update --label-add Robomaker=true "$NODE"
echo "== 4. overlay 网络 =="
docker network ls | grep -q sagemaker-local || \
docker network create sagemaker-local -d overlay --attachable --scope swarm
echo "== 5. 目录 =="
mkdir -p "$DR_HOME"/data/minio/bucket "$DR_HOME"/custom_files "$DR_HOME"/log "$TOOL_HOME"
echo "== 6. 环境变量 =="
grep -q TOOL_HOME /etc/profile.d/deepracer.sh 2>/dev/null || cat > /etc/profile.d/deepracer.sh <<'EOF'
#!/usr/bin/bash
export WORKON_HOME=/root/.virtualenvs
export TOOL_HOME=/home/rambo/tools
export TOOL_LOG=/home/rambo/tools/AutoTrainTools/log
export DR_HOME=/home/rambo/deepracer-for-cloud
export DR_BUCKET=$DR_HOME/data/minio/bucket
EOF
chmod +x /etc/profile.d/deepracer.sh
echo "== 7. Python venv =="
python3 -m venv /root/.virtualenvs/deepracer
/root/.virtualenvs/deepracer/bin/pip install -q --upgrade pip
/root/.virtualenvs/deepracer/bin/pip install -q imap-tools beautifulsoup4 glob2 openpyxl matplotlib pandas numpy
echo "== 8. 校验 =="
docker info | grep -A3 'Swarm:'
docker node inspect self --format '{{json .Spec.Labels}}'; echo
docker network ls | grep sagemaker-local
echo "OK ------ 接下来手工: 拷贝 deepracer-for-cloud / tools,配 system.env+run.env,然后走 02 文档第 4 节"
10. 第二次实战(2026-10-21 04:00 起)新增的修复项
这次是在"2023 年镜像 + 同 IP 新实例"上重做,多踩了 4 个上次没遇到的坑,全部已修,下次重建请直接带上。
10.1 开机瞬间就要防数据被清(最高优先级)
现象 :实例一启动,镜像里的 crontab 就已经有 */1 * * * * keepAlive.sh,立刻拉起 AutomaticSignal.py。而它第一步就是 dr-start-training -w。
为什么第一次没清 :minio 还没起 → aws s3 ls s3://bucket/<prefix> 失败 → S3_FILES=0 → 跳过 WIPE。
为什么后来清了 :我把 minio 拉起来后的下一分钟 ,WIPE 就真的执行了 → reinvent_base-10000 从 843M 变 20K(丢 274M)。
正确顺序(务必照做):
bash
# 1. 先停掉看门狗
crontab -l > /root/backup/crontab.bak
crontab -l | sed 's|^\*/1 \* \* \* \* /home/rambo/deepracer-for-cloud/keepAlive.sh|#&|' | crontab -
pkill -f 'AutomaticSignal.py'; pkill -f 'keepAlive.sh'; pkill -f 'TRGHND.sh'
# 2. 备份数据
nohup tar -czf /root/backup/bucket.tgz -C /home/rambo/deepracer-for-cloud/data/minio bucket &
# 3. 再修 swarm / network / label / minio
# 4. 最后才恢复 cron
sed -i 's|^#\(\*/1 \* \* \* \* .*keepAlive.sh\)|\1|' <(crontab -l) | crontab -
教训:先把会写数据的进程全部停掉,再动基础设施。 上次是在"服务已停"的机器上修,所以没遇到;这次是在"自动化一直活着"的机器上修,就被反咬了一口。
10.2 TRGHND.sh 会 100% 占一个核
现象:
PID 23768 root bash TRGHND.sh %CPU 93~100 累积 0:56
原因 :keepAlive.sh 用 coproc TRGHND { bash TRGHND.sh ;} 启动,cron 环境下没有 tty,stdin 立刻 EOF →
while true; do read; done 里 read 立即返回失败 → 变成纯忙循环。
修复(改成不依赖 stdin,信号照样能打断 sleep):
bash
while true
do
sleep 1
done
10.3 keepAlive.sh 的"count ≠ 1 就全杀"会自我拆台
现象 :keepAlive.log 反复出现
[checkTRGHND],count is [2],jobs [23768 25092]
[checkTRGHND],jobs [27184 27189] ← 新起的也随即消失
原因 :用 coproc 启动的 TRGHND 是 keepAlive 的子进程,keepAlive 退出时被带走;下一分钟又判定 count=0 再起一个,而 count>1 分支会连健康的实例一起 kill -9。
修复 :改为完全脱离父进程启动(这样 count 才能稳定为 1):
bash
# 旧: coproc TRGHND { bash TRGHND.sh ;}
setsid nohup bash TRGHND.sh >/dev/null 2>&1 < /dev/null &
10.4 Step 3 的重试策略会每 60 秒 WIPE 一次
现象:
[04:13:23] 3.Preparation Training
[04:14:23] 3. code is [0110] ← robomaker 还在启动
[04:14:23] 3.Preparation Training again -[1/30] ← 立刻又发 start-training
原因 :robomaker 从创建到 Running 需要 60~90 秒 ,这段时间状态码是 0110/1000;而原逻辑是 if code != '1110': 重发 start-training → 每次重发都带 -w → 每 60 秒清空一次模型目录并重启整套。这正是 274M 被迅速清空的放大器。
修复 :只有在"什么都没起(0000)"时才重发;只要有容器在跑就认为部署中,直接继续等。
python
if code == '0000': # 原: if code != '1110'
log(3, f'3.Preparation Training again -[{i+1}/30]')
sendSignal("35", 60)
else:
break
10.5 本次实际改动文件汇总
| 文件 | 改动 | 备份 |
|---|---|---|
AutoTrainTools/AutomaticSignal.py |
①/60→/30 ②去掉未定义的 j ③Step3 重试条件改 == '0000' |
.bak.20261021-040955 |
TRGHND.sh |
while read → while sleep 1 |
TRGHND.sh.bak* / .bak2* |
keepAlive.sh |
coproc → setsid nohup ... &(2 处) |
keepAlive.sh.bak* |
minio/minio:latest |
悬空 tag 重新打(镜像 a5d29c2476d0) |
------ |
10.6 ★启动握手文件 ip/:-w 重试会把它们删掉
背景:DRfC 的启动握手是「algo-1 起 Redis → 把 IP 写到 S3 → robomaker 轮询拿到 IP 才连上去开仿真」。
ip/ 下必须有三个对象(2023 年成功跑的参照物在 reinvent_base-001/ip/):
| 对象 | 内容 | 大小 |
|---|---|---|
ip.json |
{"IP": "10.0.1.23"}(algo-1 的容器 IP) |
19 B |
hyperparameters.json |
本轮超参 | ~340 B |
done |
字符串 done |
4 B |
故障表现:
bash
bashAPI.sh getDRFCode # → 1110 ← 骗子!三个容器都在
bashAPI.sh getEpisode # → 0 ← 一圈都没跑
docker service logs deepracer-0_robomaker
# Waiting for SageMaker Redis server IP: Time elapsed: 1065 seconds
aws ... s3 ls s3://bucket/<prefix>/ip/ # → 空(目录都不存在)
根因 :dr-start-training -w 里的 aws s3 rm --recursive s3://bucket/<prefix> 删的是整个前缀 ,包括 algo-1 刚写好的 ip/。而 Step3 的旧重试逻辑(if code != '1110')会在 robomaker 启动的 60~90 秒里再发一次 -w → 握手文件被抹掉 → robomaker 永远等不到。
这正是 10.4 那条补丁要解决的:只要打过 Step3 补丁(仅 0000 才重发),就不会再触发。
补救(不重启整个训练):
bash
AL=$(docker ps --format '{{.Names}}' | grep algo | head -1)
IP=$(docker inspect $AL --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}')
printf '{"IP": "%s"}' "$IP" > /tmp/ip.json
cp /home/rambo/deepracer-for-cloud/custom_files/hyperparameters.json /tmp/hp.json
printf 'done' > /tmp/donemarker
S3="aws --profile minio --endpoint-url http://localhost:9000 s3"
$S3 cp /tmp/ip.json s3://bucket/<MODEL_PREFIX>/ip/ip.json
$S3 cp /tmp/hp.json s3://bucket/<MODEL_PREFIX>/ip/hyperparameters.json
$S3 cp /tmp/donemarker s3://bucket/<MODEL_PREFIX>/ip/done
docker service update --force deepracer-0_robomaker # 它已 exit 143,必须重启
判断"到底有没有在训练"的可靠信号(别只看 1110):
bash
bashAPI.sh getEpisode # 应逐渐增长
curl -s -m 4 "http://127.0.0.1:8080/stream?topic=/racecar/deepracer/kvs_stream" | wc -c
# 健康时 6 秒能收 ~2.4 MB;没在训练时只有 22 字节
完整时序与证据见
changelog/2026-10-21-cpu-instance-rebuild.md第 10 节。
10.7 ★KEEP_MODEL:从根上避免"重启训练就清空历史"
10.6 的竞态根源是 -w 会清空整个前缀。彻底解决不是"记得先备份",而是把这层语义做成开关。
新版 handler.sh (docs/scripts/handler.sh,由 restore.sh 第 6d 步自动安装)在收到 35 号信号时:
KEEP_MODEL=1(默认)
└─ aws s3 mv s3://bucket/<prefix>/ → s3://bucket/_archive/<prefix>-<时间戳>/ --recursive
├─ 成功 → dr-start-training -w (前缀已空,-w 删不到东西)
└─ 失败 → 中止启动 + 写日志 (宁可不训练,也不丢数据)
KEEP_MODEL=0
└─ 原行为:直接 -w
开关文件 /home/rambo/tools/auto.env(restore.sh 第 6e 步写入):
ini
KEEP_MODEL=1 # 1=先归档;0=直接清空
KEEP_ARCHIVES=3 # 保留最近几份归档;<=0 不清理
同时修掉的 P0 :原版 6 个分支的 coproc 全都没有重定向,dr-* 的 stdout/stderr 全丢(45 分钟静默的元凶)。新版统一 >> log/dr-actions.log 2>&1,出问题第一时间看这个文件。
归档清理与恢复:
bash
# 现有归档
aws --profile minio --endpoint-url http://localhost:9000 s3 ls s3://bucket/_archive/
# 恢复某一份(先停训练)
dr-stop-training
aws --profile minio --endpoint-url http://localhost:9000 s3 cp \
s3://bucket/_archive/reinvent_base-10000-20261021-041455/ \
s3://bucket/reinvent_base-10000/ --recursive
磁盘注意:每份归档 ≈ 当前模型前缀的体积(实测 ~270MB),
KEEP_ARCHIVES=3大约占 800MB。