docker中/dev/stdout的理解

以nginx.conf为例子

我们通常看到的日志都是输入到一个文件中,类似access.log,error.log。只要产生相关日志日志就会出现对应的文件中。

error_log /etc/nginx/logs/error.log info;
access_log /etc/nginx/logs/access.log;

而我们在docker容器中,nginx.conf文件如下

error_log /dev/stdout info;
access_log /dev/stdout;

supervisord.conf文件如下

[program:nginx]
command=/usr/sbin/nginx -g "daemon off; error_log /dev/stderr info;"
autostart=true
autorestart=true
priority=10
stdout_events_enabled=true
stderr_events_enabled=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
stopsignal=QUIT

可以看到日志并不是输出到一个文件内,而是/dev/stdout/dev/stderr。它的作用就是日志输出docker日志中,而不输入到具体的文件中。docker日志就是使用以下命令在前台输入的内容

docker-compose logs -f

或者是我们docker前台启动后,输出的内容

docker-compose up

现在有个问题,如果不是在docker上,在云上时,把nginx.conf配置成/dev/stdout时,相关日志输出在哪里?

如docker前台启动一样,日志也会输出到nginx前台启动,通过nginx二进制命令启动

[root@002 sbin]# ./nginx    
[root@002 sbin]# 119.119.76.13 - - [15/Oct/2019:14:40:27 +0800] "GET / HTTP/1.1" 200 24725 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36"
119.119.76.13 - - [15/Oct/2019:14:40:27 +0800] "GET /animated_favicon.gif HTTP/1.1" 200 207 "http://114.115.146.64:666/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36"
119.119.76.13 - - [15/Oct/2019:14:41:04 +0800] "GET / HTTP/1.1" 200 24725 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36"
119.119.76.13 - - [15/Oct/2019:14:41:04 +0800] "GET /animated_favicon.gif HTTP/1.1" 200 207 "http://114.115.146.64:666/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36"

nginx查看标准输出的日志通过前台启动时可以看到,其他服务也是一样,通过前台启动时即可查看到。

/dev/stdout 标准输出
/dev/stdin 标准输入
/dev/stderr 标准错误
/dev/null 不输入输出

还有一个问题,就是起了一个容器后,该容器有nginx和php进程,而俩进程都是使用supervisord来守护进程的。nginx日志都可以在docker里面正常输出,当我有一个需求,需要开启定时执行任务。这时需要在dockerfile文件中新增CMD命令,因为dockerfile中只能执行一条CMD命令,该命令就是容器的主进程。所以我门既要保证原来的服务能正常启动,我们还要启动crontab。所以命令如下

CMD /usr/bin/supervisord -c /etc/supervisord.conf && crond && tail -f /etc/supervisord.conf

提到CMD就不得不提应用在前台执行和后台执行的问题。docker中的所有应用后应该是前台执行,而不是像虚拟机里面用server/systemd去启动后台服务,容器里面没后台服务的概念。一般初学者将CMD写为CMD service nginx start.然后容器执行就退出了。对于容器而言,其启动程序就是容器应用进程,容器就是为了主进程而存在的,主进程退出,容器就失去意义,所以退出,其他辅助进程不是它所关心的。

CMD /usr/bin/supervisord -c /etc/supervisord.conf && crond

如果执行上条命令的话,会报code为0的问题,表示容器退出,也就是后台启动完进程就退出了,所以容器也就没有存在的意义,也就退出了。所以我们加tail命令,tail可阻塞,挂起一个主进程,类似前台启动。

CMD /usr/bin/supervisord -c /etc/supervisord.conf && crond && tail -f /etc/supervisord.conf

注意:这时意味着和之前相比,主进程发生了变化,也就意味着,此时nginx的相关日志就不会输出在docker前台了。可以想象成原来开启的是nginx服务,现在开启了一个mysql服务,nginx的相关日志信息也理所当然的不会出现在mysql的服务中了。

重要:如果使用CMD后改变主进程,类似nginx日志将不会输出到console,此时我们应该修改nginx的配置文件,让其log输出到文件中