【问题标题】:Docker: How to clear the logs properly for a Docker container?Docker:如何正确清除 Docker 容器的日志?
【发布时间】: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] 这将只显示传入的日志

标签: docker docker-compose boot2docker docker-machine


【解决方案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 运行它):

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

注意事项:

  • 它使用 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 用户,这里是解决方案:

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

                      $ docker inspect | grep log

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

                      $ docker-machine ssh default

                    1. 改成root用户(reference):

                      $ sudo -i

                    1. 删除日志文件内容:

                      $ 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 是否完成了它应该做的事情。
                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2014-04-26
                  • 2018-05-29
                  • 2023-03-04
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2017-09-18
                  相关资源
                  最近更新 更多