本节摘要:值班手册第三页——钻进箱子检修。exec 开新会话是首选通道,attach 接原会话要慎用;本节讲清两者的机制差异、单次执行与交互shell两种用法,以及极简镜像里"连 shell 都没有"的应对。
应用在箱子里行为异常,第一反应往往是"进去看看"。进去有两条路,机制完全不同,选错路会闹出事故——最有名的事故是:有人在 attach 会话里按了退出组合键,把好好的容器直接带走了。
exec:开新会话。 在运行中的容器里启动一个新进程(通常是 shell)。它像派一名检修工从舱门进去——检修工离开(退出 shell),箱子毫发无损。这是日常首选。
attach:接原会话。 把你的终端直接接到容器主进程的输入输出上。它像把你的手直接接到岸桥操纵杆上——你的一举一动都作用在主进程上,断开方式的任何闪失都可能终结主进程。这是要慎用的通道。
先跑一条最简单的单次执行感受 exec:
# 起一只测试箱子 docker run -d --name lab-shell nginx:1.25-alpine # 单次执行:在容器里跑一条命令,拿回输出,会话即结束 docker exec lab-shell hostname # 输出:c3f1a2b4d5e6 <- 容器自己的主机名(短编号) docker exec lab-shell cat /etc/os-release # PRETTY_NAME="Alpine Linux v3.20" <- 箱内的世界,与宿主机无关
交互式进入的完整写法,两个标志参数搭档:-i 保持标准输入开放,-t 分配一个伪终端(让命令提示符、颜色、行编辑都正常工作):
# 进入容器获得一个交互 shell docker exec -it lab-shell sh # /# <- 这是容器内的提示符 /# ps aux # PID USER COMMAND # 1 root nginx: master process <- 主进程 # 28 root sh <- 你派进来的检修工 /# exit # (退出的是你派进来的 shell,容器照常运行) # 验证容器没受影响 docker ps --filter name=lab-shell --format "{{.Status}}" # Up 2 minutes
-u 参数指定执行身份,是安全排查的常用开关——以非 root 身份跑一条命令,验证文件权限问题:
# 以指定用户身份在容器内执行 docker exec -u 1000 lab-shell touch /tmp/test-file docker exec -u 1000 lab-shell ls -la /tmp/test-file # -rw-r--r-- 1 1000 1000 0 ... /tmp/test-file
exec 的边界也要清楚:它只能进运行中的容器。停止的箱子进不去——想翻检已停止容器的文件系统,把它的文件系统导出来看,或者用一个挂载了同样数据卷的临时箱子间接检查(第 5 章学了卷之后会顺手得多)。
与"进去"相对的还有"取出来":把容器里的文件拷到宿主机,用 cp 命令即可,不必进箱:
# 从容器里拷文件出来(容器:路径 宿主路径) docker cp lab-shell:/usr/share/nginx/html/index.html ./index.html # 反向也行:把宿主机的文件塞进容器(临时救急用,正式交付还是走镜像) docker cp ./fixed.conf lab-shell:/etc/nginx/conf.d/default.conf # 注意:cp 进容器的改动落在可写层,拆箱即失——救急可用,不可依赖
attach 把你的终端接到主进程上。先弄清它的真实用途——看主进程的前台输出、参与它设计上就要交互的会话(比如当初用 -it 起的交互容器重新接管),而不是当 shell 用:
# 起一只前台输出的箱子(nginx 日志走 stdout,attach 能看到实时日志流) docker run -d --name lab-attach nginx:1.25-alpine # 接上主进程:实时看到 nginx 的日志输出 docker attach lab-attach # /docker-entrypoint.sh: Configuration complete; ready for start up # ...(Ctrl-C 的行为取决于 --sig-proxy,默认会把停止信号转发给容器) # 安全的 detach 方式:不杀容器地脱开 # 依次按键:Ctrl-p 然后 Ctrl-q
attach 的风险清单必须背下来:默认按 Ctrl-C 是向容器发停止信号(容器直接停);脱开的正确姿势是 Ctrl-p、Ctrl-q 组合;如果容器当初不是交互式起的(没有 -it),attach 上了也没有可输入的东西,还可能因回显混乱刷屏。规则一句话:看日志用 logs,进箱子用 exec,attach 留给交互容器的重新接管。
3.4 节瘦身时提过,scratched 或 distroless 类极简镜像里根本没有 shell,exec -it 进去会报错——这是瘦身的代价与设计的意图(攻击者进不来,你也进不去)。应对方式是旁路检修:
# 尝试进入极简镜像会失败(错误示例) docker exec -it slim-app sh # OCI runtime exec failed: exec: "sh": executable file not found in $PATH # 应对一:单次执行虽无 shell,但应用自带的诊断入口仍可用(若镜像提供) docker exec slim-app /app --version # 应对二:旁路挂卷检修——用一只带 shell 的临时箱子挂载同一数据卷检查(卷详见第 5 章) docker run --rm -it --volumes-from slim-app alpine sh # /# ls /data
"进不去"在安全视角反而是优点:终箱越小、部件越少,可被利用的攻击面越小。排查靠旁路手段与充分的日志外送,这是生产极简镜像运维的成熟范式。
进得去,还要看得懂。下一节:日志与体征——值班员的眼睛。