多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Docker daemon.json 配置全解析:从基础到生产环境调优

Docker daemon.json 配置全解析:从基础到生产环境调优 1. 项目概述为什么你需要深入了解 daemon.json如果你用过 Docker大概率在某个教程里见过让你修改/etc/docker/daemon.json这个文件的命令。很多人只是照抄改个镜像源地址就完事了觉得这不过是个简单的配置文件。但在我过去几年里从单机开发到大规模生产环境部署踩过的坑、调过的优很多问题的根源和解决方案最终都指向了这个不起眼的daemon.json文件。它远不止是换个镜像仓库那么简单而是 Docker 引擎的“中枢神经”直接决定了 Docker 守护进程也就是dockerd的几乎所有核心行为。简单来说daemon.json是 Docker 守护进程的配置文件。当你启动dockerd时它会读取这个文件并据此调整自己的运行时参数。这些参数覆盖了从最基础的存储驱动、日志配置到网络模型、安全策略再到资源限制和集群配置等方方面面。你不配置它Docker 就用默认值跑这在大多数开发场景下没问题。但一旦你的需求稍微复杂一点比如需要优化磁盘空间、集中管理日志、构建私有镜像仓库网络、或者为容器设置更严格的安全边界daemon.json就是你必须掌握的工具。网上很多文章只零散地介绍一两个配置项缺乏系统性的梳理和实战场景的串联。今天我就结合自己趟过的路把这个文件里里外外、从原理到实操给你讲透。无论你是刚入门的新手还是已经用 Docker 跑着生产服务的老手相信都能从中找到对你有用的东西。我们不止讲“怎么配”更重点讲“为什么这么配”以及“配错了会怎样”。2. daemon.json 的核心作用与文件解析2.1 配置文件的位置与优先级首先我们得找到它。daemon.json的默认位置在 Linux 系统上是/etc/docker/daemon.json。在 Windows Docker Desktop 上其配置通常通过 GUI 界面管理但底层对应的是%programdata%\docker\config\daemon.json。对于 macOS 的 Docker Desktop情况类似配置文件路径通常不直接暴露给用户修改而是通过桌面应用设置。这里有个关键点daemon.json的配置会与 Docker 守护进程启动时通过命令行传入的参数dockerd --xxx合并但如果有冲突命令行参数的优先级更高。这意味着如果你用systemd管理 Docker 服务绝大多数 Linux 发行版都是你可能会在/etc/systemd/system/docker.service.d/目录下的覆盖文件里看到用ExecStart定义的命令行参数。在修改daemon.json前最好用systemctl cat docker命令检查一下是否有这类覆盖避免配置不生效。文件本身是标准的 JSON 格式这意味着它对语法要求很严格键名必须用双引号字符串值也要用双引号最后一个配置项后不能有逗号。一个格式错误的 JSON 文件会导致 Docker 守护进程无法启动。我常用的验证方法是sudo docker info如果配置生效你会在输出中看到对应的配置项或者直接用sudo json_pp /etc/docker/daemon.json来检查 JSON 格式是否正确。2.2 配置项的分类与逻辑层次daemon.json的配置项非常多但我们可以从功能上将其分为几个清晰的层次这有助于我们理解和管理引擎基础配置层这层配置定义了 Docker 引擎如何与操作系统底层交互。主要包括存储驱动 (storage-driver)决定容器和镜像的数据如何在磁盘上组织和管理如overlay2,devicemapper,zfs等。选择不当会严重影响 I/O 性能和稳定性。数据根目录 (>{ “storage-driver”: “overlay2”, “data-root”: “/data/docker” }修改>{ “registry-mirrors”: [ “https://registry.docker-cn.com”, “https://hub-mirror.c.163.com”, “https://mirror.baidubce.com” ] }配置后当你执行docker pull ubuntu:latest时Docker 会依次尝试从这些镜像站拉取如果镜像站有缓存速度会快很多。你可以通过docker info查看当前生效的镜像仓库列表。场景二连接内网私有仓库如果你的公司在内网搭建了 Harbor、Nexus 或简单的docker registry服务并且没有配置有效的 HTTPS 证书比如用了自签名证书或直接用了 HTTP就需要将其添加到insecure-registries中否则 Docker 会拒绝连接。{ “insecure-registries”: [ “myregistry.example.com:5000”, “192.168.1.100:5000” ] }重要安全提示insecure-registries意味着与该仓库的通信是不加密的镜像内容可能被窃听或篡改。仅限在完全受信任的内网环境使用。对于任何公网或跨网络访问必须为仓库配置有效的 TLS 证书。3.3 日志驱动配置 (log-driverlog-opts)默认的日志驱动是json-file它将每个容器的标准输出和错误流以 JSON 格式记录在主机文件系统中。这在开发时没问题但在生产环境尤其是容器数量多、日志量大的情况下会导致主机磁盘被快速写满且不便于集中查询分析。生产环境推荐配置日志大小与数量限制即使使用json-file也强烈建议配置日志轮转策略。{ “log-driver”: “json-file”, “log-opts”: { “max-size”: “10m”, // 单个日志文件最大10MB “max-file”: “3” // 最多保留3个归档日志文件当前文件2个历史文件 } }这个配置意味着当一个容器的日志文件达到10MB时Docker 会将其重命名为带时间戳的归档文件并创建一个新的空日志文件。最多保留3个文件例如container-id-json.log,container-id-json.log.1,container-id-json.log.2更旧的会被自动删除。这能有效防止单个容器日志无限膨胀。进阶场景集成中央日志系统在生产环境中更佳实践是将日志直接发送到如fluentd、logstash或syslog等中央日志聚合系统。{ “log-driver”: “syslog”, “log-opts”: { “syslog-address”: “tcp://192.168.1.200:514”, “tag”: “{{.Name}}” // 使用容器名作为 syslog 消息的标签 } }或者使用fluentd{ “log-driver”: “fluentd”, “log-opts”: { “fluentd-address”: “192.168.1.201:24224”, “tag”: “docker.{{.Name}}” } }配置了中央日志驱动后容器自身的docker logs命令可能就无法查看历史日志了因为日志不再或不仅存储在本地文件。所有日志的查询和分析都应在日志聚合平台进行。3.4 网络自定义 (bip,default-address-pools)Docker 默认会创建一个名为docker0的网桥并为其分配一个私有 IP 段通常是172.17.0.1/16。如果你的宿主机网络环境与此默认网段冲突或者你需要规划一个更合理的容器网络地址空间就需要修改这些配置。bip(Bridge IP)用于设置docker0网桥本身的 IP 地址和子网。{ “bip”: “192.168.100.1/24” }这会将docker0的 IP 设为192.168.100.1并为容器分配192.168.100.2到192.168.100.254的地址。default-address-pools这个配置更强大它用于定义创建自定义网络docker network create时使用的默认 IP 地址池。在大型或多租户环境中合理规划地址池可以避免网络冲突。{ “default-address-pools”: [ { “base”: “10.10.0.0/16”, “size”: 24 } ] }这个配置意味着当创建一个新的自定义网络时Docker 会从10.10.0.0/16这个大池子里划出一个/24即10.10.x.0/24的子网给这个网络。第一个网络可能是10.10.1.0/24第二个是10.10.2.0/24以此类推。size定义了每个子网的大小。修改网络配置的注意事项修改网络相关配置后通常需要重启 Docker 守护进程。重启会导致所有正在运行的容器网络中断容器本身不会停止但会暂时失去网络连接。因此这类变更应在维护窗口进行。4. 高级配置与生产环境调优当 Docker 用于生产环境承载关键业务时一些高级配置能显著提升稳定性、安全性和可维护性。4.1 资源限制与默认 ulimits (default-ulimits)虽然可以在运行容器时通过--ulimit参数为单个容器设置限制但通过daemon.json设置默认值可以确保所有新创建的容器都遵循一套基线安全策略防止某个容器耗尽主机资源如文件描述符、进程数。{ “default-ulimits”: { “nofile”: { “Name”: “nofile”, “Hard”: 65536, “Soft”: 65536 }, “nproc”: { “Name”: “nproc”, “Hard”: 2048, “Soft”: 1024 } } }这里设置了两个常见的限制nofile每个容器内进程能打开的最大文件描述符数量统一设置为 65536。nproc每个容器内用户能创建的最大进程数。Soft是警告值Hard是绝对上限。这里设置为软限制1024硬限制2048。实操心得设置nproc时要特别注意。如果容器内运行的应用如 Java 应用会创建很多线程而 Linux 中线程也算作进程过低的nproc限制可能导致应用报“无法创建新线程”的错误。建议根据容器内应用的实际需求来调整这个值。4.2 启用用户命名空间映射 (userns-remap)这是 Docker 一项重要的安全特性。默认情况下容器内的root用户UID 0映射到宿主机的root用户。这意味着如果容器被攻破攻击者理论上在宿主机上也有root权限。用户命名空间重映射可以将容器内的 UID/GID 映射到宿主机上一个无特权的、范围受限的 UID/GID 上实现权限隔离。配置相对复杂需要先准备用户和子UID映射。创建专用于 Docker 的用户和组例如dockremapsudo useradd -r -s /bin/false dockremap配置/etc/subuid和/etc/subgid为dockremap用户分配一段从属 UID/GID。# /etc/subuid dockremap:100000:65536 # /etc/subgid dockremap:100000:65536这表示将宿主机上从 100000 开始的 65536 个 UID/GID 映射给容器内的dockremap用户使用。容器内的 UID 0 会被映射为宿主机的 UID 100000。在daemon.json中启用{ “userns-remap”: “dockremap” }重启 Docker 后所有新创建的容器都会应用此映射。注意启用此功能后原有的镜像和容器数据可能需要重新处理权限因为文件所有者变成了高位的 UID。通常建议在新部署的 Docker 环境中启用此功能。4.3 配置 Docker 守护进程的监听地址 (hosts)默认情况下Docker 守护进程只监听本地的 Unix 套接字/var/run/docker.sock。这意味着只有本地用户通常是 root 或 docker 组成员才能执行 Docker 命令。有时为了配合 CI/CD 工具如 Jenkins Agent 不在同一台机器或集群管理工具需要让 Docker 监听 TCP 端口。这是一个极高风险的配置必须与 TLS 客户端证书认证结合使用否则等同于将 root 权限开放给网络上的任何人。{ “hosts”: [“unix:///var/run/docker.sock”, “tcp://0.0.0.0:2376”], “tls”: true, “tlscacert”: “/etc/docker/ca.pem”, “tlscert”: “/etc/docker/server-cert.pem”, “tlskey”: “/etc/docker/server-key.pem”, “tlsverify”: true }这个配置让 Docker 同时监听本地套接字和所有网络接口的 2376 端口并强制要求 TLS 加密和客户端证书验证。客户端必须使用由相同 CA 签发的证书才能连接。关于如何生成这些证书可以参考 Docker 官方文档的“Protect the Docker daemon socket”部分。绝对不要在没有 TLS 验证的情况下配置 TCP 监听。5. 配置生效、调试与故障排查修改了daemon.json如何让它生效出了问题怎么查这是最后也是最关键的一环。5.1 配置生效的正确流程编辑配置文件sudo vim /etc/docker/daemon.json检查 JSON 语法sudo json_pp /etc/docker/daemon.json或使用在线 JSON 校验工具。一个多余的逗号、缺失的双引号都会导致失败。重载守护进程配置对于大多数配置需要重启 Docker 服务。sudo systemctl daemon-reload # 重载 systemd 配置 sudo systemctl restart docker # 重启 Docker 服务验证配置sudo systemctl status docker查看服务状态确保重启成功。sudo docker info是查看绝大多数daemon.json配置是否生效的最佳命令。仔细查看输出找到你修改的对应项。对于网络配置可以运行sudo docker network inspect bridge查看docker0网桥的当前设置。对于日志配置可以运行一个测试容器sudo docker run --rm -it alpine echo “test log”然后去/var/lib/docker/containers/...下查看日志文件大小或者检查你的日志聚合系统。5.2 常见问题与排查技巧问题一修改daemon.json后Docker 无法启动。这是最常见的问题通常是 JSON 语法错误或配置项值错误。排查方法使用sudo journalctl -u docker --since “5 minutes ago”查看 Docker 服务的详细日志。错误信息通常会明确指出哪一行配置有问题比如invalid character ‘,’或unknown configuration option。如果日志看不出来可以尝试逐行注释掉daemon.json中新添加的配置每次注释一部分后重启 Docker用二分法定位问题配置项。检查配置项的名称和值类型。例如registry-mirrors的值必须是数组[]即使只有一个镜像地址log-opts的值必须是对象{}。问题二配置看似生效但容器行为不符合预期。可能原因配置项被更高优先级的设置覆盖。例如通过systemd的ExecStart参数传递了冲突的配置。排查方法运行sudo systemctl cat docker查看是否有[Service]部分覆盖了ExecStart。如果有类似ExecStart/usr/bin/dockerd -H fd:// --containerd/run/containerd/containerd.sock --dns 8.8.8.8这样的行那么命令行参数--dns 8.8.8.8的优先级高于daemon.json中的dns配置。你需要修改这个 systemd 覆盖文件通常在/etc/systemd/system/docker.service.d/下或者将参数移到daemon.json中。问题三修改>
返回列表