docker

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输出到文件中

docker swarm集群部署应用

Manager

docker swarm init

Work1

docker swarm join --token SWMTKN-1-45iawvwnc45h6c7plj6zkmj0f0zd0tr8y5rvk9o35w25mt6pev-dahwo3nak1y7qyx0dwe803zbm xxx.xxx.xxx:2377

work2

docker swarm join --token SWMTKN-1-45iawvwnc45h6c7plj6zkmj0f0zd0tr8y5rvk9o35w25mt6pev-dahwo3nak1y7qyx0dwe803zbm xxx.xxx.xxx:2377

work3

docker swarm join --token SWMTKN-1-45iawvwnc45h6c7plj6zkmj0f0zd0tr8y5rvk9o35w25mt6pev-dahwo3nak1y7qyx0dwe803zbm xxx.xxx.xxx:2377

docker node ls

部署服务

我们使用 docker service 命令来管理 Swarm 集群中的服务,该命令只能在管理节点运行。

新建服务

现在我们在上一节创建的 Swarm 集群中运行一个名为 nginx 服务。

$ docker service create --replicas 3 -p 80:80 --name nginx nginx:1.13.7-alpine

现在我们使用浏览器,输入任意节点 IP ,即可看到 nginx 默认页面。

查看服务

使用 docker service ls 来查看当前 Swarm 集群运行的服务。

$ docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                 PORTS
kc57xffvhul5        nginx               replicated          3/3                 nginx:1.13.7-alpine   *:80->80/tcp

使用 docker service ps 来查看某个服务的详情。

$ docker service ps nginx
ID                  NAME                IMAGE                 NODE                DESIRED STATE       CURRENT STATE                ERROR               PORTS
pjfzd39buzlt        nginx.1             nginx:1.13.7-alpine   swarm2              Running             Running about a minute ago
hy9eeivdxlaa        nginx.2             nginx:1.13.7-alpine   swarm1              Running             Running about a minute ago
36wmpiv7gmfo        nginx.3             nginx:1.13.7-alpine   swarm3              Running             Running about a minute ago

使用 docker service logs 来查看某个服务的日志。

$ docker service logs nginx
nginx.3.36wmpiv7gmfo@swarm3    | 10.255.0.4 - - [25/Nov/2017:02:10:30 +0000] "GET / HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:58.0) Gecko/20100101 Firefox/58.0" "-"
nginx.3.36wmpiv7gmfo@swarm3    | 10.255.0.4 - - [25/Nov/2017:02:10:30 +0000] "GET /favicon.ico HTTP/1.1" 404 169 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:58.0) Gecko/20100101 Firefox/58.0" "-"
nginx.3.36wmpiv7gmfo@swarm3    | 2017/11/25 02:10:30 [error] 5#5: *1 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 10.255.0.4, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "192.168.99.102"
nginx.1.pjfzd39buzlt@swarm2    | 10.255.0.2 - - [25/Nov/2017:02:10:26 +0000] "GET / HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:58.0) Gecko/20100101 Firefox/58.0" "-"
nginx.1.pjfzd39buzlt@swarm2    | 10.255.0.2 - - [25/Nov/2017:02:10:27 +0000] "GET /favicon.ico HTTP/1.1" 404 169 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:58.0) Gecko/20100101 Firefox/58.0" "-"
nginx.1.pjfzd39buzlt@swarm2    | 2017/11/25 02:10:27 [error] 5#5: *1 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 10.255.0.2, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "192.168.99.101"

服务伸缩

我们可以使用 docker service scale 对一个服务运行的容器数量进行伸缩。

当业务处于高峰期时,我们需要扩展服务运行的容器数量。

$ docker service scale nginx=5

当业务平稳时,我们需要减少服务运行的容器数量。

$ docker service scale nginx=2

删除服务

使用 docker service rm 来从 Swarm 集群移除某个服务。

$ docker service rm nginx