用下面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 的Shell
和 Exec
两种命令方式的区别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 为 1
的 init
进程,不会把 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