Skip to content

Docker 安装、权限与升级:从软件包到可验证运行环境

Docker 安装不是执行一条 apt install docker 就结束。生产环境要回答:安装的是发行版自带包还是 Docker 官方仓库包,CLI、daemon、containerd、runc、Buildx、Compose 分别来自哪里,软件源签名如何验证,Docker 数据写到哪个文件系统,普通用户为什么会 permission denied,加入 docker 组为什么近似授予 root 权限,rootless 能降低什么风险,升级 daemon 会不会影响正在运行的容器,以及安装后如何证明镜像拉取、网络、Volume、日志和 cgroup 都正常。

安装命令会随操作系统版本和 Docker 官方仓库调整。执行生产安装前,应结合当前系统版本核对 Docker 官方安装文档。本页重点提供可解释、可验证、可回滚的完整方法,而不是把未知脚本直接交给 root 执行。

学习目标

学完后,应能:

  1. 解释 Docker CLI、dockerd、containerd、shim、runc、Buildx 和 Compose 的职责。
  2. 比较发行版仓库、Docker 官方仓库、便利脚本、静态二进制和 Docker Desktop 的边界。
  3. 在 Ubuntu/Debian 上按签名仓库方式安装,并解释每一步为什么存在。
  4. 使用 systemd 管理 docker.service 和 docker.socket,读懂 daemon 日志。
  5. 解释 Docker socket 权限、docker 组风险、sudo 混用和 rootless 模式。
  6. 规划 Docker Root Dir、文件系统、cgroup、网络地址池、日志轮转和代理。
  7. 验证镜像、容器、端口、DNS、Volume、资源限制、Compose 和优雅停止。
  8. 安全升级和卸载软件包,不误删镜像、Volume 与业务数据。
  9. 定位 daemon 连不上、GPG、TLS、DNS、overlay2、iptables、权限和磁盘问题。

一、安装后到底会多出哪些组件

mermaid
flowchart TD
    A["用户执行docker命令"] --> B["Docker CLI"]
    B --> C["Docker Engine API"]
    C --> D["dockerd守护进程"]
    D --> E["containerd"]
    E --> F["containerd-shim"]
    F --> G["runc等OCI Runtime"]
    G --> H["Linux内核namespace、cgroup、网络和Mount"]
    B --> I["Buildx插件"]
    B --> J["Compose插件"]
组件常见职责没有或异常时的表现
Docker CLI解析 docker 命令并调用 Engine APIshell提示命令不存在,或只有Client无法连接Server
dockerd管理镜像、容器、网络、Volume和APICannot connect to the Docker daemon
containerd管理镜像内容与容器任务生命周期daemon创建/启动容器失败
containerd-shim保持容器任务与运行时状态、转发IOdaemon重启和容器任务管理异常
runc根据OCI配置创建容器进程namespace/cgroup/rootfs创建阶段失败
BuildxBuildKit驱动的高级构建入口docker buildx不可用
Compose plugin解析Compose项目并调用Enginedocker compose不可用

容器不是 dockerd 的子虚拟机。最终应用仍是 Linux 进程,使用宿主机内核。完整链路见 Docker容器运行底层原理

二、先选择安装方式

方式优点风险与适用边界
Docker官方软件仓库组件版本配套、更新路径清晰需要管理仓库信任、版本和变更窗口
Linux发行版自带包与发行版生命周期集成包名、版本、默认配置可能与Docker官方包不同
官方便利脚本实验机快速安装不适合不审查就以root运行在生产;版本与行为需先阅读
静态二进制特殊离线环境灵活systemd、升级、依赖、日志和安全补丁都需自行治理
Docker DesktopWindows/macOS开发体验完整Engine运行在Linux VM/WSL2;路径、资源和网络不等于原生Linux
rootless安装daemon和容器不以宿主机root运行网络、低端口、cgroup、存储驱动和运维方式有兼容性边界

本页 Linux 主线采用 Docker 官方 APT 仓库。企业如果统一使用发行版仓库,应遵守内部基线,但要记录实际包来源和版本,不能混装两套冲突包。

三、安装前检查:先证明主机适合运行Docker

3.1 识别操作系统和CPU架构

bash
cat /etc/os-release
uname -r
uname -m
dpkg --print-architecture 2>/dev/null || true

需要记录:

  • Ubuntu、Debian或其他发行版。
  • 发行版版本和代号。
  • Kernel版本。
  • amd64、arm64等架构。

