我们最近将我们的一个应用程序迁移到“在 64 位 Amazon Linux 2/3.2.12 上运行的 Corretto 8”平台。现在我们发现一个问题,即日志文件在一周多的时间内填满了我们的磁盘卷。我们以前没有遇到过这个问题。
令人恼火的是,我们正在将这些日志流式传输到 CloudWatch,因此我们实际上不需要在实例本身上使用它们。更令人恼火的是,我能找到的所有文档、博客文章等显然都不是为这个平台编写的。查看文件结构时,似乎它采用了一种我还没有完全弄清楚的不同方法。
首先,没有 /var/log/httpd ... 文件夹或其他用于特定日志的文件夹。到目前为止,我已经弄清楚发送到 web.stdout.log 日志流(在旧平台上,它曾经被命名为不同的名称,但我不记得具体名称了。无论如何,它是 spring-boot 应用程序记录日志的地方)的内容存储在文件 /var/log/messages 中。
我知道这一点,是因为在分析磁盘空间不足的原因时,这个文件始终是整个磁盘上最大的文件。除了在实例启动后,它的大小还算合理。3 天后,它的大小可以达到 2 GB,并且会一直增长,直到什么都没有了。毫无疑问,这就是我们麻烦的根源。
问题是,我能做什么做关于它?日志轮换处于默认配置中,我可以在 /var/log/rotated 中看到一些文件(也是一个与轮换日志所在的文件夹不同的文件夹),但那些文件很小(其中最大的文件大小为 1.3 MB...),并且 /var/log/messages 的大小永远不会减小,只会增长。
我读过许多关于如何使用 ebextensions 配置 logrotate 来解决类似问题的文章,有 AWS 自己写的,也有博主写的,但我很快就发现,这些文章都是建立在非常不同的结构之上的,所以似乎不太适用。此外,我们在迁移过程中已经发现,一些使用 ebextensions 完成的事情现在不再使用 ebextensions 完成了,但文档相当缺乏。
有谁足够了解这个平台,能给我一些关于如何配置它的线索吗?我甚至不需要旋转严格来说,日志一旦超过一小时左右,我只想尽快删除它们。毕竟,我们在 CloudWatch 上拥有它们……
附加信息 我对此研究得越深,就越感到困惑。有一个 /var/log/web.stdout.log 文件,它接收与 /var/log/messages 相同的消息。查看 logrotate.elasticbeanstalk.hourly 的内容,这是实际上处于日志轮换中的文件,并且似乎运行良好。
执行 lsof 时,使用该文件的进程是 rsyslogd。根据以下 shern89s 的评论,显然这是新的 syslog,记录到 stdout 的所有内容都会记录在那里。
意识到该文件不属于任何类型的轮换,我正尝试进行设置。目前只在实例上直接设置,稍后我将弄清楚如何在实际环境配置中执行此操作。
我在 /etc/logrotate/elasticbeanstalk.hourly 中创建了一个新的配置文件,其内容如下:
/var/log/messages {
su root root
size 10M
rotate 5
missingok
compress
notifempty
copytruncate
dateext
dateformat %s
olddir /var/log/rotated
}
运行后sudo /usr/sbin/logrotate /etc/logrotate.elasticbeanstalk.hourly/logrotate.elasticbeanstalk.messages.conf --debug
,我得到以下输出:
rotating pattern: /var/log/messages 10485760 bytes (5 rotations)
olddir is /var/log/rotated, empty log files are not rotated, old logs are removed
considering log /var/log/messages
log needs rotating
rotating log /var/log/messages, log->rotateCount is 5
Converted ' %s' -> '%s'
dateext suffix '1646905905'
glob pattern '[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]'
glob finding old rotated logs failed
copying /var/log/messages to /var/log/rotated/messages1646905905
truncating /var/log/messages
compressing log with: /bin/gzip
这看起来很有希望,但冷酷的事实是似乎什么都没有改变。文件仍然具有相同的大小,并且旋转文件夹中没有创建任何文件。它似乎根本没有效果。我更改了配置,以便它移动并创建而不是就地截断,我尝试了 -f,结果都相同。logrotate 没有错误,但也没有效果。该文件似乎完全无懈可击。
答案1
如果您查看/etc/logrotate.d/syslog
,您会发现已经有一个轮换文件的规定/var/log/messages
。但配置不会压缩轮换的文件,并且会保留最多 4 周的轮换日志。这对于轻度使用来说没问题,但在每次访问都会流式传输日志的服务器应用程序上,这会很快耗尽磁盘空间。
AWS 现在建议使用.platform/hooks
文件而不是.ebextensions
。此外,如果被覆盖,.ebextensions
还会创建带有扩展名的文件副本。这可能会导致重复的 logrotate 文件,从而导致错误。.bak
我在路径中添加了以下配置文件.platform/hooks/predeploy/modify-logrotate.sh
确保此文件是可执行的并且以正确的 shebang 开始。
#!/bin/sh
fileName=/etc/logrotate.d/syslog
lineCount=($(wc -l "$fileName"))
lineToInsert="$((${lineCount[0]}))"
echo $lineToInsert
sed -i "${lineToInsert}i compress\n rotate 1\n daily" "$fileName"
原始配置文件以}
作为最后一行结束。上述代码在结束行上方插入了额外的配置行,以使最终的代码有效。
我不确定这种更改在某些情况下是否会导致无效语法,但我发现没有更好的方法以更安全的方式修改此文件。
答案2
我将其保存在 .ebextensions/liblogrotate.config 中:
files:
/etc/remove_old_logs.sh:
owner: root
group: root
mode: "000644"
content: |
#!/bin/sh
find /var/log -type f -mtime +7 -exec rm {} +
container_commands:
01_crontab:
command: "( crontab -l | grep -v -F \". /etc/remove_old_logs.sh\" ; echo \"0 0 * * * . /etc/remove_old_logs.sh\" ) | crontab -"
它创建一个 crontab,用于删除 /var/log 文件夹中超过 7 天的文件。我知道这不是最佳选择,但我不太关心这些日志。
答案3
最简单的方法是停止将 web stdout 发送到。它只需要在 中相应的 rsyslog 配置中添加/var/log/messages
以下行:stop
/etc/rsyslog.d/web.conf
# This rsyslog file redirects Elastic Beanstalk platform logs.
# Logs are initially sent to syslog, but we also want to divide
# stdout and stderr into separate log files.
if $programname == 'web' then {
*.=warning;*.=err;*.=crit;*.=alert;*.=emerg /var/log/web.stderr.log
*.=info;*.=notice /var/log/web.stdout.log
# THE LINE BELOW STOPS SENDING OUTPUT TO ANY OTHER LOG FILES
stop
}
在目录中创建一个可执行文件(带有chmod +x
).platform/hooks/predeploy
,其中包含以下内容,以便在部署新版本时应用此配置更改:
#!/bin/sh
FILE="/etc/rsyslog.d/web.conf"
CONTENTS=$(cat <<-END
# This rsyslog file redirects Elastic Beanstalk platform logs.
# Logs are initially sent to syslog, but we also want to divide
# stdout and stderr into separate log files.
if $programname == 'web' then {
*.=warning;*.=err;*.=crit;*.=alert;*.=emerg /var/log/web.stderr.log
*.=info;*.=notice /var/log/web.stdout.log
stop
}
END
)
echo "$CONTENTS" > "$FILE"
service rsyslog restart