># 停服务前先停 socket,否则 systemd 的 socket 激活会把它重新拉起来 systemctl stop docker.socket systemctl stop docker # -aHAX 保留权限、属主、ACL 和扩展属性,少了这几个参数容器会起不来 rsync -aHAX --numeric-ids /var/lib/docker/ /data/docker/ # 开了 SELinux 的机器必须补这一步,否则容器访问存储会权限拒绝 restorecon -R /data/docker搬完再往daemon.json里写>{ "log-driver": "json-file", "log-opts": { "max-size": "100m", "max-file": "3" } }
default-address-pools值得单独说。Docker 默认从172.17.0.0/16开始分配网桥网段,容器一多,会往上吃到172.18、172.19……如果你的宿主机或者内网正好用了这些地址段,就会出现容器能起、但连不上某个内网服务的怪现象,ping通一半、telnet不通,排查起来极其痛苦。规范做法是显式声明一个专用池,把base选在内网没用的段上,size决定每个网段切多大。
{ "default-address-pools": [ { "base": "10.201.0.0/16", "size": 24 } ] }这里的算法很直白:/16的地址池切成/24的子网,一共2^(24-16) = 256个网段,每个网段可用地址 254 个。够几百个容器网络用,同时和常见的内网/16完全不重叠。配置前建议先ip route看一眼宿主机路由表,把已有的段都列出来避开。
2.3 改完怎么生效才不出事 正确顺序只有三步:校验语法、重启服务、验证结果。第一节提到的语法校验,很多人靠"重启后看报错",效率太低。较新版本的dockerd提供了--validate参数,可以在不影响运行中服务的前提下检查配置:
dockerd --validate --config-file=/etc/docker/daemon.json输出configuration OK就放心重启。如果版本不支持这个参数,退而求其次用python3 -m json.tool /etc/docker/daemon.json检查 JSON 合法性,至少能挡住逗号和注释这类低级错误。
重启这一步要格外小心。systemctl restart docker默认会停掉所有容器,线上环境等于一次全站中断。两个办法规避:一是提前live-restore: true,它能让守护进程重启时容器继续跑(但注意它和 swarm 模式不能共用,而且网络配置的部分变更仍然需要重建容器);二是挑维护窗口,或者干脆用滚动方式一台一台改。
<注意>重启完成后别只看服务状态,一定要验证。systemctl is-active docker只告诉你进程活着,不代表配置生效了。我一般固定跑这几条:
docker info | grep -E "Storage Driver|Logging Driver|Docker Root Dir|Cgroup Driver" docker info --format '{{json .}}' | python3 -m json.tool | head -40对照你要改的字段,逐个确认。曾经有一次我把exec-opts拼成了exec-opt(少了 s),dockerd 对未知字段是忽略而不是报错,重启成功、状态正常,直到某个编排组件报 cgroup 不一致才发现配置压根没生效。这个教训让我养成了"改完必须 grep 验证"的习惯。
3. systemd 单元与环境文件:开机那一刻谁说了算 3.1 为什么不要直接改 docker.service daemon.json不是唯一的配置入口。dockerd是以 systemd 服务的形式启动的,启动命令写在/usr/lib/systemd/system/docker.service里,形如ExecStart=/usr/bin/dockerd -H fd:// ...。理论上你可以直接改这个文件加启动参数,但千万别这么干——包管理器升级 Docker 时会覆盖它,你的改动无声无息地消失,某次重启之后服务行为突变,排查成本高得离谱。
正确做法是用 systemd 的 drop-in 机制,在/etc/systemd/system/docker.service.d/目录下建一个.conf文件。这个目录的优先级高于包自带的单元文件,升级不会覆盖。
# /etc/systemd/system/docker.service.d/override.conf [Service] # 必须先清空再重写,否则会变成追加,出现两个 ExecStart ExecStart= ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock LimitNOFILE=1048576 LimitNPROC=infinityExecStart=后面空一行这个写法是 systemd 的语法规定:给一个空值表示清空原有列表,然后再追加。漏了这行,最终生效的是两条ExecStart拼接,服务直接起不来。我第一次写 drop-in 就犯过,systemctl status docker报docker.service has more than one ExecStart,看着莫名其妙,实际就是少了那行空赋值。
LimitNOFILE这个也别忽略。容器里跑高并发服务时,文件描述符上限受守护进程继承的限制。即便你在daemon.json里配了default-ulimits,宿主机层面的上限太低照样卡住。默认 1024 在老系统上很常见,调到 1048576 是常规操作。
改完单元文件必须systemctl daemon-reload,否则 systemd 用的还是缓存里的旧定义。这个动作和restart是两回事,很多人只 restart 不 reload,改了等于没改。
3.2 EnvironmentFile 与控制权优先级 另一种常见写法是把变量塞进/etc/default/docker(部分发行版是/etc/sysconfig/docker),再在单元文件里通过EnvironmentFile=引入。这种模式在早期版本里很流行,现在用得少了,但老机器上还会遇到。
[Service] EnvironmentFile=-/etc/default/docker ExecStart=/usr/bin/dockerd $DOCKER_OPTS路径前面的-表示文件不存在也不报错,属于防御性写法。这种方式的坑在于:$DOCKER_OPTS是靠 shell 展开的,参数里带空格、引号时容易解析异常;而且和daemon.json同时配置同一个选项时,行为不确定。
关于优先级,有一条实践结论值得记住:同一个选项如果在daemon.json和命令行参数里同时出现,较新版本的dockerd会直接启动失败 ,报错信息大意是"该指令同时以命令行参数和配置文件形式指定"。这其实是好事,比默默取其中一个更安全。真遇到了,就去 drop-in 里把冲突的参数删掉,统一收敛到daemon.json。
我的团队定了一条规矩:除-H和--containerd这类必须由单元文件决定的参数外,所有可配项一律写进daemon.json 。理由是单一真相源,出问题只看一个文件,新人接手也不用翻两处。
4. 客户端与构建侧配置:别把三层混成一锅 4.1 ~/.docker/config.json 管的是客户端身份 daemon.json管服务端,~/.docker/config.json管客户端,两者互不相干。这个文件在你第一次执行docker login时自动生成,主要存认证信息和客户端行为。
{ "auths": { "registry.internal:5000": {} }, "credsStore": "secretservice", "psFormat": "table {{.Names}}\t{{.Status}}\t{{.Ports}}" }注意auths里的值是空对象{},实际凭据被交给credsStore指定的凭据助手保管。这是比把 base64 编码的账号密码明文放文件里安全得多的做法——base64 不是加密,任何能读文件的人都能解开。团队协作时我的建议是统一启用credsStore,别图省事往文件里写明文。
还有一个容易被忽略的坑:~/.docker/config.json是按用户 隔离的。你sudo docker login之后普通用户docker pull私有镜像照样 401,因为读的是另一个人的 home 目录。CI 环境里更明显,跑构建的用户和登录的用户往往不是同一个。解决办法要么统一用同一个用户,要么显式指定DOCKER_CONFIG环境变量指向共享目录。
psFormat这类格式化配置属于锦上添花,但真能提升效率。默认的docker ps输出太挤,把Names、Status、Ports排一排,一眼就能看出哪个容器在反复重启。
4.2 .dockerignore 与 Dockerfile 的边界 很多人不把.dockerignore当"配置文件",其实它的重要性一点不亚于前几个。docker build的第一步是把整个构建上下文打包发给守护进程,上下文里有什么就传什么。我在一个前端项目里见过上下文 1.2G 的构建,node_modules、.git、构建产物全被塞进去,每条RUN前的传输都要等半分钟。
.dockerignore的语法和.gitignore类似,但不完全一样,特别是例外规则。
# 忽略一切非必要内容 .git node_modules dist *.log .env* # 但保留构建脚本需要的模板 !config/template.json!开头的例外规则要在忽略规则之后写才生效,顺序有讲究。另外**在这里是可用的,**/*.md能匹配任意层级的 Markdown 文件。
<提示>改了.dockerignore之后,如果构建产物看起来没变化,先看是不是COPY . .把不该带的东西带进去了。用docker build --no-cache排除缓存干扰,再用docker history看每层大小,一眼就能定位是哪一层把上下文整个吃进去了。
Dockerfile本身算不算配置文件?我的理解是它更像"构建脚本",但它定义了镜像的最终形态,是构建层配置的源头。几个和配置相关的经验:基础镜像尽量固定到具体的小版本号,别用latest,否则今天能构建成功的镜像明天可能因为基础镜像更新而失败;ENV设的值会在容器运行时一直生效,用于配时区、字符集这类全局变量很合适;ARG只在构建期有效,别指望它在运行期读到。
5. Compose 文件的组织方式与叠加技巧 5.1 版本字段已经不需要了 如果现在还有人让你在docker-compose.yml顶部写version: "3.8",可以直接告诉他:Compose V2 已经废弃这个字段,写了只会得到一条the attribute version is obsolete的警告。老版本 V1 靠它判断语法特性,V2 改成了按文件内容自动推断。这个变化很多人没跟上,简历上还写着"熟悉 Compose 3.x 语法",其实已经过时两三年了。
一个精简但完整的 Compose 文件长这样:
services: api: image: registry.internal:5000/app/api:1.4.2 restart: unless-stopped environment: APP_ENV: ${APP_ENV:-prod} DB_HOST: db ports: - "8080:8080" volumes: - app-data:/var/lib/app depends_on: db: condition: service_healthy healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/healthz"] interval: 15s timeout: 3s retries: 3 start_period: 30s db: image: registry.internal:5000/base/db:12.4 environment: DB_PASSWORD: ${DB_PASSWORD:?DB_PASSWORD is required} volumes: - db-data:/var/lib/db healthcheck: test: ["CMD-SHELL", "pg_isready -U app"] interval: 10s retries: 5 volumes: app-data: db-data:几个值得说的细节。${VAR:-default}是给默认值,${VAR:?message}是必填校验,变量缺失时直接报错退出,比悄悄用空字符串启动、跑到一半连接失败强太多。start_period是给慢启动服务的宽限时间,避免启动阶段就被判定为 unhealthy 然后被depends_on拦住。restart: unless-stopped比always更符合直觉——手动停掉的容器不会在守护进程重启后自己爬起来。
5.2 变量、叠加与配置分层 真实项目很少只有一个 Compose 文件。开发环境的端口映射、调试开关和生产不一样,但 90% 的内容是共用的。硬复制两份,改一处忘一处,早晚出事。正确姿势是"基础文件 + 差异化叠加"。
# base.yml 放通用定义,override 只写差异 docker compose -f base.yml -f prod.yml up -d叠加规则要记清楚:标量值(如image)后者覆盖前者;列表(如ports)默认是追加而不是替换;映射(如environment)按 key 合并。这个"列表追加"的行为坑过很多人——以为覆盖端口映射,结果两套都生效,端口冲突起不来。
变量来源的优先级也值得记住,从高到低大致是:docker compose命令行-e传入 > 当前 shell 环境变量 >.env文件 > 文件内默认值。.env放在执行目录(不是 Compose 文件所在目录),这一点经常搞混。团队里我一般要求把.env加进.gitignore,同时提交一份.env.example说明每个变量什么含义、什么范围合法。
<注意>敏感信息别直接写进 Compose 文件然后提交。environment里的明文密码会出现在镜像层的docker inspect输出里,任何能执行docker inspect的人都能看到。保险起见用文件挂载或者专门的密钥管理方式,把凭据从 Compose 文件里彻底摘出去。
6. 配置文件引发的典型故障与排查实录 6.1 启动失败的定位顺序 服务起不来,先别急着重装。固定按这个顺序看,八成问题一轮就能定位。
第一步,systemctl status docker --no-pager -l,看退出码和最后几行日志。JSON 语法错误的报错会直接指出行号,非常明确。
第二步,journalctl -u docker -n 100 --no-pager,翻最近一百行。这里能看到dockerd的完整启动过程,包括读到了哪个配置文件、哪个字段解析失败。
第三步,如果日志里出现"同时以 flag 和配置文件指定"这类字样,去查 drop-in 目录和/etc/default/docker,把冲突的参数删掉。
第四步,如果报的是存储驱动或者路径相关错误,检查>{ "data-root": "/data/docker", "storage-driver": "overlay2", "log-driver": "json-file", "log-opts": { "max-size": "100m", "max-file": "3" }, "exec-opts": ["native.cgroupdriver=systemd"], "default-address-pools": [ { "base": "10.201.0.0/16", "size": 24 } ], "default-ulimits": { "nofile": { "Name": "nofile", "Hard": 65536, "Soft": 65536 } }, "live-restore": true, "max-concurrent-downloads": 6, "max-concurrent-uploads": 6 }
这中间每个字段都是被具体问题逼出来的:>
版权声明:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设
2026/10/26 14:27:56
深度学习框架这几年更新迭代很快,但PyTorch始终是绕不开的那一个。我最早接触它是在几个图像分类的小项目上,后来做序列建模、部署落地也一直在用。这篇内容我想从一线使用者的角度,把PyTorch这个框架的定位、设计思路、核心机制和实操细节讲…
李华
网站建设
2026/10/26 14:27:20
简介:《动手学深度学习2.0-李沐Pytorch版》是一本面向深度学习初学者与进阶研发人员的实战型教材,聚焦PyTorch框架下的监督学习、线性回归及自然语言处理等核心任务,系统解决理论理解与代码实现脱节的问题。资源为单文件PDF格式,共…
李华
网站建设
2026/10/26 14:27:17
简介:这份PDF资料源自北京大学多个部门联合推出的DeepSeek内部研讨系列,面向对自然语言处理与人工智能感兴趣的学生、学者及关注AI应用趋势的企业管理与技术人员,无需专业AI或IT背景即可阅读。内容围绕DeepSeek-R1推理模型展开,梳…
李华
网站建设
2026/10/26 14:27:10
1. 语料困境下的AI发展现状 当我在2023年清理服务器上的训练数据时,突然意识到一个严峻的事实:我们可能已经收集了互联网上90%以上的可用高质量文本数据。这个发现让我开始重新思考大模型发展的根本性问题——在语料资源接近枯竭的今天,人工智…
李华
网站建设
2026/10/26 14:26:34
简介:硬件测试方案-整机和单板.doc 提供了一套适用于硬件研发与生产阶段的整机、单板测试规范,面向硬件工程师、测试人员以及项目管理相关从业者,用于统一测试流程、明确质量判定依据,也可作为新员工或测试团队的入门培训材料。压…
李华
网站建设
2026/10/26 14:25:55
1. 项目概述:为什么这27个库不是“清单”,而是数据科学工作的“工具箱地图”你打开Jupyter Notebook,想快速画个分布图,却卡在plt.hist()参数调不出来的瞬间;你刚爬完一批电商评论,面对上万条文本ÿ…
李华
编程爱好者
专注于前端开发和人工智能领域,热爱分享技术心得和编程技巧。
关于博客
这是一个专注于编程技术分享的极简博客,旨在为开发者提供高质量的技术文章和教程。