镜像架构必须与主机或仿真能力匹配,否则可能出现 no matching manifestexec format error

3.2 确认cgroup模式

bash
stat -fc %T /sys/fs/cgroup
mount | grep cgroup

常见:

  • cgroup v1。
  • cgroup v2。

它影响资源控制文件、监控和部分旧软件兼容性。现代系统普遍使用 v2,但不能只凭发行版名称猜测。

3.3 确认存储空间、inode和文件系统

bash
df -h
df -i
lsblk -f
findmnt /

至少规划:

  • Docker Root Dir 可用空间。
  • 镜像和构建缓存增长。
  • 容器日志。
  • 数据库 Volume。
  • Heap/Core Dump。
  • inode 数量。

根分区只有少量空间却把 /var/lib/docker 放在根分区,后续很容易因镜像、日志和 OverlayFS 写满宿主机。

3.4 确认时间、DNS、代理和外网

bash
timedatectl status
getent hosts download.docker.com
getent hosts registry-1.docker.io

TLS 依赖正确系统时间。企业网络还要确认:

  • HTTP/HTTPS代理。
  • TLS中间代理CA。
  • Docker官方仓库是否可达。
  • 镜像Registry是否可达。
  • 内部DNS。

APT能联网不代表 dockerd 拉镜像一定能联网,因为 daemon 是 systemd 服务,未必继承当前Shell代理变量。

3.5 检查旧包和现有数据

bash
dpkg -l | grep -E 'docker|containerd|runc' || true
systemctl status docker --no-pager 2>/dev/null || true

如果主机已经运行容器,先保存:

bash
docker version
docker info
docker ps -a --no-trunc
docker image ls --digests
docker volume ls
docker network ls

卸载软件包通常不会自动删除 /var/lib/docker,但混装和版本切换可能导致 daemon 无法读取现有状态。任何已有业务主机都应先做变更评估、备份和回滚计划。

四、Ubuntu使用Docker官方APT仓库安装

以下命令面向当前常见 Ubuntu APT 方式。执行前先核对操作系统确实是 Ubuntu,而不是把 Ubuntu 仓库地址照搬到 Debian。

4.1 移除可能冲突的软件包

先只查看:

bash
dpkg -l | grep -E 'docker.io|docker-compose|docker-compose-v2|docker-doc|podman-docker|containerd|runc' || true

确认不是已有生产运行环境后,移除与官方包冲突的发行版包:

bash
sudo apt-get remove -y \
  docker.io \
  docker-compose \
  docker-compose-v2 \
  docker-doc \
  podman-docker \
  containerd \
  runc

包不存在时 APT 可能提示无法定位或未安装。关键不是机械忽略所有错误,而是再次检查包状态,确认没有两套 containerd/runc 来源冲突。

不要在这一步删除 /var/lib/docker/var/lib/containerd。它们可能保存现有镜像、容器元数据和业务卷。

4.2 安装仓库访问依赖

bash
sudo apt-get update
sudo apt-get install -y ca-certificates curl
  • ca-certificates:验证 HTTPS 服务端证书。
  • curl:下载 Docker 仓库签名公钥。

如果企业使用私有CA,应由安全/运维流程把CA加入系统信任,不应使用 curl -k 跳过TLS校验。

4.3 创建APT Keyring目录

bash
sudo install -m 0755 -d /etc/apt/keyrings

install -m 同时创建目录并设置权限。单独 keyring 配合 signed-by,可以把该密钥的信任范围限制到指定仓库,而不是把第三方Key全局信任给所有APT源。

4.4 下载Docker仓库签名公钥

bash
sudo curl -fsSL \
  https://download.docker.com/linux/ubuntu/gpg \
  -o /etc/apt/keyrings/docker.asc

sudo chmod a+r /etc/apt/keyrings/docker.asc

参数含义:

  • -f:HTTP错误时失败。
  • -sS:减少进度输出但保留错误。
  • -L:跟随重定向。
  • -o:写入明确文件。

生产可以按组织基线核对密钥指纹和来源。HTTPS只能证明连接到证书信任的站点,签名校验用于验证仓库元数据由持有对应私钥的一方发布。

4.5 添加Ubuntu软件源

bash
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo \"${UBUNTU_CODENAME:-$VERSION_CODENAME}\") stable" |
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

