Docker:如何正确清除 Docker 容器的日志?

Docker: How to clear the logs properly for a Docker container?

我使用docker logs [container-name]查看特定容器的日志。

是否有清除这些日志的优雅方法?

首先是错误的答案。从 this question 开始,您可以 运行:

echo "" > $(docker inspect --format='{{.LogPath}}' <container_name_or_id>)

没有 echo,有更简单的:

: > $(docker inspect --format='{{.LogPath}}' <container_name_or_id>)

或者有 t运行cate 命令:

truncate -s 0 $(docker inspect --format='{{.LogPath}}' <container_name_or_id>)

我不是其中任何一个的忠实粉丝,因为它们直接修改 Docker 的文件。外部日志删除可能发生在 docker 将 json 格式的数据写入文件时,导致部分行,并破坏了从 docker logs cli 读取任何日志的能力。有关发生这种情况的示例,请参阅 :

after emptying the logfile, I get this error: 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权限。确保在更改此文件后 运行 a 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"

为了额外 space 节省,您可以从 json 日志驱动程序切换到“本地”日志驱动程序。它采用相同的 max-size 和 max-file 选项,但不是存储在 json 中,而是使用更快更小的二进制语法。这允许您在相同大小的文件中存储更多日志。 daemon.json 条目看起来像:

{
  "log-driver": "local",
  "log-opts": {"max-size": "10m", "max-file": "3"}
}

本地驱动程序的缺点是依赖于直接访问 json 日志的外部日志 parsers/forwarders 将不再有效。因此,如果您使用 filebeat 之类的工具发送到 Elastic 或 Splunk 的通用转发器,我会避免使用“本地”驱动程序。

我的 Tips and Tricks presentation.

中对此有更多介绍

您不能直接通过 Docker 命令执行此操作。

您可以限制日志的大小,或使用脚本删除与容器相关的日志。您可以在此处找到脚本示例(从底部阅读):Feature: Ability to clear log history #1083

查看 docker-compose 文件参考的 logging section,您可以在其中为某些日志记录驱动程序指定选项(例如日志轮换和日志大小限制)。

使用:

truncate -s 0 /var/lib/docker/containers/*/*-json.log

您可能需要 sudo

sudo sh -c "truncate -s 0 /var/lib/docker/containers/*/*-json.log"

参考。杰夫

参考:Truncating a file while it's being used (Linux)

您可以设置logrotate来定期清除日志。

/etc/logrotate 中的示例文件。d/docker-logs

/var/lib/docker/containers/*/*.log {
 rotate 7
 daily
 compress
 size=50M
 missingok
 delaycompress
 copytruncate
}
sudo sh -c "truncate -s 0 /var/lib/docker/containers/*/*-json.log"

Docker Mac 用户,解决方法如下:

    1. 通过以下方式查找日志文件路径:

      $ docker inspect | grep log

    1. SSH进入docker机器(假设名字是default,如果不是,运行docker-machine ls查找):

      $ docker-machine ssh default

    1. 更改为 root 用户():

      $ sudo -i

    1. 删除日志文件内容:

      $ echo "" > log_file_path_from_step1

作为 root 用户,尝试 运行 以下操作:

>  /var/lib/docker/containers/*/*-json.log

cat /dev/null > /var/lib/docker/containers/*/*-json.log

echo "" > /var/lib/docker/containers/*/*-json.log

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 虚拟机中执行 运行 命令,该虚拟机作为 Docker4[= 下所有 docker 容器的主机33=]。我们 运行 的命令是非 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/nsenter1nsenter 技巧。

在 Docker 上 Windows 和 Mac,可能还有其他人,可以使用 tail 选项。例如:

docker logs -f --tail 100

这样,只显示最后 100 行,您不必先滚动 1M 行...

(因此,删除日志可能是不必要的)

在我的 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>`

我更喜欢这个(来自上面的解决方案):

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

您还可以在 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(詹姆斯·奎格利)

不确定这是否对您有帮助,但移除容器总是有帮助的。

因此,如果您使用 docker-compose 进行设置,则只需使用 docker-compose down && docker-compose up -d 而不是 docker-compose restart。通过正确的设置(确保为持久数据使用卷装载),您不会以这种方式丢失任何数据。

当然,这比 OP 要求的要多。但是在其他答案无法提供帮助的各种情况下(如果使用远程 docker 服务器或在 Windows 机器上工作,访问底层文件系统是专有且困难的)

我需要一些我可以 运行 作为一个命令的东西,而不是必须编写 docker ps 并复制每个容器 ID 并 运行 多次执行命令。我已经改编 并认为我会分享以防其他人发现这有用。

混合 xargs 似乎可以满足我的需求:

docker ps --format='{{.ID}}' | \
  xargs -I {} sh -c 'echo > $(docker inspect --format="{{.LogPath}}" {})'

这会获取 docker ps 列出的每个容器 ID( 将删除该列表中任何容器的日志!),将其通过管道传输到 xargs 并然后回显一个空字符串来替换容器的日志路径。

这里是清除docker容器日志的跨平台解决方案:

docker run --rm -v /var/lib/docker:/var/lib/docker alpine sh -c "echo '' > $(docker inspect --format='{{.LogPath}}' CONTAINER_NAME)"

将其粘贴到您的终端并将 CONTAINER_NAME 更改为所需的容器名称或 ID。

到remove/clear docker 容器日志我们可以使用下面的命令

$(docker inspect container_id|grep "LogPath"|cut -d """ -f4) or $(docker inspect container_name|grep "LogPath"|cut -d """ -f4)

这将删除所有容器的所有日志文件:

sudo find /var/lib/docker/containers/ -type f -name "*.log" -delete

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 个字符,因为 * 表示“任何”。

感谢 ,我刚刚编写了一个 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

如果您需要在删除日志文件之前存储它们的备份,我已经创建了一个脚本来为指定的容器执行以下操作(您必须 运行 使用 sudo):

  1. 创建一个文件夹来存储压缩日志文件作为备份。
  2. 查找 运行ning 容器的 ID(由容器名称指定)。
  3. 使用随机名称将容器的日志文件复制到新位置(步骤 1 中的文件夹)。
  4. 压缩之前的日志文件(保存space)。
  5. T运行按您可以定义的特定大小分类容器的日志文件。

备注:

  • 它使用shuf命令。确保您的 linux 发行版有它或将其更改为另一个 bash 支持的随机生成器。
  • 使用前,更改变量CONTAINER_NAME以匹配您的运行ning容器;它可以是部分名称(不必是完全匹配的名称)。
  • 默认情况下它 t运行 将日志文件设置为 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 }' | 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 并按回车键保存文件。确保 script.sh 文件具有执行权限。