You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker中运行C++二进制文件无输出/输入且容器挂起问题

Docker中C++二进制容器挂起、stdout无输出问题解决

环境与配置

Dockerfile构建阶段

FROM ubuntu:focal as builder
WORKDIR /var/lib/project
RUN cmake ... && make ...

Dockerfile最终镜像阶段

WORKDIR /var/lib/project

COPY --from=builder /usr/src/project/bin/binary ./binary

EXPOSE 8080

CMD ["./binary"]

镜像构建命令

docker build . --platform=linux/amd64 --file docker/Dockerfile --progress=plain -c 32 -t mydocker:latest

问题现象

  • 执行docker run -d启动容器时,容器无任何输出且挂起,只能通过其他终端强制终止
  • 用docker exec进入容器shell后,手动运行二进制文件可正常工作
  • 二进制进程作为PID1运行时,std::printf无输出,仅当注释server->Serve()或输出内容填满缓冲区时才会显示内容

已尝试的无效配置

先后测试以下CMD/ENTRYPOINT组合,均无法解决问题:

CMD ["/bin/bash", "-c" , "./binary"]
CMD ["/bin/bash", "-c" , "exec", "./binary"]

补充信息

  • C++编译参数:
    CXX_FLAGS= -fno-builtin-memcmp -fPIC -Wfatal-errors -w -msse -msse4.2 -mavx2
    
  • 核心服务代码(基于Apache Arrow 10.0.1):
int main() {
   arf::Location srv_loc = arf::Location::ForGrpcTcp("127.0.01", 8080).ValueUnsafe();
   arf::FlightServerOptions opt(srv_loc);
   auto server = std::make_unique<MyService>();
   ARROW_RETURN_NOT_OK(server->Init(opt));
   std::printf("Starting on port: %i\n", server->port());
   return server->Serve().ok();
}

问题根因

当二进制进程作为容器的PID1运行时,会触发Linux系统的特殊行为:

  1. 信号处理异常:PID1不会自动转发SIGTERM等终止信号,导致容器无法正常停止,表现为"挂起"
  2. stdout缓冲模式异常:PID1的标准输出默认是全缓冲,而非交互式进程的行缓冲,因此printf的内容不会立刻输出到主机终端,直到缓冲区填满或进程退出

解决方案

方案1:在Dockerfile中集成init进程(替代docker run --init)

通过安装tini工具(Docker官方--init参数的底层实现),让它作为容器的PID1进程,负责信号转发、缓冲修正和僵尸进程清理。修改后的最终镜像Dockerfile如下:

FROM ubuntu:focal
WORKDIR /var/lib/project

# 安装tini工具
RUN apt-get update && apt-get install -y --no-install-recommends tini \
    && rm -rf /var/lib/apt/lists/*

COPY --from=builder /usr/src/project/bin/binary ./binary

EXPOSE 8080

# 用tini作为PID1,启动二进制程序
ENTRYPOINT ["tini", "--"]
CMD ["./binary"]

方案2:修改C++代码强制刷新stdout(仅解决输出问题)

如果只需要解决stdout无输出的问题,可以在printf后手动刷新缓冲区:

std::printf("Starting on port: %i\n", server->port());
fflush(stdout); // 强制刷新标准输出

但此方案无法解决信号处理和容器正常停止的问题,仅作为临时输出调试手段。

验证

构建修改后的镜像并启动:

docker run -d mydocker:latest

此时容器会正常运行,docker logs可以看到Starting on port: 8080的输出,且容器能响应docker stop命令正常终止。

内容的提问来源于stack exchange,提问作者ishkhan23

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 20:05:12