拆解:

  • arch=...:只获取当前CPU架构包。
  • signed-by=...:指定该仓库使用的公钥。
  • /linux/ubuntu:Ubuntu仓库,Debian不能直接照搬。
  • codename:例如某个Ubuntu发行版代号。
  • stable:稳定通道。

检查生成结果:

bash
cat /etc/apt/sources.list.d/docker.list
sudo apt-get update
apt-cache policy docker-ce

apt-get update 出现 GPG、Release file、404,应修复仓库和代号,不能通过关闭签名校验绕过。

4.6 安装组件

bash
sudo apt-get install -y \
  docker-ce \
  docker-ce-cli \
  containerd.io \
  docker-buildx-plugin \
  docker-compose-plugin

包职责:

主要内容
docker-ceDocker Engine daemon及systemd集成
docker-ce-clidocker命令行客户端
containerd.ioDocker配套containerd及相关运行组件
docker-buildx-plugindocker buildx插件
docker-compose-plugindocker compose V2插件

安装完成不代表业务环境已经验证,还要执行后续 systemd、网络、Volume 和资源测试。

五、Debian安装时与Ubuntu有什么不同

Debian 的 key URL 和仓库路径应使用 Debian:

bash
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL \
  https://download.docker.com/linux/debian/gpg \
  -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

仓库:

