Docker:如何正确清除 Docker 容器的日志?
Posted
技术标签:
【中文标题】Docker:如何正确清除 Docker 容器的日志?【英文标题】:Docker: How to clear the logs properly for a Docker container? 【发布时间】:2017-07-19 11:56:58 【问题描述】:我使用docker logs [container-name]
查看特定容器的日志。
有没有优雅的方法来清除这些日志?
【问题讨论】:
在旁注中,您可以通过sudo sh -c "du -ch /var/lib/docker/containers/*/*-json.log"
获取日志的大小
不完全清除日志,但为了避免看到旧日志,您可以使用“-n”和“-f”选项。 -n:从日志末尾开始显示的行数(默认为“all”) -f:跟随日志输出 $ docker logs -n 0 -f [container-name] 这将只显示传入的日志
【参考方案1】:
不确定这是否对您有帮助,但移除容器总是有帮助的。
因此,如果您使用 docker-compose 进行设置,您可以简单地使用 docker-compose down && docker-compose up -d
而不是 docker-compose restart
。通过正确的设置(确保对持久数据使用卷挂载),您不会以这种方式丢失任何数据。
当然,这比 OP 要求的要多。但在各种情况下其他答案无济于事(如果使用远程 docker 服务器或在 Windows 机器上工作,访问底层文件系统是专有且困难的)
【讨论】:
为我工作。很有帮助,因为我确实有几个容器、卷、docker-compose.yml 等,而且它“顺利”地完成了。我在运行 up 命令时总是忘记添加-d
标志(已分离),所以不要忘记这样做:)【参考方案2】:
您还可以在docker run
命令行上提供 log-opts 参数,如下所示:
docker run --log-opt max-size=10m --log-opt max-file=5 my-app:latest
或在这样的 docker-compose.yml 中
my-app:
image: my-app:latest
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "5"
致谢:https://medium.com/@Quigley_Ja/rotating-docker-logs-keeping-your-overlay-folder-small-40cfa2155412 (James Quigley)
【讨论】:
参数值应该被引用(即"5"
和"10m"
分别),如全局daemon.json文件的here所示,但对于docker-compose也是如此。 yml。在这两种情况下,它只会影响新创建的容器。
@AdrianW:docker-compose.yml 不需要引号。这些是完全不同的文件格式。是的,你是对的:“docker run”命令和 docker-compose 参数只影响新创建的容器 - 而这里投票最多的答案只影响重新启动的 dockerd 守护进程,并且只能通过 root 访问。我的答案应该是比重新启动整个 dockerd 进程更简单和更新的路径。
不带引号,我得到:错误:应用程序无法为服务应用程序创建容器:json:无法将数字解组到字符串类型的 Go struct 字段 LogConfig.Config 如果我引用像这样:"5"
它有效。 10m
确实没有引用。
看起来 Docker for Windows 和 Docker for Linux 之间存在差异。对于后者,我必须将值括在引号中。不在前者。更新了描述以适应两者。谢谢,@AdrianW【参考方案3】:
如果您需要在删除之前存储日志文件的备份,我已经创建了一个脚本,该脚本为指定的容器执行以下操作(您必须使用 sudo 运行它):
-
创建一个文件夹来存储压缩日志文件作为备份。
查找正在运行的容器的 ID(由容器的名称指定)。
使用随机名称将容器的日志文件复制到新位置(步骤 1 中的文件夹)。
压缩之前的日志文件(以节省空间)。
按照您可以定义的特定大小截断容器的日志文件。
注意事项:
它使用 shuf 命令。确保您的 linux 发行版具有它或将其更改为另一个支持 bash 的随机生成器。 使用前,更改变量CONTAINER_NAME 以匹配您正在运行的容器;它可以是部分名称(不必是完全匹配的名称)。 默认情况下,它将日志文件截断为 10M(10 兆字节),但您可以通过修改变量 SIZE_TO_TRUNCATE 来更改此大小。 它在路径中创建一个文件夹:/opt/your-container-name/logs,如果您想将压缩日志存储在其他地方,只需更改变量LOG_FOLDER强>。 在生产中运行之前运行一些测试。#!/bin/bash
set -ex
############################# Main Variables Definition:
CONTAINER_NAME="your-container-name"
SIZE_TO_TRUNCATE="10M"
############################# Other Variables Definition:
CURRENT_DATE=$(date "+%d-%b-%Y-%H-%M-%S")
RANDOM_VALUE=$(shuf -i 1-1000000 -n 1)
LOG_FOLDER="/opt/$CONTAINER_NAME/logs"
CN=$(docker ps --no-trunc -f name=$CONTAINER_NAME | awk 'print $1' | tail -n +2)
LOG_DOCKER_FILE="$(docker inspect --format='.LogPath' $CN)"
LOG_FILE_NAME="$CURRENT_DATE-$RANDOM_VALUE"
############################# Procedure:
mkdir -p "$LOG_FOLDER"
cp $LOG_DOCKER_FILE "$LOG_FOLDER/$LOG_FILE_NAME.log"
cd $LOG_FOLDER
tar -cvzf "$LOG_FILE_NAME.tar.gz" "$LOG_FILE_NAME.log"
rm -rf "$LOG_FILE_NAME.log"
truncate -s $SIZE_TO_TRUNCATE $LOG_DOCKER_FILE
您可以创建一个 cronjob 来每月运行之前的脚本。第一次运行:
sudo crontab -e
在键盘中输入 a 以进入编辑模式。然后添加以下行:
0 0 1 * * /your-script-path/script.sh
按 escape 键退出编辑模式。通过键入 :wq 并按 Enter 保存文件。确保 script.sh 文件具有执行权限。
【讨论】:
【参考方案4】:感谢answer by @BMitch,我刚刚写了一个shell脚本来清理所有容器的日志:
#!/bin/bash
ids=$(docker ps -a --format='.ID')
for id in $ids
do
echo $(docker ps -a --format='.ID ### .Names ### .Image' | fgrep $id)
truncate -s 0 $(docker inspect --format='.LogPath' $id)
ls -llh $(docker inspect --format='.LogPath' $id)
done
【讨论】:
【参考方案5】:在 Windows 和 Mac 的 Docker 上,可能还有其他的,可以使用 tail 选项。例如:
docker logs -f --tail 100
这样,只显示最后 100 行,而您不必先滚动 1M 行...
(因此,删除日志可能是不必要的)
【讨论】:
思路是清理日志文件而不是打印日志文件的最后n行 这实际上解决了我最初寻找的问题。谢谢! 虽然严格来说这不是问题的答案,但这是我真正需要的! 一些编辑了我的帖子,但建议不起作用,至少在 docker 20.10.5 上不能使用 docker logs -f --since 30s(例如) 如果您只想使用 docker-compose 从特定容器中获取日志,您也可以使用以下命令:docker-compose logs --tail 10 --follow service1 service2 etc
【参考方案6】:
首先是错误的答案。从this question 可以运行一个单行:
echo "" > $(docker inspect --format='.LogPath' <container_name_or_id>)
而不是回声,有更简单的:
: > $(docker inspect --format='.LogPath' <container_name_or_id>)
或者有截断命令:
truncate -s 0 $(docker inspect --format='.LogPath' <container_name_or_id>)
我不是其中任何一个的忠实粉丝,因为它们直接修改 Docker 的文件。当 docker 将 json 格式的数据写入文件时,可能会发生外部日志删除,从而导致部分行,并破坏从docker logs
cli 读取任何日志的能力。有关发生这种情况的示例,请参阅this comment on duketwo's answer:
清空日志文件后,我收到此错误:
error from daemon in stream: Error grabbing logs: invalid character '\x00' looking for beginning of value
相反,您可以让 Docker 自动为您轮换日志。如果您使用默认的JSON logging driver,则可以通过向 dockerd 附加标志来完成此操作:
dockerd ... --log-opt max-size=10m --log-opt max-file=3
您也可以将其设置为您的daemon.json 文件的一部分,而不是修改您的启动脚本:
"log-driver": "json-file",
"log-opts": "max-size": "10m", "max-file": "3"
这些选项需要配置为具有 root 访问权限。确保在更改此文件以应用设置后运行systemctl reload docker
。然后,此设置将成为任何新创建容器的默认设置。请注意,需要删除并重新创建现有容器才能接收新的日志限制。
可以将类似的日志选项传递给各个容器以覆盖这些默认值,从而允许您在各个容器上保存更多或更少的日志。从docker run
看起来像:
docker run --log-driver json-file --log-opt max-size=10m --log-opt max-file=3 ...
或在撰写文件中:
version: '3.7'
services:
app:
image: ...
logging:
options:
max-size: "10m"
max-file: "3"
为了节省更多空间,您可以从 json 日志驱动程序切换到“本地”日志驱动程序。它采用相同的 max-size 和 max-file 选项,但不是存储在 json 中,而是使用更快更小的二进制语法。这允许您在相同大小的文件中存储更多日志。 daemon.json 条目如下所示:
"log-driver": "local",
"log-opts": "max-size": "10m", "max-file": "3"
本地驱动程序的缺点是依赖于直接访问 json 日志的外部日志解析器/转发器将不再工作。因此,如果您使用诸如 filebeat 之类的工具发送到 Elastic 或 Splunk 的通用转发器,我会避免使用“本地”驱动程序。
我的Tips and Tricks presentation 对此有更多的了解。
【讨论】:
我做了一个service docker restart
,它本身不起作用。还必须在它生效之前创建新的容器。即只是调出旧容器并没有应用新的日志记录
我使用的是 Docker 1.13.1,并且 'docker inspect --format='.LogPath' Linux/Ubuntu:
如果您有多个容器,并且只想删除一个日志而不删除其他日志。
(如果您遇到“权限被拒绝”之类的问题,请先执行sudo su
。)
列出所有容器:docker ps -a
查找所需的容器并复制CONTAINER ID
。示例:E1X2A3M4P5L6
。
容器文件夹和实名比E1X2A3M4P5L6
长,但前12个字符是docker ps -a
的结果。
仅删除该日志:
> /var/lib/docker/containers/E1X2A3M4P5L6*/E1X2A3M4P5L6*-json.log
(替换 E1X2A3M4P5L6
为您的结果!!)
如您所见,/containers
内部是容器,并且日志具有相同的名称,但末尾带有 -json.log
。您只需要知道前 12 个字符,因为*
表示“任何东西”。
【讨论】:
好吧,我在你说“*”的地方完成了标签,它可以工作,谢谢。 而> /var/lib/...
不起作用,但echo >/var/lib/...
起作用。【参考方案8】:
sudo find /var/lib/docker/containers/ -type f -name "*.log" -delete
【讨论】:
社区鼓励在代码中添加解释,而不是纯粹基于代码的答案(参见here)。【参考方案9】:要删除/清除 docker 容器日志,我们可以使用以下命令
$(docker inspect container_id|grep "LogPath"|cut -d """ -f4) 要么 $(docker inspect container_name|grep "LogPath"|cut -d """ -f4)
【讨论】:
【参考方案10】:这里是一个清除docker容器日志的跨平台解决方案:
docker run --rm -v /var/lib/docker:/var/lib/docker alpine sh -c "echo '' > $(docker inspect --format='.LogPath' CONTAINER_NAME)"
将此粘贴到您的终端并将CONTAINER_NAME
更改为所需的容器名称或ID。
【讨论】:
对我来说,这是在 Windows 上使用 wsl2 时删除日志的唯一有效解决方案。然而,这可能会导致一些配置问题 - 理论上应该可以从 wsl2 发行版(例如 ubuntu)访问 docker 日志,但这对我不起作用。 @Nicramus 我在 windows 下的-v
选项有问题:docker: Error response from daemon: mkdir C:\Program Files\Git\var: Access is denied.
不要使用 Git-for-Windows bash(MingW),因为它将 git 安装文件夹挂载为文件系统树的虚拟根目录。尝试 Ubuntu for Windows 并在其中运行 docker。或者,使用 Docker for Windows 并找出这些日志文件的位置并删除它们。
在 Linux 机器上运行良好。谢谢!【参考方案11】:
我需要一些可以作为一个命令运行的东西,而不必编写 docker ps
并复制每个容器 ID 并多次运行该命令。我改编了BMitch's answer,并认为我会分享以防其他人发现这很有用。
混合xargs
似乎可以满足我的需要:
docker ps --format='.ID' | \
xargs -I sh -c 'echo > $(docker inspect --format=".LogPath" )'
这会抓取docker ps
列出的每个容器 ID(将删除该列表中任何容器的日志!),将其通过管道传输到 xargs
,然后回显一个空白字符串以替换日志容器的路径。
【讨论】:
【参考方案12】:用途:
truncate -s 0 /var/lib/docker/containers/*/*-json.log
你可能需要 sudo
sudo sh -c "truncate -s 0 /var/lib/docker/containers/*/*-json.log"
参考。杰夫 S.How to clear the logs properly for a Docker container?
参考:Truncating a file while it's being used (Linux)
【讨论】:
截断:无法打开'/var/lib/docker/containers/*/*-json.log'进行写入:没有这样的文件或目录 @BTRNaidu 你必须以root/sudo 运行它,否则containers
的内容不可用。
sudo sh -c "truncate -s 0 /var/lib/docker/containers/*/*-json.log"
- 为我工作
忽略上面两位专业人士。如果您不确定,您可以使用“ls /var/lib/docker/containers/*/*-json.log”检查被截断的内容。
这个答案完美无缺。在我看来,这应该是公认的答案【参考方案13】:
我更喜欢这个(来自上面的解决方案):
truncate -s 0 /var/lib/docker/containers/*/*-json.log
但是,我正在运行多个系统(例如 Ubuntu 18.x Bionic),但此路径无法按预期工作。 Docker是通过Snap安装的,所以容器的路径更像:
truncate -s 0 /var/snap/docker/common/var-lib-docker/containers/*/*-json.log
【讨论】:
【参考方案14】:在我的 Ubuntu 服务器上,即使是 sudo,我也会得到 Cannot open ‘/var/lib/docker/containers/*/*-json.log’ for writing: No such file or directory
但是结合 docker 检查和截断答案是有效的:
sudo truncate -s 0 `docker inspect --format='.LogPath' <container>`
【讨论】:
【参考方案15】:您不能直接通过 Docker 命令执行此操作。
您可以限制日志的大小,也可以使用脚本删除与容器相关的日志。您可以在此处找到脚本示例(从底部阅读):Feature: Ability to clear log history #1083
查看 docker-compose 文件参考的logging section,您可以在其中为某些日志记录驱动程序指定选项(例如日志轮换和日志大小限制)。
【讨论】:
【参考方案16】:Docker4Mac,2018 年的解决方案:
LOGPATH=$(docker inspect --format='.LogPath' <container_name_or_id>)
docker run -it --rm --privileged --pid=host alpine:latest nsenter -t 1 -m -u -n -i -- truncate -s0 $LOGPATH
第一行获取日志文件路径,类似于接受的答案。
第二行使用nsenter
,它允许您在xhyve
VM 中运行命令,该 VM 作为 Docker4Mac 下所有 docker 容器的主机。我们运行的命令是来自非 Mac 答案的熟悉的 truncate -s0 $LOGPATH
。
如果你使用docker-compose
,第一行变成:
local LOGPATH=$(docker inspect --format='.LogPath' $(docker-compose ps -q <service>))
而<service>
是您的docker-compose.yml
文件中的服务名称。
感谢https://github.com/justincormack/nsenter1 提供nsenter
技巧。
【讨论】:
要截断所有容器的日志,您可以使用 shell 通配符,如其他答案所示,因此它只是一个命令:docker run -it --rm --privileged --pid=host alpine:latest nsenter -t 1 -m -u -n -i -- sh -c 'truncate -s0 /var/lib/docker/containers/*/*-json.log'
【参考方案17】:
作为 root 用户,尝试运行以下命令:
> /var/lib/docker/containers/*/*-json.log
或
cat /dev/null > /var/lib/docker/containers/*/*-json.log
或
echo "" > /var/lib/docker/containers/*/*-json.log
【讨论】:
【参考方案18】:sudo sh -c "truncate -s 0 /var/lib/docker/containers/*/*-json.log"
【讨论】:
获取日志sudo sh -c "du -ch /var/lib/docker/containers/*/*-json.log"
的大小,只获取日志的总大小sudo sh -c "du -ch /var/lib/docker/containers/*/*-json.log | grep total"
dockerd/aufs 不知道并且无法删除轮换的日志文件有什么问题吗?
这个命令对我有用,而这个 SO 中的其他命令没有。如果重要的话,我在 CentOS 7 上运行 Docker 版本 18【参考方案19】:
Docker for Mac 用户,这里是解决方案:
通过以下方式查找日志文件路径:
$ docker inspect | grep log
SSH进入docker机器(假设名称是default
,如果不是,运行docker-machine ls
查找):
$ docker-machine ssh default
改成root用户(reference):
$ sudo -i
删除日志文件内容:
$ echo "" > log_file_path_from_step1
【讨论】:
docker-machine 不适用于 Docker for Mac。您可以改为运行 “泊坞窗运行-ti -v在/ var / lib中/泊坞窗/容器:在/ var / CentOS的成立庆典”,然后“截断--size 0 /var/inception/08d29a7d469232cfef4456dc6eebcbf313bf01ba73e479520a036150c5ab84de/08d29a7d469232cfef4456dc6eebcbf313bf01ba73e479520a036150c5ab84de-json.log" 你可以使用docker exec -it default sh
在容器中进入一个sh shell。但是,许多容器不会隐式地使sudo
命令可用。【参考方案20】:
您可以设置 logrotate 定期清除日志。
/etc/logrotate.d/docker-logs 中的示例文件
/var/lib/docker/containers/*/*.log
rotate 7
daily
compress
size=50M
missingok
delaycompress
copytruncate
【讨论】:
我该如何使用它?它与docker run
一起用作默认值?文件/etc/logrotate.d/docker-logs
不存在,我必须创建它吗?
您必须调用 logrotate 实用程序 (logrotate "log-opts"
)
logrotate
可能已经设置好了。在我的 Ubuntu 20.04 服务器上,它被设置为 cron 作业:cat /etc/cron.daily/logrotate
。尝试sudo logrotate -d /etc/logrotate.conf
进行试运行,看看新创建的/etc/logrotate.d/docker-logs
是否完成了它应该做的事情。以上是关于Docker:如何正确清除 Docker 容器的日志?的主要内容,如果未能解决你的问题,请参考以下文章