Docker日志太多?磁盘爆了?一篇教你搞定容器日志问题

在使用 Docker 时,容器日志的无限制增长可能会导致磁盘空间被快速占满,甚至引发服务崩溃。哥们带你将从问题定位、临时解决方案、长期优化策略三个层面,手把手教你彻底解决 Docker 日志问题。 一、问题定位:日志文件在哪? 通常情况下位于Docker容器的日志默认存储在宿主机的以下路径中: /var/lib/docker/containers/<container_id>/<container_id>-json.log 取决于你的 docker 存储目录,如需修改请结合个人环境以及项目条件进行修改,每个容器生成的日志文件通常以 *-json.log 结尾。 快速检查磁盘占用: # 查看磁盘使用情况 df -h # 找出日志目录占用空间最大的容器 cd /var/lib/docker/containers/ du -sh * | sort -nr | head -n 20 二、临时解决方案:快速释放磁盘空间 方法一:使用 truncate 清空日志 # 替换为实际容器ID container_id="your_container_id" truncate -s 0 /var/lib/docker/containers/${container_id}/*-json.log 优势:保留文件 inode,不会中断正在写入的日志进程。 方法二:使用 echo 清空日志 echo "" > /var/lib/docker/containers/${container_id}/*-json.log 注意:可能导致日志文件 inode 变化,建议优先使用 truncate。 其实某些情况下你也可以使用docker system prune -a来进行清理未使用的容器、镜像、网络和卷。 三、长期优化策略 方法一:配置日志轮转(Log Rotation) 通过 logrotate 工具自动管理日志文件的大小和保留时间。 创建配置文件 /etc/logrotate.d/docker-container-logs: vim /etc/logrotate.d/docker-container-logs /var/lib/docker/containers/*/*.log { rotate 7 # 保留7天日志 daily # 每天轮转一次 compress # 压缩旧日志 missingok # 文件缺失不报错 notifempty # 空文件不轮转 copytruncate # 截断原始文件前复制 } 方法二:限制单个日志文件大小 在启动容器时,通过 --log-opt 参数限制日志文件的大小和数量: ...

六月 26, 2025 · 1 分钟 · iren.

利用CloudFlare来实现镜像加速