bash
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian $(. /etc/os-release && echo \"$VERSION_CODENAME\") stable" |
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

再执行 update 和安装同类组件。Ubuntu和Debian的发行版代号、仓库路径不能混用。衍生发行版还可能需要映射到上游代号,应以其支持说明为准。

六、RHEL系主机怎么处理

RHEL、Rocky Linux、AlmaLinux、CentOS Stream 等通常使用 RPM/DNF 体系,不能复制 APT 命令。核心流程仍相同:

text
识别发行版与版本

清理冲突包

添加受信任RPM仓库

检查可用版本

安装Engine、CLI、containerd、Buildx、Compose

systemd启动与验证

示意命令:

bash
sudo dnf install -y dnf-plugins-core
sudo dnf config-manager --add-repo \
  https://download.docker.com/linux/centos/docker-ce.repo
sudo dnf install -y \
  docker-ce \
  docker-ce-cli \
  containerd.io \
  docker-buildx-plugin \
  docker-compose-plugin

不同RHEL系发行版、版本、订阅和SELinux策略可能不同,生产必须核对 Docker 官方支持矩阵与组织镜像仓库,不能把示意命令当成所有RPM系统完全一致的脚本。

七、为什么不建议生产直接执行便利脚本

常见快速脚本形式:

text
curl 某URL | sh

问题不在于脚本一定恶意,而在于:

  • 远程内容未经本地审查就交给 Shell。
  • 常以 root 运行。
  • 今天和明天下载内容可能不同。
  • 版本选择、仓库变化和副作用不清楚。
  • 不利于审计和重复部署。

实验机若使用便利脚本,也应先下载、固定内容、阅读脚本并记录版本。生产更适合配置管理工具或经过评审的安装脚本,明确软件源、包版本、daemon配置和验证结果。

八、systemd如何管理Docker

8.1 启用并立即启动

bash
sudo systemctl enable --now docker

相当于:

  • 设置在适当启动目标中启用。
  • 当前立即启动 docker.service。

验证:

bash
systemctl is-enabled docker
systemctl is-active docker
sudo systemctl status docker --no-pager

8.2 docker.service与docker.socket

查看:

bash
systemctl status docker.service --no-pager
systemctl status docker.socket --no-pager
systemctl cat docker.service
systemctl cat docker.socket

某些安装启用 socket activation:客户端访问 Docker Unix Socket 时,systemd可以触发 daemon 启动。实际行为取决于 unit 配置,不应只看进程是否曾手工 start。

8.3 查看daemon日志

bash
sudo journalctl -u docker --since "30 minutes ago" --no-pager
sudo journalctl -u containerd --since "30 minutes ago" --no-pager

实时查看:

bash
sudo journalctl -u docker -f

-f 持续占用终端。生产应控制时间范围并将关键日志外部采集。

8.4 restart与daemon-reload区别

bash
sudo systemctl daemon-reload

让 systemd 重新读取 unit 和 drop-in,不等于重启 Docker。

bash
sudo systemctl restart docker

会重启 daemon,可能影响所有容器和管理操作。修改 daemon 配置后常需 restart,但生产执行前必须评估运行容器、live-restore、重启策略和业务流量。

九、Docker Unix Socket与权限原理

Rootful Docker 默认常通过:

text
/var/run/docker.sock

通信。检查:

bash
ls -l /var/run/docker.sock
getent group docker
id

常见权限类似:

text
srw-rw---- root docker ... /var/run/docker.sock

含义:root和docker组成员可以调用 Engine API。

9.1 为什么加入docker组近似授予root权限

拥有 Docker API 权限的用户通常可以:

  • 启动高权限容器。
  • 挂载宿主机根目录。
  • 访问宿主机文件。
  • 挂载Docker socket。
  • 创建带设备和Capability的容器。

因此 docker 组不是普通“应用用户组”,应按高权限管理员组控制、审计和定期复核。

9.2 将可信用户加入docker组

只对经过授权的运维或开发用户:

bash
sudo usermod -aG docker "$USER"

组成员关系通常在新登录会话生效。可退出重新登录,或在当前终端测试新组会话:

bash
newgrp docker
id
docker version

如果之前大量使用 sudo docker,用户家目录中的 Docker CLI 配置可能由 root 创建,导致普通用户访问 ~/.docker 出错。应检查所有者并修正明确文件,不要递归放宽整个家目录权限。

9.3 不要把socket挂给普通业务容器

危险配置:

yaml
volumes:
  - /var/run/docker.sock:/var/run/docker.sock

该容器获得的通常不是普通文件访问,而是控制宿主机Docker API的能力。仅基础设施组件在严格评估、只读代理、权限隔离和审计下才可能需要,普通Java服务不应挂载。

十、Rootless Docker解决什么

Rootless 模式让 daemon 和容器以普通宿主机用户身份运行,降低 daemon 或容器漏洞直接获得宿主机 root 的风险。

mermaid
flowchart TD
    A["普通用户启动rootless dockerd"] --> B["User Namespace映射"]
    B --> C["用户目录下Docker数据"]
    B --> D["用户级systemd服务"]
    B --> E["rootless网络与端口机制"]

10.1 前置条件

常见需要:

  • uidmap 工具。
  • /etc/subuid/etc/subgid 为用户分配从属ID范围。
  • 支持 user namespace 的内核。
  • 用户级 systemd 或其他进程管理。
  • Rootless配套组件。

Ubuntu/Debian示意:

bash
sudo apt-get install -y uidmap
grep "^$USER:" /etc/subuid
grep "^$USER:" /etc/subgid

Docker官方包可提供 rootless extras,具体包和安装工具应按当前版本确认:

bash
dockerd-rootless-setuptool.sh check
dockerd-rootless-setuptool.sh install

安装工具通常会提示设置 DOCKER_HOST 和用户级服务。按实际输出配置,不要把 rootful /var/run/docker.sock 与 rootless 用户 socket 混用。

10.2 用户级systemd

bash
systemctl --user status docker --no-pager
systemctl --user enable --now docker

若希望用户退出后服务继续运行,可能需要管理员评估并启用 linger:

bash
loginctl show-user "$USER" -p Linger

是否启用由组织安全和运维策略决定,不应对所有用户无条件开启。

10.3 Rootless不是没有边界

需要验证:

  • 低于1024端口的绑定策略。
  • cgroup资源限制是否完整可用。
  • OverlayFS/fuse-overlayfs。
  • 网络性能和真实源IP。
  • 存储路径和配额。
  • ICMP、设备、特权能力。
  • 监控和备份工具兼容性。

Rootless降低风险,不会自动解决镜像漏洞、错误Mount、应用权限、Secret泄露和网络暴露。

十一、Docker数据目录和存储驱动

查看:

bash
docker info --format 'root={{.DockerRootDir}} driver={{.Driver}}'

Rootful常见数据目录是 /var/lib/docker,但可以通过配置改变。它可能包含:

  • 镜像层。
  • 容器可写层。
  • 本地Volume。
  • 容器日志。
  • 网络和元数据。
  • 构建缓存的相关数据。

11.1 为什么不能运行中直接移动目录

直接 mv /var/lib/docker 可能造成:

  • daemon仍在写入。
  • 文件所有权或安全标签变化。
  • OverlayFS层关系损坏。
  • 容器和Volume不可用。
  • 回滚困难。

迁移 data-root 应制定停机、备份、复制校验、daemon配置和回滚流程,数据库业务数据还要使用数据库一致性备份,不能把复制 Docker Root Dir 当作通用热备。

11.2 overlay2和底层文件系统

常见 Linux 存储驱动是 overlay2。需要底层文件系统和内核支持。XFS 场景历史上需关注 ftype=1/目录项类型支持:

bash
xfs_info <挂载> 2>/dev/null | grep ftype || true

实际支持以当前 Docker Engine 和发行版文档为准。不要通过强行切换 storage driver 启动旧数据目录,不同驱动的数据布局并不通用。

十二、daemon.json配置与验证

默认常见路径:

text
/etc/docker/daemon.json

生产示意:

json
{
  "data-root": "/data/docker",
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "20m",
    "max-file": "5"
  },
  "live-restore": true,
  "default-address-pools": [
    {
      "base": "172.30.0.0/16",
      "size": 24
    }
  ]
}

