Docker容器无法显示内部进程日志,如何将其输出到STDOUT?
问题描述
我有以下Dockerfile内容:
FROM debian:stretch-slim CMD ["/opt/server/start-server.sh"]
对应的start-server.sh脚本内容:
#!/bin/sh echo "Launching Server" ./ServerApplicationIHaveNoControllOver echo "Finished Application"
执行docker-compose up时,服务能正常启动处理请求,但用docker logs看不到日志;其他容器日志显示正常。在普通shell运行脚本时能看到所有日志。另外,如果应用进程报错提前退出,所有日志会被刷到STDOUT,说明进程会缓存日志,只在结束时释放。
请问:
- shell与容器中日志显示有何差异?
- 如何将
./ServerApplicationIHaveNoControllOver的日志输出到STDOUT,使其能通过docker logs CONTAINER_HASH命令查看?
一、Shell与容器日志显示的差异
- 终端环境差异:普通shell是交互式终端(TTY),程序检测到这种环境时,会自动将STDOUT/STDERR设为行缓冲模式,日志会逐行实时输出。
- 容器非交互式环境:Docker容器默认以非交互式方式运行进程,程序会识别到输出不是TTY,自动切换为块缓冲模式——只有缓冲区填满或进程退出时,才会把缓冲的内容一次性输出到STDOUT/STDERR,这就是正常运行时看不到日志、退出时才刷出的核心原因。
二、解决方法
可以通过以下几种方式强制程序实时输出日志:
1. 用stdbuf强制行缓冲
直接在运行程序时,通过stdbuf修改缓冲策略,强制STDOUT和STDERR使用行缓冲:
#!/bin/sh echo "Launching Server" stdbuf -oL -eL ./ServerApplicationIHaveNoControllOver echo "Finished Application"
-oL:设置STDOUT为行缓冲-eL:设置STDERR为行缓冲
2. 给容器分配伪TTY
让程序误以为运行在交互式终端环境,从而自动使用行缓冲:
- Dockerfile修改:
或者在启动容器时添加FROM debian:stretch-slim CMD ["sh", "-c", "/opt/server/start-server.sh"]--tty/-t参数,比如docker run -t your-image - docker-compose.yml修改:
services: your-service: # 其他配置项 tty: true
注意:该方式会引入终端相关的额外行为,需根据实际场景测试验证。
3. 重定向输出到管道强制刷新
通过管道让程序输出变为行缓冲,再实时输出到STDOUT:
#!/bin/sh echo "Launching Server" ./ServerApplicationIHaveNoControllOver 2>&1 | cat echo "Finished Application"
内容的提问来源于stack exchange,提问作者Loading
相关产品推荐
相关产品推荐

