跳转到内容

1. x86服务器上拉取arm64镜像

bash
# 获取镜像完整 digest
# curl -x http://192.168.60.1:12450 -s "https://hub.docker.com/v2/repositories/ollama/ollama/tags/0.30.6" | jq -r '.images[] | select(.architecture=="arm64") | .digest'
sha256:4465a16593023cb6082d7d2a41feec4c908df60908ba2bf5b9a7dd372488c602

# 拉取镜像
docker pull --platform linux/arm64 ollama/ollama@sha256:4465a16593023cb6082d7d2a41feec4c908df60908ba2bf5b9a7dd372488c602

2. docker manifest push 未覆盖已有 tag

环境: Windows PowerShell / Docker CLI

现象:docker manifest create + docker manifest push 更新一个已存在的 manifest list tag,push 显示成功,但 registry 上的内容没有变化。

根因: docker manifest 命令在本地 ~/.docker/manifests/ 维护了一份 manifest 缓存。create 时如果缓存中已有同名条目,会使用旧的组合结果,导致 push 上去的还是旧 digest。--amend 参数虽然能在 create 时覆盖本地缓存中的条目,但如果缓存残留的是上一次 create 的完整 list,仍需先清除再重建。

解决: 先删除本地缓存,再用 --amend 重建并推送。

powershell
# 1. 删除本地 manifest 缓存(只删本地,不影响 registry)
docker manifest rm <registry>/<repo>:<tag>

# 2. 用 --amend 重建 manifest list
docker manifest create --amend <registry>/<repo>:<tag> `
  <registry>/<repo>:<arch1-tag> `
  <registry>/<repo>:<arch2-tag>

# 3. 推送
docker manifest push <registry>/<repo>:<tag>

替代方案(绕过本地缓存,最可靠): 使用 docker buildx imagetools 直接在 registry 侧操作,完全不经过本地 manifest store。

powershell
# 覆盖整个 manifest list
docker buildx imagetools create --tag <registry>/<repo>:<tag> `
  <registry>/<repo>:<arch1-tag> `
  <registry>/<repo>:<arch2-tag>

验证:

powershell
# 检查 push 后的 digest 是否变化、platforms 是否包含新条目
docker buildx imagetools inspect <registry>/<repo>:<tag>

边界: 如果 push 时报 manifest already exists 或 HTTP 409,不是缓存问题,而是 registry 侧开了 immutable tag 保护(如 Harbor Immutable Tag Rule、Docker Hub Immutable Tags),需要在 registry 管理界面关闭该规则后重试。

3. 按 compose 项目统计容器内存占用

多项目共用一台演示服务器、需要评估内存占用时,按 com.docker.compose.project 标签聚合每个项目的内存使用量(GB,降序)。

bash
docker stats --no-stream --format "table {{.Container}}\t{{.Name}}\t{{.MemUsage}}" | \
awk 'NR>1 {print $1, $3}' | while read cid mem_used; do
project=$(docker inspect -f '{{ index .Config.Labels "com.docker.compose.project" }}' "$cid" 2>/dev/null || echo "unknown")
echo "$project $mem_used"
done | awk '{
if (match($2, /([0-9.]+)([KMG]iB)/, arr)) {
num = arr[1]
unit = arr[2]

if (unit == "KiB") bytes = num * 1024
else if (unit == "MiB") bytes = num * 1048576
else if (unit == "GiB") bytes = num * 1073741824
else bytes = 0
} else {
bytes = 0
}

mem_bytes[$1] += bytes
}
END {
# 收集所有项目和数据
for (project in mem_bytes) {
    mem_gb = mem_bytes[project] / 1073741824
    printf "%-25s %.2f\n", project, mem_gb
}
}' | sort -k2 -nr

说明: docker inspect 取不到 compose 项目标签时归入 unknown;输出为 项目名 占用GB,按占用降序排列,适合迁移评估。

4. docker.service 反复重启后彻底失败:iptables not found

环境: WSL2 里的 Ubuntu(最小化 rootfs);同样的根因适用于任何精简安装的 Linux 系统

现象: docker 起不来,systemd 一路重试后放弃:

text
systemd[1]: docker.service: Scheduled restart job, restart counter is at 3.
systemd[1]: docker.service: Start request repeated too quickly.
systemd[1]: docker.service: Failed with result 'exit-code'.
systemd[1]: Failed to start docker.service - Docker Application Container Engine.

坑:报错被 systemd 提示刷掉了。 journalctl -xeu docker.service 输出满屏 ░░ Subject: 解释文本,把 daemon 自己那行报错挤到中间。真正的根因是:

text
failed to start daemon: Error initializing network controller: error obtaining controller instance:
failed to register "bridge" driver: failed to create NAT chain DOCKER: iptables not found

根因: dockerd 启动时 bridge 网络驱动必须调 iptables 建 DOCKER NAT 链。系统里没有 iptables 命令 → dockerd 直接 exit 1Restart=on-failure 连撞 3 次 → StartLimitBurst=3 / StartLimitIntervalSec=60 触发 Start request repeated too quickly,systemd 放弃重试。

注意:内核侧通常是好的。 实测 CONFIG_NF_NAT=yip_tables 模块已加载(lsmod | grep ip_tables 有输出),问题纯粹出在用户态缺组件——所以不要去折腾内核模块或 modprobe,装了 iptables 就行。

定位(两条命令):

bash
# 1) 拿真正的报错,别被 systemd 的解释文本带偏
journalctl -u docker -n 50 --no-pager | grep -iE "iptables|nft|NAT chain"

# 2) 确认 iptables 到底在不在(三个证据一起看)
command -v iptables nft
ls -l /usr/sbin/iptables* 2>/dev/null
dpkg -l | grep -E "iptables|nftables"

修复:

bash
sudo apt-get update && sudo apt-get install -y iptables
sudo systemctl restart docker
systemctl is-active docker          # 必须输出 active 才算修好
  • 只装 nftables 不够:dockerd 默认仍通过 iptables-nft 兼容层调用,iptables 这个命令必须存在。
  • 装完再跑一次 journalctl -u docker -n 30 --no-pager,确认不再出现 failed to create NAT chain

WSL 上还会顺带踩到的两个坑:

现象处理
代理地址写宿主局域网 IP从 WSL 里访问宿主机代理超时(30s)WSL2 mirrored 网络模式下共享宿主机环回,代理监听在 127.0.0.1 就用 127.0.0.1:<port>,不要用宿主机的局域网 IP
apt 源走代理返 502apt-get update502 Bad Gatewayhttp://archive.ubuntu.comhttps:// 即通(security.ubuntu.com 同理)

安装脚本的教训: 如果脚本在 systemctl enable --now docker 之后不校验状态,就会出现"脚本打印『docker 安装完成』但服务其实是 failed"。补一行显式校验,把静默失败变成显式失败:

bash
systemctl enable --now docker
systemctl is-active --quiet docker || { journalctl -u docker -n 30 --no-pager; exit 1; }

验证状态(2026-09-11): 根因已实测确认(command -v iptables nft 全空、/usr/sbin/iptables* 不存在、dpkg -l 只有 iproute2)。apt-get install iptables 之后 docker 恢复属推断,未在该环境跑完端到端验证(操作中断);镜像上的 WSL 最小化 rootfs 默认不带 iptables,这一点是实测事实。

基于 MIT 许可发布