每项含义:

配置目的风险与验证
data-root将Docker数据放到规划磁盘迁移旧数据需停机和校验
log-driver设置默认日志驱动新建容器才会按新默认配置
log-opts默认日志轮转必须inspect最终容器LogConfig
live-restoredaemon不可用时尽量保持容器运行不代表所有升级/网络管理都无影响
default-address-pools控制自动网络地址池必须避免与机房、VPN、K8s网段冲突

12.1 修改前备份和语法验证

先查看当前配置和 unit 参数:

bash
sudo test -f /etc/docker/daemon.json && sudo cat /etc/docker/daemon.json
systemctl cat docker

编辑后先进行 JSON 语法校验。若当前 dockerd 支持:

bash
sudo dockerd --validate --config-file=/etc/docker/daemon.json

不同版本支持情况以 dockerd --help 为准。还要注意同一选项若同时出现在 systemd启动参数和 daemon.json,可能导致冲突并使 daemon 启动失败。

12.2 应用配置

bash
sudo systemctl restart docker
sudo systemctl status docker --no-pager
sudo journalctl -u docker --since "10 minutes ago" --no-pager
docker info

生产重启前先摘流、确认运行容器和回滚方案。配置失败时应恢复已验证配置,而不是反复删除数据目录。

十三、镜像加速、私有Registry与信任边界

镜像加速示意:

json
{
  "registry-mirrors": [
    "https://mirror.example.com"
  ]
}

需要确认:

  • 镜像源由谁运营。
  • 是否完整同步Digest和多架构Manifest。
  • 是否有访问日志和限流。
  • 是否可能返回过期或篡改内容。
  • 企业是否应使用内部Registry代理缓存。

不要使用来源不明的公共镜像加速地址处理商业镜像。

私有 Registry 的 TLS 证书应由受信任 CA 签发,或将企业 CA 正确安装到 Docker 信任目录。不要为了省事配置明文 insecure registry,除非是隔离环境且经过明确风险评估。

十四、Docker daemon代理为什么与Shell代理不同

当前Shell设置:

bash
export HTTPS_PROXY=http://proxy.example.com:3128

不一定影响 systemd 启动的 dockerd。常见做法是创建 systemd drop-in:

bash
sudo systemctl edit docker

示意内容:

ini
[Service]
Environment="HTTP_PROXY=http://proxy.example.com:3128"
Environment="HTTPS_PROXY=http://proxy.example.com:3128"
Environment="NO_PROXY=127.0.0.1,localhost,.example.internal,registry.example.com"

应用:

bash
sudo systemctl daemon-reload
sudo systemctl restart docker
sudo systemctl show docker --property=Environment

代理地址可能包含凭据,systemd配置、日志和命令输出都要按敏感信息保护。NO_PROXY 需要覆盖内部Registry和服务地址,格式和端口行为应按使用组件验证。

十五、Docker网络与宿主机防火墙

Docker会创建 bridge、veth、路由和 iptables/nftables 规则。安装后需要理解:

  • Docker发布端口可能添加NAT规则。
  • ufw/firewalld与Docker规则链交互可能与直觉不同。
  • 云安全组、宿主机防火墙和Docker发布端口是不同层。
  • 不能因为使用Docker就关闭宿主机防火墙。
  • 不要随意设置 "iptables": false,否则端口发布、隔离和转发可能失效,并需要自行完整管理规则。

检查:

bash
docker network ls
ip link show
ip route

iptables/nft命令需要管理员权限且不同系统后端不同。详细报文路径见 Docker网络底层原理

十六、安装后的分层验证

hello-world 只能验证一部分链路,不能证明生产能力完整。

16.1 验证CLI、daemon和运行时

bash
docker version
docker info
docker run --rm hello-world

