ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

docker compose up卡住?用run解决输入问题

docker compose up卡住?用run解决输入问题 docker compose up卡住用run解决输入问题问题现象最近在学习 Docker实战用 docker-compose 编排一个 Go 聊天室项目一个 server 容器一个 client 容器。执行dockercompose up-dserver# 创建并在后台运行server容器dockercompose up client# 直接在终端运行client容器明明创建成功了终端也正常打印出了提示语但是我在键盘上敲Y 程序完全没有反应就像卡死了一样 只能ctrlc返回容器状态查了一下也是正常的Up没有 Exited也没有报错就是死活不响应输入。解决方法然后我尝试了其他的开启方法当然也问了AI终于让我找到了一种可以运行的不要用up启动需要交互的容器改用run# 服务端后台运行dockercompose up-dserver# 客户端用run启动dockercompose run--rmclient启动后输入立刻生效问题解决为什么这样就可以了呢原理分析1. 程序在等什么标准输入 stdin我写的客户端程序需要读取键盘输入Go 代码里是这样写的varscannerbufio.NewScanner(os.Stdin)funcreadLine()(string,error){ifscanner.Scan(){// 程序阻塞在这里等待键盘输入returnscanner.Text(),nil}return,scanner.Err()}在 Linux 中每个进程启动时都有三个标准流文件描述符名称作用0stdin标准输入读取输入默认是键盘1stdout标准输出正常输出2stderr标准错误错误输出程序执行到读取 stdin 的代码时会阻塞挂起等待数据进来。所谓卡住其实就是进程在安安静静地等键盘输入——但数据根本送不到它那里。2. 容器里的 stdin 默认是断开的Docker 启动容器时 默认不会把宿主机的键盘连接到容器内进程的 stdin 。分两种情况后台运行up -d容器内进程的 stdin 会立即收到 EOF输入结束信号。Scanner读到 EOF 后程序直接退出所以你会看到容器状态是Exited。前台运行up不加 -dDocker 把容器的输出收集起来显示成日志但键盘输入 不会被路由给任何容器 。容器内进程的 stdin 既没有数据也没有 EOF就会永远阻塞在那里——这就是我遇到的卡住现象。数据流是这样的docker compose up:docker compose run client:有读者可能会问我敲的Y明明显示在屏幕上了啊注意 屏幕回显是你本机终端的行为 敲什么显示什么和容器有没有收到数据完全是两回事。你敲的字符进入了 compose 进程但 compose 在up模式下只负责聚合日志不转发输入字符被直接丢弃了。容器里的程序一个字符都没收到。3. 怎么判断当前是不是日志模式看输出有没有容器名 |这样的前缀一旦看到容器名 |前缀就说明当前是日志聚合视图键盘输入不会被转发。 这是最简单的判断方法。而docker compose run启动时输出是没有这个前缀的因为终端和容器是直接对接的。4. -i 和 -t 参数的作用Docker 提供了两个参数来打开交互能力对应 docker-compose.yml 中的配置services: client: stdin_open: true # 等价于 docker run -i tty: true # 等价于 docker run -t-iinteractive 保持容器的 stdin 打开并桥接到你终端的输入。没有它你敲的字进不到容器里。-ttty 给容器分配一个 伪终端pseudo-TTY 让程序认为自己连着一个真实终端这样输入回显、提示符等交互行为才正常。两者通常合写成docker run -it缺一不可。但重点是 即使 compose 文件里写了这两行up命令也不会把键盘定向给某个容器 ——因为up面对的是多个容器而键盘只有一个无法分发。5. up、run、attach、exec 的区别这四个命令也是初学者最容易混淆的命令作用适合场景docker compose up -d后台启动所有服务管理生命周期运行服务端等长期运行的程序docker compose up前台启动聚合显示所有容器日志查看多容器日志不能交互docker compose run 服务名新建一次性容器终端直接对接运行需要键盘交互的容器docker attach 容器名接入容器中正在运行的主进程容器后台启动后随时接入交互docker exec -it 容器 sh在容器里另起一个新进程shell进容器排查问题不是接手交互程序特别说明 attach 和 exec 的区别attach: 键盘 ── 容器主进程已经在等待输入的 client 程序 ✓ exec sh: 键盘 ── 新开的 shell原来的 client 程序还在原地傻等 ✗6. --rm 参数是什么run命令建议加上--rmdocker compose run --rm client作用是 容器退出后自动删除容器 。因为run每次都会新建一个容器不加--rm每运行一次就会残留一个停止的容器时间长了会攒很多垃圾。正确的使用方式总结最后总结一下这套项目的标准操作后台构建并启动服务端dockercompose up-d--buildserver以交互模式启动客户端想开几个用户就执行几次dockercompose run--rmclient全部结束后清理dockercompose down如果想后台挂着、随时接入dockercompose up-ddockerattach chatroom_client脱离但不关闭容器CtrlP再 CtrlQ写在最后这个问题排查了挺久最大的收获就是明白了 容器里的卡住和本机程序的卡住不是一回事首先要怀疑的是输入输出链路有没有接通而不是程序本身。希望这篇文章能帮到遇到同样问题的朋友。如果觉得有用欢迎点赞、收藏有问题欢迎评论区交流
返回列表