docker 容器镜像无法重定向日志标准输出到指定文件排错

背景

用下面Dockerfile构建了个服务镜像,启动之后发现无论怎么测试都不会生成我们想要的日志文件/opt/service.out

FROM openjdk:8-jdk-alpine
COPY service.jar /opt/service.jar
ENTRYPOINT  ["java", "-Dfile.encoding=utf-8", "-Xms512M","-Xmx1024M","-jar", "/opt/service.jar",">>","/opt/service.out", "2>&1"]

尝试用nohup后台方式启动也只会在根目录下面生成nohup.out文件而不是我们想要的service.out文件nohup 方式如下

ENTRYPOINT  ["nohup","java", "-Dfile.encoding=utf-8", "-Xms512M","-Xmx1024M","-jar", "/opt/service.jar",">>","/opt/service.out", "2>&1","&"]

这个问题让人头大, 有必要深入了解一下了

解决

在了解Dockfile 的ShellExec 两种命令方式的区别1 时突然想到会不会是在sh 命令中才能使用重定向功能, 于是将镜像中启动命令改造成下面的 sh -c的方式

ENTRYPOINT  ["/bin/sh","-c","java", "-Dfile.encoding=utf-8", "-Xms512M","-Xmx1024M","-jar", "/opt/service.jar",">>","/opt/service.out"]

进入容器中查看service.out文件能成功生成了, 但是查看进程会发现有两个进程, 其中一个是bash 进程

root@e6704bc7d50c:/opt# ls
service.jar  service.out

root@e6704bc7d50c:/opt# ps -ef -w -w
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 22:32 pts/0    00:00:00 /bin/sh -c java  -Dfile.encoding=utf-8  -Xms512M -Xmx1024M -jar  /opt/service.jar  >> /opt/service.out 2>&1
root         8     1 99 22:32 pts/0    00:00:40 java -Dfile.encoding=utf-8 -Xms512M -Xmx1024M -jar /opt/service.jar 

bash 进程会负责回收僵尸进程, 但是它有一个比较严重的问题,bash 不会传递信号给它启动的进程,优雅停机等功能无法实现2 对于这种情况可以使用 docker 官方的轻量级 init 系统, 运行命令如下

docker run -it --init you_docker_image_id

这种启动方式会以 /sbin/docker-init 作为 PID 为 1init 进程,不会把 Dockerfile 中 CMD 作为第一个启动进程。例如:

UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 15:30 pts/0    00:00:00 /sbin/docker-init -- /app/node-default
root         6     1  0 15:30 pts/0    00:00:00 ./signal_test

另外, 如果容器中存在多个进程的话有可能会产生孤儿进程和僵尸进程3

  • 父进程先于子进程退出,那么子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)接管,并由init进程对它完成状态收集(wait/waitpid)工作。
  • 子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中,这种进程称之为僵尸进程

如果不得不在容器中使用多个程序进程的话可以考虑使用dumb-init,tini,runit,Monit,Skaware S6,Supervisor等三方进程守护工具4, 详细介绍请参考: 如何在一个Docker中同时运行多个程序进程?

回到问题本身,如果我只想在我的容器中只保留一个java -jar的进程并且不用sh -c 的方式启动,那我应该怎么做呢?

答案是:
springboot日志的--logging.file.name 参数可以指定日志文件,如果是其他日志框架应该也有对应的配置参数

启动命令修改后:

ENTRYPOINT  ["java", "-Dfile.encoding=utf-8", "-Xms512M","-Xmx1024M","-jar", "/opt/service.jar","--logging.file.name=/opt/service.out"]

启动后查看容器只有一个java -jar进程

root@d048b0c9df8e:/opt# ps -ef -w -w
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0 99 23:27 pts/0    00:01:15 java -Dfile.encoding=utf-8 -Xms512M -Xmx1024M -jar /opt/service.jar  --logging.file.name=/opt/service.out

参考


  1. Dockerfile: ENTRYPOINT和CMD的区别 ↩︎

  2. 一次 Docker 容器内大量僵尸进程排查分析 ↩︎

  3. Docker和孤儿进程、僵尸进程 ↩︎

  4. 如何在一个Docker中同时运行多个程序进程? ↩︎

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值