hello-world 大致验证:

text
CLI连接daemon

daemon解析镜像

缺失时从Registry拉取

containerd/runc创建容器进程

stdout通过日志链路返回

它没有充分验证:

  • 端口发布。
  • 自定义网络DNS。
  • Volume持久化。
  • 日志轮转。
  • CPU/内存限制。
  • Compose。
  • daemon重启行为。

16.2 验证端口发布

bash
docker run -d \
  --name install-check-nginx \
  --label training=docker-install \
  -p 127.0.0.1:18080:80 \
  nginx:1.27

curl -fsS http://127.0.0.1:18080/
docker port install-check-nginx

16.3 验证自定义网络DNS

bash
docker network create --label training=docker-install install-check-net
docker network connect install-check-net install-check-nginx

docker run --rm \
  --network install-check-net \
  busybox:1.36 \
  wget -qO- http://install-check-nginx/

16.4 验证Volume持久化

bash
docker volume create --label training=docker-install install-check-data

docker run --rm \
  --mount type=volume,source=install-check-data,target=/data \
  busybox:1.36 \
  sh -c 'echo persisted > /data/check.txt'

docker run --rm \
  --mount type=volume,source=install-check-data,target=/data,readonly \
  busybox:1.36 \
  cat /data/check.txt

第一次临时容器已删除,第二个容器仍读到数据,证明命名卷具有独立生命周期。

16.5 验证资源限制

bash
docker run -d \
  --name install-check-resource \
  --label training=docker-install \
  --memory=128m \
  --cpus=0.5 \
  busybox:1.36 \
  sh -c 'while true; do sleep 60; done'

docker inspect \
  --format 'memory={{.HostConfig.Memory}} nanoCpus={{.HostConfig.NanoCpus}}' \
  install-check-resource

docker stats --no-stream install-check-resource

16.6 验证Buildx与Compose

bash
docker buildx version
docker buildx ls
docker compose version

16.7 安全清理验证对象

先按标签列出:

bash
docker ps -a --filter label=training=docker-install
docker network ls --filter label=training=docker-install
docker volume ls --filter label=training=docker-install

只清理明确实验对象:

bash
docker stop install-check-nginx install-check-resource
docker rm install-check-nginx install-check-resource
docker network rm install-check-net
docker volume rm install-check-data

不使用全局 prune,不影响其他业务对象。

十七、日志轮转验证

daemon默认日志设置通常只影响之后新创建的容器。创建容器后检查:

bash
docker inspect \
  --format '{{json .HostConfig.LogConfig}}' \
  install-check-nginx

如果容器已在应用默认设置前创建,单纯重启不会改变 HostConfig;需要受控重建。日志路径和磁盘告警还应结合:

bash
docker info --format '{{.DockerRootDir}}'
docker system df -v
df -h
df -i

十八、升级Docker Engine

升级不是直接运行 apt upgrade 后观察运气。

18.1 升级前收集

bash
docker version
docker info
docker ps -a --no-trunc
docker image ls --digests
docker volume ls
docker network ls
sudo systemctl status docker --no-pager

还需:

  • 阅读目标版本Release Notes和弃用项。
  • 检查API、Compose、Buildx、日志和存储驱动兼容性。
  • 确认容器是否有其他节点承接。
  • 确认数据库和Volume备份。
  • 在测试/预发验证。
  • 准备包版本回退和配置回退。

18.2 查看可用版本

Ubuntu/Debian:

bash
apt-cache madison docker-ce
apt-cache policy docker-ce docker-ce-cli containerd.io

生产应显式选择经过验证的版本组合。具体包版本字符串由仓库决定,不在文档中硬编码一个会过时的值。

18.3 升级窗口

mermaid
flowchart TD
    A["测试环境验证目标版本"] --> B["备份配置与业务数据"]
    B --> C["摘流或迁移容器"]
    C --> D["升级一个金丝雀节点"]
    D --> E["验证daemon、网络、Volume、日志和业务"]
    E --> F{"是否正常"}
    F -- "否" --> G["停止扩散并按预案回退"]
    F -- "是" --> H["分批升级其他节点"]

live-restore 可在部分 daemon 不可用场景保持容器进程,但不等于升级完全无影响:CLI管理、网络变更、日志链路和新容器创建仍可能受影响,具体版本升级是否支持无缝需要验证。

十九、卸载软件包与删除数据必须分开

查看包:

bash
dpkg -l | grep -E 'docker-ce|docker-ce-cli|containerd.io|docker-buildx|docker-compose' || true

停止业务和备份后,卸载包可使用发行版包管理器。重要原则:

  • 卸载包不等于安全删除 /var/lib/docker
  • 数据目录可能保存命名卷和事故证据。
  • containerd数据也可能独立存在。
  • daemon配置、systemd drop-in、CA和仓库文件需要按变更单识别。
  • 是否保留数据取决于迁移/重装目标。

本页不提供递归删除 Docker Root Dir 的命令。若确实永久退役主机,应先导出审计清单、完成业务数据销毁审批,再由基础设施流程精确处理。

二十、Docker Desktop:Windows和macOS不是原生Linux安装

20.1 Windows常见架构

mermaid
flowchart TD
    A["Windows上的docker.exe"] --> B["Docker Desktop"]
    B --> C["WSL2或Hyper-V Linux环境"]
    C --> D["Linux dockerd/containerd"]
    D --> E["Linux容器进程"]

检查 WSL:

powershell
wsl --status
wsl --list --verbose
docker context ls
docker version
docker info

需要区分:

  • Windows磁盘空间。
  • Docker Desktop虚拟磁盘空间。
  • Windows路径与Linux路径。
  • WSL发行版与Docker Desktop内部环境。
  • Windows代理与daemon代理。

项目源码放在跨Windows文件系统Bind Mount上,文件监听和大量小文件IO可能比Linux文件系统慢。数据库数据不应随意放在高延迟共享路径。

20.2 macOS

macOS 同样通过 Linux VM 运行 Linux 容器,不共享 macOS 内核。CPU、内存、磁盘和文件共享由 Docker Desktop 配置限制。--network host、路径权限和性能不能机械套用原生Linux结论。

20.3 商业许可与组织策略

企业使用 Docker Desktop 应核对当前许可条款、软件分发、自动升级、代理、证书和数据采集策略。具体条款可能变化,应由组织依据当前官方许可确认。

二十一、常见安装故障

21.1 APT仓库没有Release文件或404

检查:

bash
cat /etc/os-release
cat /etc/apt/sources.list.d/docker.list
sudo apt-get update

常见原因:

  • Ubuntu/Debian仓库路径混用。
  • 发行版代号错误。
  • 衍生发行版代号不被上游仓库支持。
  • 代理或DNS返回错误页面。

不要关闭仓库安全校验来“修复”。

21.2 GPG签名错误

检查:

bash
ls -l /etc/apt/keyrings/docker.asc
grep signed-by /etc/apt/sources.list.d/docker.list

方向:

  • key文件下载失败或是HTML错误页。
  • APT用户不可读。
  • signed-by 路径错误。
  • 企业代理替换下载内容。
  • 系统时间异常。

21.3 Cannot connect to the Docker daemon

bash
docker context show
systemctl is-active docker
sudo systemctl status docker --no-pager
sudo journalctl -u docker --since "30 minutes ago" --no-pager
ls -l /var/run/docker.sock

区分:daemon未运行、context错误、socket权限、配置失败、磁盘满。

21.4 普通用户permission denied

bash
id
getent group docker
ls -l /var/run/docker.sock

加入组后旧会话仍可能没有新组身份。重新登录或验证 newgrp docker。不要把 socket 改成全员可写。

21.5 daemon配置后启动失败

bash
sudo dockerd --validate --config-file=/etc/docker/daemon.json
sudo journalctl -u docker -b --no-pager
systemctl cat docker

常见:JSON逗号错误、同一选项同时在启动参数和配置文件、data-root权限、地址池冲突、代理格式错误。

21.6 拉镜像TLS或超时

先区分宿主机curl和daemon:

bash
getent hosts registry-1.docker.io
curl -I https://registry-1.docker.io/v2/
sudo systemctl show docker --property=Environment
docker pull hello-world

Registry /v2/ 返回未认证响应也可能说明TLS和HTTP链路已到达,具体状态需结合响应判断。

21.7 failed to mount overlay

检查:

bash
uname -r
docker info
findmnt "$(docker info --format '{{.DockerRootDir}}')"
sudo journalctl -u docker --since "30 minutes ago" --no-pager

方向:内核模块、底层文件系统、XFS特性、嵌套虚拟化环境、旧数据目录的storage driver不一致。

21.8 容器能启动但不能联网

检查:

bash
docker network ls
docker network inspect bridge
sysctl net.ipv4.ip_forward