目前可用加速镜像仓库 DockerProxy 代理加速:dockerproxy.com 百度云 Mirror: mirror.baidubce.com Daocloud: docker.m.daocloud.io 南京大学:docker.nju.edu.cn 上海交大:docker.mirrors.sjtug.sjtu.edu.cn sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-EOF { "registry-mirrors": [ "https://<changme>.mirror.aliyuncs.com", "https://dockerproxy.com", "https://mirror.baidubce.com", "https://docker.m.daocloud.io", "https://docker.nju.edu.cn", "https://docker.mirrors.sjtug.sjtu.edu.cn" ] } EOF sudo systemctl daemon-reload sudo systemctl restart docker 准备工作 注册CloudFlare账号 开始自建CloudFlare仓库 首先进入cloudflare创建一个Workers,创建完成以后点击编辑代码 编辑Woker.js文件 import HTML from './docker.html'; export default { async fetch(request) { const url = new URL(request.url); const path = url.pathname; const originalHost = request.headers.get("host"); const registryHost = "registry-1.docker.io"; if (path.startsWith("/v2/")) { const headers = new Headers(request.headers); headers.set("host", registryHost); const registryUrl = `https://${registryHost}${path}`; const registryRequest = new Request(registryUrl, { method: request.method, headers: headers, body: request.body, // redirect: "manual", redirect: "follow", }); const registryResponse = await fetch(registryRequest); console.log(registryResponse.status); const responseHeaders = new Headers(registryResponse.headers); responseHeaders.set("access-control-allow-origin", originalHost); responseHeaders.set("access-control-allow-headers", "Authorization"); return new Response(registryResponse.body, { status: registryResponse.status, statusText: registryResponse.statusText, headers: responseHeaders, }); } else { return new Response(HTML.replace(/{{host}}/g, originalHost), { status: 200, headers: { "content-type": "text/html" } }); } } } 编辑器内新建docker.html <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>镜像使用说明</title> <style> body { font-family: 'Roboto', sans-serif; margin: 0; padding: 0; background-color: #f4f4f4; } .header { background: linear-gradient(135deg, #667eea, #764ba2); color: #fff; padding: 20px 0; text-align: center; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); } .container { max-width: 800px; margin: 40px auto; padding: 20px; background-color: #fff; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); border-radius: 10px; } .content { margin-bottom: 20px; } .footer { text-align: center; padding: 20px 0; background-color: #333; color: #fff; } pre { background-color: #272822; color: #f8f8f2; padding: 15px; border-radius: 5px; overflow-x: auto; } code { font-family: 'Source Code Pro', monospace; } a { color: #4CAF50; text-decoration: none; } a:hover { text-decoration: underline; } @media (max-width: 600px) { .container { margin: 20px; padding: 15px; } .header { padding: 15px 0; } } </style> <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&family=Source+Code+Pro:wght@400;700&display=swap" rel="stylesheet"> </head> <body> <div class="header"> <h1>镜像仓库Hub加速说明</h1> </div> <div class="container"> <div class="content"> <p>为了加速镜像拉取,你可以使用以下命令设置 registry mirror:</p> <pre><code>sudo tee /etc/docker/daemon.json &lt;&lt;EOF { "registry-mirrors": ["https://{{host}}"] } EOF</code></pre> <p>为了避免 Worker 用量耗尽,你可以手动 pull 镜像然后 re-tag 之后 push 至本地镜像仓库:</p> <pre><code>docker pull {{host}}/library/alpine:latest # 拉取 library 镜像 docker pull {{host}}/coredns/coredns:latest # 拉取 coredns 镜像</code></pre> </div> </div> <div class="footer"> <p>Powered by Cloudflare Workers</p> <p><a href="https://blog.mletter.cn" target="_blank">技术支持: Cloudflare && 春日心动日记</a></p> </div> </body> </html> 点击右侧的部署 ...

七月 16, 2024 · 2 分钟 · iren.

优雅的多阶段构建微服务镜像

借助Maven Wrapper 首先我们说说maven wrapper的使用场景 假设我们所在的团队同时维护多个项目,不同的项目使用的JDK版本不同,使用的maven版本也不同,那么为了支持多项目开发,为了构建运行效果一致,你可能需要在本地管理多个maven版本,这会非常繁琐,从而引出了maven wrapper来解决这个maven版本的管理问题。 版本一致性:通过在mvnw配置中指定 Maven 版本,确保所有开发人员和持续集成环境使用相同的maven版本。 简化批量安装:不需要预先安装maven,直接运行mvnw命令就如安装了mvn一样,从而简化了项目的初始设置和配置。 Maven Wrapper安装方式 maven-wrapper: 提供maven-wrapper.jar下载、安装和运行目标maven发行版。 maven-wrapper-distribution: 提供mvnw/mvnw.cmd脚本发行版, maven-wrapper-plugin: wrapper用于轻松将 Wrapper 安装到项目中的插件。 首先安装maven wrapper,默认情况下安装的是only-script版本,也就是精简版,不需要额外的maven-wrapper.jar。如果你需要安装source版本请使用-Dtype=source参数。 # 假设你的本地已经有了一个特定版本的maven,可以直接通过如下命令进行引入 mvn -N wrapper:wrapper # 当然也可以指定引入的maven版本信息 mvn -N wrapper:wrapper -Dmaven=3.6.1 检查是否安装成功,正常来讲是会出现一个mvnw和mvnw.cmd以及.mvn目录 [root@localhost maven-wrapper]# tree -fa . ├── ./.mvn │ └── ./.mvn/wrapper │ └── ./.mvn/wrapper/maven-wrapper.properties ├── ./mvnw └── ./mvnw.cmd 2 directories, 3 files 修改maven-wrapper.properties定义的路径地址,因为用的是官方地址可能由于墙的问题无法进行下载,我这边采用MinioS3的地址来提前下好相关版本的maven包进行上传。 wrapperVersion=3.3.1 distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.1/apache-maven-3.6.1-bin.zip # 正常修改distributionUrl的地址就可以了 distributionUrl=http://10.1.6.15:10240/software/apache-maven-3.6.1-bin.zip 正常能检测到相关的版本即表示成功 [root@localhost maven-wrapper]# ./mvnw --version Apache Maven 3.6.1 (d66c9c0b3152b2e69ee9bac180bb8fcc8e6af555; 2019-04-05T03:00:29+08:00) Maven home: /root/.m2/wrapper/dists/apache-maven-3.6.1/5256b4e Java version: 1.8.0_391, vendor: Oracle Corporation, runtime: /usr/local/java/jre Default locale: en_US, platform encoding: UTF-8 OS name: "linux", version: "4.18.0-372.9.1.el8.x86_64", arch: "amd64", family: "unix" 遇到小问题 如果大家在构建的过程中遇到了小问题可以看看小思路 ...

五月 8, 2024 · 3 分钟 · iren.

Docker常见的几个问题处理

Docker迁移存储目录 问题起因 由于公司最开始的服务器在/var/lib/docker没有挂载存储,容量只有40G,导致服务器磁盘用满。现将原有的Docker目录数据进行迁移。 请各位Kubernetes用户不要操作,因为容器编排不支持! # 启动容器发现如下报错 ERROR:cannot create temporary directory! 方法一: 软连接方式 # 1.停止docker服务 systemctl stop docker # 2.开始迁移目录 mv /var/lib/docker /data/ # 使用cp命令也可以 cp -arv /var/lib/docker /data/docker # 3.添加软链接 ln -s /data/docker /var/lib/docker # 4.启动docker服务 systemctl start docker 方法二: 修改docker配置文件 注意: 这是一个旧版本docker修改存储目录的方式. vim /etc/docker/daemon.json { "graph": [ "/data/docker/" ] # 更改docker镜像的存储目录 } 新版本修改存储目录方式 # 请找到你的docker.service存放位置 vim /usr/lib/systemd/system/docker.service 通过加入--data-root=/data/docker进行修改默认的数据存储位置 [Unit] Description=Docker Application Container Engine Documentation=https://docs.docker.com After=network-online.target firewalld.service Wants=network-online.target [Service] Type=notify ExecStart=/usr/bin/dockerd --data-root=/data/docker ExecReload=/bin/kill -s HUP $MAINPID LimitNOFILE=infinity LimitNPROC=infinity TimeoutStartSec=0 Delegate=yes KillMode=process Restart=on-failure StartLimitBurst=3 StartLimitInterval=60s [Install] WantedBy=multi-user.target 修改完成之后重启docker ...

七月 14, 2022 · 2 分钟 · iren.

什么是dockershim

先前了解 参考链接 Githubissue kubelet中的Docker支持现在已弃用,并将在未来的版本中删除。kubelet使用了一个名为dockershim的模块,该模块实现了对Docker的CRI支持,并在Kubernetes社区中发现了维护问题。我们鼓励您评估迁移到一个容器运行时的情况,该容器运行时是CRI(v1alpha1或v1兼容)的完整实现。 也就是说,在后续的Kubernetes1.20x版本以后会删除dockershim组件,但是由于目前Docker的使用用户众多,中间必然会有替换的一个过渡期,所以大家可以更多的关注一下其他的Container Runtime。 例如我们的Podman、Containerd、cri-o等其他容器运行时来运行kubernetes。 下面我们就具体来看看Kubernetes所提到的弃用dockershim到底是什么东西. CRI容器运行时接口 参考链接 CRI:容器运行时接口 container runtime interface,CRI 中定义了容器和镜像两个接口,实现了这两个接口目前主流的是:CRI-O、Containerd。(目前 PCI 产品使用的即为 Containerd)。 CRI接口的具体用处就在于 对容器操作的接口,包括容器的创建、启动和停止.即create、stop等操作。 对镜像的操作,下载、删除镜像等. 即pull、rmi等操作。 podsandbox OCI开放容器标准 OCI:开放容器标准 open container initiative,OCI 中定义了两个标准:容器运行时标准 和 容器镜像标准,实现了这一标准的主流是:runc(也即我们日常说的 Docker)、Kata-Container。 OCI的作用在于 ImageSpec(容器标准包) 文件系统:以 layer 保存的文件系统,每个 layer 保存了和上层之间变化的部分,layer 应该保存哪些文件,怎么表示增加、修改和删除的文件等 config 文件:保存了文件系统的层级信息(每个层级的 hash 值,以及历史信息),以及容器运行时需要的一些信息(比如环境变量、工作目录、命令参数、mount 列表),指定了镜像在某个特定平台和系统的配置。比较接近我们使用 docker inspect <image_id> 看到的内容 manifest 文件:镜像的 config 文件索引,有哪些 layer,额外的 annotation 信息,manifest 文件中保存了很多和当前平台有关的信息 index 文件:可选的文件,指向不同平台的 manifest 文件,这个文件能保证一个镜像可以跨平台使用,每个平台拥有不同的 manifest 文件,使用 index 作为索引 2.runtimeSpec: ociVersion(string, REQUIRED):是该州遵守的开放容器倡议运行时规范的版本。 id: 容器的 ID。这在此主机上的所有容器中必须是唯一的。不要求它在主机之间是唯一的。 status(string, REQUIRED): 加冕时容器的几个状态 1. creating 2. created 3. running 4. stopped pid: host上看到的容器进程 bundle:host上容器bundle目录的绝对路径 annotation:容器相关的标注,可选 所以在Json的序列化时,必须遵守以下格式 ...

二月 13, 2022 · 1 分钟 · iren.