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' ' 返回一个空字符串 ("")....但我仍然从'docker logs '获得输出?!?这是从哪里来的,我该如何清除它?? @AlexisWilke 如果您能够停止 docker,那么您很可能能够停止您的容器。如果您可以执行后者,那么我的建议是使用日志记录选项重新创建容器。新容器没有旧日志,新日志会自动滚动,同时解决短期和长期问题。 如果这不是生产环境,那么我会说简单地停止容器,截断日志,然后重新启动容器是安全的。 @Vitaliy 重申我上面的评论,如果您可以停止容器,您还应该能够使用自动轮换日志的选项重新创建容器。【参考方案7】:

Linux/Ubuntu:

如果您有多个容器,并且只想删除一个日志而不删除其他日志。

如果您遇到“权限被拒绝”之类的问题,请先执行sudo su) 列出所有容器:docker ps -a 查找所需的容器并复制CONTAINER ID。示例:E1X2A3M4P5L6。 容器文件夹和实名比E1X2A3M4P5L6长,但前12个字符是docker ps -a的结果。 仅删除该日志: &gt; /var/lib/docker/containers/E1X2A3M4P5L6*/E1X2A3M4P5L6*-json.log(替换 E1X2A3M4P5L6 为您的结果!!)

如您所见,/containers 内部是容器,并且日志具有相同的名称,但末尾带有 -json.log。您只需要知道前 12 个字符,因为* 表示“任何东西”。

【讨论】:

好吧,我在你说“*”的地方完成了标签,它可以工作,谢谢。 &gt; /var/lib/... 不起作用,但echo &gt;/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>))

&lt;service&gt; 是您的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 "" &gt; 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 ),它将读取您的配置并运行清理。例如,您还可以将其设置为 cron 作业。 这个的问题是它可能与 docker 正在做的事情没有正确同步。使用 docker 设施可能更明智。 (BMitch 显示的"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 容器的日志?的主要内容,如果未能解决你的问题,请参考以下文章

将日志输出到Docker容器外

Docker学习之Docker容器基本使用

markdown Docker清除图像和容器

sh 清除所有Docker容器和/或图像

如何知道 docker 容器中的哪些数据能够正确地将其映射为卷

docker 常用命令