再查 iptables/nftables、firewalld/ufw、企业安全软件、代理和DNS。不要立即关闭防火墙或Docker iptables管理。

二十二、商业场景:新生产节点上线验收

场景:为订单系统新增一台 Linux 容器节点。

22.1 验收清单

项目必须记录
主机OS、Kernel、CPU架构、时区、NTP
DockerEngine、CLI、containerd、runc、Compose、Buildx版本
安装源仓库URL、签名key、包版本
存储Docker Root Dir、文件系统、空间、inode、告警
资源cgroup版本、CPU/内存限制验证
网络地址池、DNS、代理、Registry、端口发布
安全docker组成员、socket权限、SELinux/AppArmor、审计
日志driver、轮转、集中采集
数据Volume策略、数据库备份和恢复
运维systemd、升级窗口、回滚、监控告警

22.2 验收过程

mermaid
flowchart TD
    A["按受信仓库安装固定版本"] --> B["验证systemd与daemon"]
    B --> C["验证Registry拉取"]
    C --> D["验证容器运行与日志"]
    D --> E["验证端口和自定义网络DNS"]
    E --> F["验证Volume持久化"]
    F --> G["验证cgroup资源限制"]
    G --> H["验证Compose和Buildx"]
    H --> I["接入监控、日志和审计"]
    I --> J["再接生产流量"]

不能因为 hello-world 输出成功就直接承载数据库和订单流量。

二十三、面试标准回答

Docker安装了哪些核心组件

Docker CLI负责解析命令并调用Engine API,dockerd管理镜像、容器、网络和Volume,containerd管理容器任务和镜像内容,shim维持任务与IO,runc根据OCI配置创建namespace、cgroup和rootfs中的进程;Buildx负责高级构建,Compose插件把多服务项目模型转换为Engine对象。容器最终仍是宿主机Linux进程。

为什么docker组近似root权限

docker组成员可以访问rootful daemon的Unix Socket,通过Engine API创建高权限容器、挂载宿主机目录或设备,因此通常可以间接获得宿主机高权限。不能把socket改成所有用户可写,也不能挂给普通业务容器;成员必须按管理员权限审批和审计,或者评估rootless模式。

rootless Docker解决什么问题

rootless让dockerd和容器进程以普通宿主机用户运行,并通过User Namespace映射降低daemon或容器漏洞直接获得宿主机root的风险。但低端口、网络、cgroup、OverlayFS、设备和监控存在兼容边界,它也不解决镜像漏洞、Secret泄露和错误Mount。

hello-world成功能证明什么

它大致证明CLI能连接daemon、daemon能解析和拉取镜像、containerd/runc能创建进程、stdout链路可用。但不能完整证明端口发布、自定义网络DNS、Volume持久化、日志轮转、cgroup限制、Compose和daemon升级行为,生产还要分层验收。

修改daemon.json后怎么安全生效

先备份和检查当前配置、unit启动参数及业务容器,使用JSON和dockerd validate校验,避免同一参数同时出现在命令行和配置文件;在摘流和有回滚方案的窗口重启daemon,立即查看systemd状态与journal,再用docker info和容器验收确认data-root、日志、网络等配置真正生效。

Docker升级为什么要做金丝雀

Engine升级可能影响API、containerd/runc、storage driver、网络规则、日志和运行容器管理。应先在测试环境验证,备份配置和业务数据,摘流一个节点进行金丝雀升级,验证daemon、网络、Volume、资源限制和业务,再分批扩散;live-restore也不等于升级完全无影响。

二十四、学习验收

不看答案完成:

  1. 画出 CLI、dockerd、containerd、shim、runc 和内核关系。
  2. 解释Docker官方仓库的HTTPS、GPG key、signed-by和发行版代号。
  3. 安装Engine、CLI、containerd、Buildx、Compose并记录包版本。
  4. 使用systemd查看service、socket、unit和journal。
  5. 解释Docker socket、docker组和rootless安全边界。
  6. 规划data-root、日志轮转、地址池、DNS、代理和Registry。
  7. 分别验证hello-world、端口、网络DNS、Volume、资源限制、Buildx和Compose。
  8. 制造一个daemon.json语法错误,在不删除数据目录的情况下定位并恢复。
  9. 写出Engine升级金丝雀、回滚和业务验收计划。
  10. 说明卸载软件包为什么不能直接等同删除Docker Root Dir。

关联知识点