Nginx 自己没有处理日志的滚动问题,它把这个球踢给了使用者。一般情况下,你可以使用 logrotate 工具来完成这个任务,或者如果你愿意,你可以写各式各样的脚本完成同样的任务。本文笔者介绍如何滚动运行在 docker 中的 nginx 日志文件(下图来自互联网)。
思路
Nginx 官方其实给出了如何滚动日志的说明:
Rotating Log-files
In order to rotate log files, they need to be renamed first. After that USR1 signal should be sent to the master process. The master process will then re-open all currently open log files and assign them an unprivileged user under which the worker processes are running, as an owner. After successful re-opening, the master process closes all open files and sends the message to worker process to ask them to re-open files. Worker processes also open new files and close old files right away. As a result, old files are almost immediately available for post processing, such as compression.
这段说明的大意是:
- 先把旧的日志文件重命名
- 然后给 nginx master 进程发送 USR1 信号
- nginx master 进程收到信号后会做一些处理,然后要求工作者进程重新打开日志文件
- 工作者进程打开新的日志文件并关闭旧的日志文件
其实真正需要我们做的工作只有前面两点!
创建测试环境
假设你的系统中已经安装好了 docker,这里我们直接运行一个 nginx 容器:
$ docker run -d \
-p : \
-v $(pwd)/logs/nginx:/var/log/nginx \
--restart=always \
--name=mynginx \
nginx:1.11.
注意,我们把 nginx 的日志绑定挂载到了当前目录下的 logs 目录下。
把下面的内容保存到 test.sh 文件中:
#!/bin/bash for ((i=;i<=;i++))
do
curl http://localhost > /dev/null
sleep
done
然后运行这个脚本,就可以模拟产生连续的日志记录。
创建滚动日志的脚本
创建 rotatelog.sh 文件,其内容如下:
#!/bin/bash getdatestring()
{
TZ='Asia/Chongqing' date "+%Y%m%d%H%M"
}
datestring=$(getdatestring) mv /var/log/nginx/access.log /var/log/nginx/access.${datestring}.log
mv /var/log/nginx/error.log /var/log/nginx/error.${datestring}.log
kill -USR1 `cat /var/run/nginx.pid`
getdatestring 函数取当前的时间并格式化为字符串,比如 "201807241310",笔者比较喜欢用日期和时间来命名文件。注意这里通过 TZ='Asia/Chongqing' 指定了时区,因为默认情况下格式化的是 UTC 时间,用起来怪怪的(要实时脑补 +8 小时)。下面的两条 mv 命令用来重命名日志文件。最后通过 kill 命令向 nginx master 进程发送 USR1 信号。
通过下面的命令为 rotatelog.sh 文件添加可执行权限并复制到 $(pwd)/logs/nginx 目录下:
$ chmod +x rotatelog.sh
$ sudo cp rotatelog.sh $(pwd)/logs/nginx
定时执行滚动操作
我们的 nginx 运行在容器中,所以需要在容器中给 nginx master 进程发送 USR1 信号。因此我们需要通过 docker exec 命令在 mynginx 容器中执行 rotatelog.sh 脚本:
$ docker exec mynginx bash /var/log/nginx/rotatelog.sh
执行一次上面的命令,会如期产生一批新的日志文件:
下面我们把这个命令配置在定时任务中,让它每天早上 1 点钟执行一次。执行 crontab -e 命令,并在文件的末尾添加下面的行:
* * * * docker exec mynginx bash /var/log/nginx/rotatelog.sh
保存并退出就可以了。下图是笔者测试过程中每 5 分钟滚动一次的效果:
为什么不在宿主机中直接 mv 日志文件?
理论上这么做是可以的,因为通过绑定挂载的数据卷中的内容从宿主机上看和从容器中看都是一样的。但是真正这么做的时候你很可能碰到权限问题。在宿主机中,你一般使用的是普通用户,而在容器中产生的日志文件的所有者是会是特殊的用户,并且一般不会给其它用户写和执行的权限:
当然,如果你在宿主机中使用的是 root 用户就不会有问题。
能从宿主机中发送的信号吗?
其实这个问题的全称应该是:能从宿主机中给 docker 容器中的 nginx master 进程发送信号吗?
答案是,可以的。
笔者这《在 docker 容器中捕获信号》一文中介绍了容器中信号的捕获问题,感兴趣的朋友可以去看看。在那篇文章中我们介绍了 docker 向容器中进程发送信号的 kill 命令。我们可以通过命令:
$ docker container kill mynginx -s USR1
向容器中的 1 号进程(nginx master)发送 USR1 信号(这种方式只能向 1 号进程发送信号):
结合上面的两个问题,我们可以写出另外的一种方式来滚动 docker 中的 nginx 日志。这种方式不需要通过 docker exec 命令在容器中执行命令,而完全在宿主机中完成所有的操作:
- 先重命名容器数据卷中的日志文件
- 给容器中的 1 号进程发送 USR1 信号
总结
相比之下我还是更喜欢第一种方式,它逻辑上清晰,操作上几乎与宿主机完全隔离,也不容易出错。但是通过第二种方式的尝试,我们不但可以找到新的实现方式,还会加深对容器操作的理解。学而不思则罔啊!
参考:
How To Configure Logging and Log Rotation in Nginx on an Ubuntu VPS
How To Manage Logfiles with Logrotate on Ubuntu 16.04
滚动 docker 中的 nginx 日志的更多相关文章
-
解决docker中使用nginx做负载均衡时并发过高时的一些问题
# 解决docker中使用nginx做负载均衡时并发过高时的一些问题 1.问题产生原因: 由于通过nginx作为负载均衡服务,在访问并发数量达到一定量级时jmeter报错. nginx日志关键信息:a ...
-
Docker中运行nginx
Docker中运行nginx 1.Docker中运行nginx 2.配置文件 2.1 nginx.conf 2.2 default.conf 3.docker的镜像可以挂什么卷 部分内容原文地址: C ...
-
docker中实现服务日志轮转
问题背景 通常我们一个完整的应用镜像有两部分组成,一个是运行时环境,一个是应用程序.我们以php应用为例,一个完整的php应用需要包含openresty + php两个服务来配置运行时环境,然后再加上 ...
-
为 docker 中的 nginx 配置 https
没有 https 加持的网站会逐渐地被浏览器标记为不安全的,所以为网站添加 https 已经变得刻不容缓.对于商业网站来说,花钱购买 SSL/TLS 证书并不是什么问题.但对于个人用户来说,如果能有免 ...
-
Docker中运行nginx并挂载本地目录到镜像中
1.1 从hup上pull镜像1.2 创建将要挂载的目录1.3 先要有配置文件才能启动容器1.3.1 vim /data/nginx/conf/nginx.conf1.3.2 vim /data/ng ...
-
一次docker中的nginx进程响应慢问题定位记录
有个ft测试的环境,其中nginx使用docker发布的.测试用例是curl的时候,没有获得nginx的响应. docker ps CONTAINER ID IMAGE COMMAND CREATED ...
-
docker中使用nginx容器代理其他容器
Nginx is an HTTP and reverse proxy server, a mail proxy server, and a generic TCP/UDP proxy server, ...
-
docker-compose中加入nginx 日志和部署下载
服务器部署了nginx镜像,所以加入一个日志查看,添加一下静态页面下载. 1.查看nginx镜像怎么部署的 nginx: image: nginx ports: - '80:80' volumes: ...
-
docker中安装nginx,部署前端代码
最近在学习docker,初次接触,难免遇到磕磕碰碰,遂将其整理成博客,以便日后查看. 1.拉取nginx镜像 直接从官方镜像库拉取简单粗暴: docker pull nginx 2.运行 docker ...
随机推荐
-
导入myeclipse项目出现的问题及解决方案
1.myeclipse 方法上加上@Override就报错 在有@Override方法上面会报错如下: The method oncreate(Bundle) of type HelloWorld m ...
-
HTTP基础03--HTTP报文
报文大致结构: 报文首部: 请求行(请求报文)/状态行(响应报文) 首部字段:请求和响应的各种条件和属性的各类首部: 其它(Cookie) 空行 报文主体(不是必须) 编码提升传输速率: 报文主体和实 ...
-
共享参数ContentProvider 类与数据库绑定,如何通过共享参数测试类,测试数据库的增删改查功能
Intent可以传一个对象 当两个界面之间跳转时,需要传递一个对象过去,是通过使用Bundle类,并且实体类需要serializable实现序列化,传递方法如下: 定义一个静态常量作为key值 pub ...
-
vue数据请求
我是vue菜鸟,第一次用vue做项目,写一些自己的理解,可能有些不正确,欢迎纠正. vue开发环境要配置本地代理服务.把config文件加下的index.js里的dev添加一些内容, dev: { e ...
-
LeetCode - Robot Room Cleaner
Given a robot cleaner in a room modeled as a grid. Each cell in the grid can be empty or blocked. Th ...
-
logback log4j log4j2 性能实测
logback log4j log4j2 性能实测 转载: https://blog.souche.com/logback-log4j-log4j2shi-ce/ 日志已经成为系统开发中不可或缺的一部 ...
-
判断一个整数是否是2的n次方
参考:http://bbs.csdn.net/topics/370058619 如题,如何判断一个整数是否是2的N次方,我能想到的方法有两个 1.一直除2,看最后是否等于1.(最笨的方法) 2.转换成 ...
-
Java数据结构和算法(一)散列表
Java数据结构和算法(一)散列表 数据结构与算法目录(https://www.cnblogs.com/binarylei/p/10115867.html) 散列表(Hash table) 也叫哈希表 ...
-
Javascript 面向对象编程(补充):封装
Javascript是一种基于对象(object-based)的语言,你遇到的所有东西几乎都是对象.但是,它又不是一种真正的面向对象编程(OOP)语言,因为它的语法中没有class(类). 那么,如果 ...
-
转 C语言编译过程简介
C语言编译过程简介 C语言编译过程简介 刚开始接触编程的时候,只知道照书敲敲代码,一直都不知道为什么在windows平台下代码经过鼠标那样点击几下,程序的结果就会在那个黑色的屏幕上.现在找了个机会将C ...