02-Docker 安装与基础命令
上一篇已经把 Docker 的核心概念讲清楚了:镜像是交付物,容器是运行实例,仓库负责分发,Docker Engine 通过 containerd、runc、Namespace、Cgroup 和 OverlayFS 把应用隔离起来运行。本文进入真正的操作层:在一台 Linux 主机上安装。

1. 概述
上一篇已经把 Docker 的核心概念讲清楚了:镜像是交付物,容器是运行实例,仓库负责分发,Docker Engine 通过 containerd、runc、Namespace、Cgroup 和 OverlayFS 把应用隔离起来运行。本文进入真正的操作层:在一台 Linux 主机上安装 Docker Engine,完成基本验证,并掌握日常最常用的容器、镜像、日志、网络、数据卷和清理命令。
这篇文章的目标不是把 docker --help 逐项翻译一遍,而是建立一套可执行的最小工作流。读完之后,应该能够完成下面几件事:
- 在 Ubuntu 服务器上使用 Docker 官方 apt 仓库安装 Docker Engine。
- 判断 Docker Desktop、Docker Engine 和发行版自带
docker.io包之间的区别。 - 用
docker run、docker ps、docker logs、docker exec管理容器生命周期。 - 用
docker pull、docker images、docker inspect、docker rmi管理镜像。 - 用端口映射、环境变量、命名卷和 bind mount 启动一个可验证的 Nginx 容器。
- 在故障发生时快速判断是 daemon、权限、镜像、网络还是端口冲突问题。
本文以 Ubuntu 24.04 LTS / 22.04 LTS 服务器为主要环境,因为这是企业内网、云主机、测试环境最常见的 Docker Engine 落地点。macOS 和 Windows 更适合安装 Docker Desktop,本质上是在本机上运行一个轻量 Linux VM,再把 Docker CLI、Desktop UI 和虚拟机内的 Docker Engine 串起来。
2. 理论基础
2.1 Docker Engine 与 Docker Desktop 的区别
很多初学者会把 Docker 当成一个单一软件,但实际落地时至少要区分三类安装形态。
| 安装形态 | 典型平台 | 适用场景 | 需要注意 |
|---|---|---|---|
| Docker Engine | Ubuntu、Debian、RHEL、CentOS、Rocky Linux 等 Linux 服务器 | 生产服务器、测试服务器、CI Runner、云主机 | 直接管理宿主机容器运行时,需要关注 systemd、iptables、内核参数和磁盘空间 |
| Docker Desktop | macOS、Windows、开发者 Linux 桌面 | 本地开发、调试、学习、单机演示 | macOS/Windows 容器实际运行在 Linux VM 中,网络和文件挂载行为与纯 Linux 有差异 |
| 发行版自带包 | Ubuntu 的 docker.io、旧版第三方源 |
快速试验或受控内网仓库 | 版本可能落后,包名和插件组合可能不同,不适合作为标准生产安装基线 |
如果是服务器,优先采用 Docker 官方文档中的仓库安装方式;如果是个人电脑,优先采用 Docker Desktop。不要在同一台机器上混装多个来源的 Docker 包,否则后续排障会变得非常混乱。
2.2 Docker 安装后到底装了什么
使用官方仓库安装 Docker Engine 时,常见核心包包括:
docker-ce:Docker Community Edition 的 daemon 与核心组件。docker-ce-cli:docker命令行客户端。containerd.io:容器运行时服务,负责镜像、快照和容器生命周期的底层管理。docker-buildx-plugin:Buildx 构建插件,支持 BuildKit、多平台构建等能力。docker-compose-plugin:Compose v2 插件,命令形式是docker compose。
它们之间的调用关系可以简化理解为:
平时我们输入的 docker run nginx 看起来是一条命令,背后实际发生了多步动作:CLI 把请求发给 Docker daemon;daemon 检查本地有没有镜像;没有就从 registry 拉取;然后通过 containerd 创建容器快照;最后由 runc 创建隔离进程。
2.3 安装前需要想清楚的几件事
Docker 很容易装上,但生产环境真正容易出问题的是前置规划。
| 规划项 | 建议 |
|---|---|
| 操作系统 | 优先使用仍在维护期内的 LTS 发行版,例如 Ubuntu 24.04 LTS 或 22.04 LTS |
| 磁盘路径 | 默认数据目录是 /var/lib/docker,镜像和容器日志增长很快,建议单独规划磁盘或 LVM |
| 网络 | Docker 会创建 docker0 bridge,并可能修改 iptables/nftables 规则;生产主机需提前确认防火墙策略 |
| 权限 | 默认只有 root 或 docker 组用户能访问 Docker socket;把用户加入 docker 组等同于授予高权限 |
| 镜像源 | 内网环境通常需要配置 registry mirror 或私有仓库 |
| 日志 | 默认 json-file 日志如果不限制大小,长期运行容器可能撑满磁盘 |
| 版本管理 | 生产环境应记录 Docker Engine、containerd、Compose 插件版本,升级前先在测试环境验证 |
特别要注意 Docker socket 权限。/var/run/docker.sock 能控制宿主机上的容器,具备很高权限。不要为了方便把它随意挂进业务容器,也不要把普通用户无脑加入 docker 组。开发机可以这样做,生产服务器则应该经过权限评估。
3. 环境规划
本文采用下面的验证环境作为命令基线:
| 项目 | 说明 |
|---|---|
| 操作系统 | Ubuntu 24.04 LTS 或 Ubuntu 22.04 LTS |
| CPU 架构 | amd64 或 arm64 |
| 安装来源 | Docker 官方 apt repository |
| 主要组件 | Docker Engine、Docker CLI、containerd、Buildx、Compose v2 |
| 网络要求 | 能访问 download.docker.com、Docker Hub 或企业镜像代理 |
| 用户权限 | 具备 sudo 权限 |
如果你的服务器在公司内网,无法直接访问外部网络,需要提前准备三类代理:
- apt 仓库代理或离线 deb 包仓库。
- Docker Hub 镜像代理或私有镜像仓库。
- HTTPS 代理环境变量,例如
HTTP_PROXY、HTTPS_PROXY、NO_PROXY。
本文命令默认直接访问 Docker 官方仓库。内网离线安装可以沿用相同验证步骤,但包来源需要替换为企业内部仓库。
4. 实战操作
这个实操路径把本文步骤串成一条可复验流程:先清理冲突包,再完成仓库、安装、验证、权限、端口发布和数据持久化。后续命令都围绕这条路径展开。
4.1 卸载旧版本或冲突包
如果机器上曾经安装过 Ubuntu 自带的 docker.io,或者历史脚本装过旧包,先清理冲突包。官方文档建议在安装 Docker Engine 前移除旧版或非官方包名。
for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do
sudo apt-get remove -y "$pkg"
done
这一步不会删除 /var/lib/docker/ 中已有镜像、容器和卷数据。如果是生产主机,执行前仍然建议先确认是否存在历史容器:
sudo ls -lah /var/lib/docker 2>/dev/null || true
sudo systemctl status docker --no-pager || true
如果这台机器已经承载业务容器,不要直接清理或重装,应该先导出容器清单、镜像清单、Compose 文件和数据卷位置。
4.2 配置 Docker 官方 apt 仓库
安装依赖工具:
sudo apt-get update
sudo apt-get install -y ca-certificates curl
创建 keyrings 目录并导入 Docker 官方 GPG key:
sudo install -m 0755 -d /etc/apt/keyrings
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
添加 apt source:
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
更新索引:
sudo apt-get update
如果这里报 NO_PUBKEY、Could not resolve host、Connection timed out,先不要继续安装,应该回到网络、DNS、代理或 GPG key 步骤排查。
4.3 安装 Docker Engine 与插件
安装当前仓库中的稳定版本:
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
安装完成后检查服务状态:
sudo systemctl status docker --no-pager
sudo systemctl is-enabled docker
如果服务没有自动启动,可以手动启用并启动:
sudo systemctl enable --now docker
查看版本:
docker version
docker compose version
docker buildx version
这里不要在文章或运维手册里写死某个版本输出,因为 Docker Engine 和插件版本会随时间更新。更稳妥的做法是记录实际执行结果,例如在变更单或 CMDB 中记录:
docker version --format 'Client={{.Client.Version}} Server={{.Server.Version}}'
docker compose version
4.4 运行 hello-world 验证
执行最小验证:
sudo docker run hello-world
这条命令会完成四件事:
- Docker CLI 连接本机 Docker daemon。
- daemon 发现本地没有
hello-world镜像。 - daemon 从默认 registry 拉取镜像。
- daemon 创建并运行一个短生命周期容器,容器输出说明后退出。
查看退出后的容器:
sudo docker ps -a
清理测试容器:
sudo docker container prune
hello-world 适合验证安装链路,但不适合验证端口映射、日志、exec、数据卷等日常能力。下一步我们用 Nginx 做一个更接近真实业务的验证。
4.5 配置非 root 用户使用 Docker
开发机或测试机可以把当前用户加入 docker 组,避免每条命令都写 sudo:
sudo usermod -aG docker "$USER"
newgrp docker
重新登录后验证:
docker ps
生产环境要谨慎执行这一步。能访问 Docker socket 的用户基本可以通过挂载宿主机目录、启动特权容器等方式获得宿主机高权限。服务器上更推荐通过 sudoers、堡垒机、CI/CD 服务账号和审计流程控制 Docker 操作。
4.6 启动一个 Nginx 容器
拉取镜像:
docker pull nginx:alpine
后台启动容器,把宿主机 8080 端口映射到容器 80 端口:
docker run -d \
--name web-demo \
-p 8080:80 \
--restart unless-stopped \
nginx:alpine
检查容器状态:
docker ps
访问验证:
curl -I http://127.0.0.1:8080
查看日志:
docker logs web-demo
docker logs -f --tail=50 web-demo
进入容器执行命令:
docker exec -it web-demo sh
在容器内可以检查 Nginx 进程和配置目录:
ps aux
nginx -T | head
exit
停止、启动、重启容器:
docker stop web-demo
docker start web-demo
docker restart web-demo
删除容器:
docker rm -f web-demo
这里的 -f 会强制停止并删除容器。生产环境不要习惯性使用 rm -f,除非已经确认容器没有承载业务,或者数据已经通过卷、数据库、对象存储等方式持久化。
4.7 使用 bind mount 发布自定义页面
创建本地目录和测试页面:
mkdir -p ~/docker-lab/nginx/html
cat > ~/docker-lab/nginx/html/index.html <<'EOF'
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>Docker Nginx Demo</title>
</head>
<body>
<h1>Hello Docker</h1>
<p>这个页面来自宿主机 bind mount。</p>
</body>
</html>
EOF
启动容器并挂载目录:
docker run -d \
--name nginx-bind \
-p 8081:80 \
-v "$HOME/docker-lab/nginx/html:/usr/share/nginx/html:ro" \
nginx:alpine
验证页面:
curl http://127.0.0.1:8081
这里的 :ro 表示容器内只读挂载。对于配置文件、静态页面、证书等场景,如果容器不需要写入,优先使用只读挂载,减少误改和安全风险。
4.8 使用命名卷保存数据
bind mount 适合把宿主机某个明确路径挂进容器;命名卷更适合由 Docker 管理生命周期。以 Nginx 日志目录为例:
docker volume create nginx-logs
docker run -d \
--name nginx-volume \
-p 8082:80 \
-v nginx-logs:/var/log/nginx \
nginx:alpine
查看卷信息:
docker volume ls
docker volume inspect nginx-logs
删除容器后,卷仍然保留:
docker rm -f nginx-volume
docker volume ls
删除卷:
docker volume rm nginx-logs
注意:容器删除不等于数据删除,数据卷删除才会真正清掉 Docker 管理的卷数据。反过来,如果没有规划卷,容器可写层里的业务数据会随容器删除而丢失。
5. 配置详解
5.1 docker run 常用参数
docker run 是初学阶段最重要的命令。它不是单纯的“运行”,而是“基于镜像创建一个新容器并启动”。
| 参数 | 作用 | 示例 |
|---|---|---|
-d |
后台运行容器 | docker run -d nginx |
--name |
指定容器名称 | --name web-demo |
-p |
端口映射 | -p 8080:80 |
-e |
注入环境变量 | -e TZ=Asia/Shanghai |
-v |
挂载卷或目录 | -v app-data:/data |
--restart |
设置重启策略 | --restart unless-stopped |
--network |
指定网络 | --network bridge |
--memory |
限制内存 | --memory 512m |
--cpus |
限制 CPU | --cpus 1.5 |
--user |
指定容器内运行用户 | --user 1000:1000 |
--rm |
容器退出后自动删除 | docker run --rm alpine uname -a |
一个稍完整的例子:
docker run -d \
--name app-nginx \
--restart unless-stopped \
-p 8080:80 \
-e TZ=Asia/Shanghai \
-v "$PWD/html:/usr/share/nginx/html:ro" \
--memory 256m \
--cpus 0.5 \
nginx:alpine
这个命令已经包含了生产演练中最常见的几个要素:固定名称、自动重启、端口映射、时区、只读挂载和资源限制。
5.2 容器状态管理命令
| 命令 | 作用 |
|---|---|
docker ps |
查看正在运行的容器 |
docker ps -a |
查看所有容器,包括已退出容器 |
docker start <container> |
启动已存在容器 |
docker stop <container> |
优雅停止容器 |
docker restart <container> |
重启容器 |
docker rm <container> |
删除已停止容器 |
docker rm -f <container> |
强制停止并删除容器 |
docker inspect <container> |
查看容器详细 JSON 信息 |
docker stats |
查看容器资源使用 |
docker top <container> |
查看容器内进程 |
排障时不要只看 docker ps。如果容器启动后立即退出,docker ps 看不到,需要用:
docker ps -a
docker logs <container>
docker inspect <container>
5.3 镜像管理命令
| 命令 | 作用 |
|---|---|
docker pull <image> |
拉取镜像 |
docker images |
查看本地镜像 |
docker image ls |
查看本地镜像,等同于新式子命令 |
docker rmi <image> |
删除镜像 |
docker image prune |
清理悬空镜像 |
docker history <image> |
查看镜像层历史 |
docker inspect <image> |
查看镜像元数据 |
查看镜像占用:
docker system df
只清理悬空镜像:
docker image prune
清理所有未被容器使用的镜像:
docker image prune -a
prune -a 在开发机上很方便,在生产服务器上要谨慎。它不会删除正在被容器使用的镜像,但会删除暂时没有容器引用的镜像,可能导致下次回滚或启动时需要重新拉取。
5.4 日志查看与限制
查看日志:
docker logs web-demo
docker logs --tail=100 web-demo
docker logs -f --since=30m web-demo
默认日志驱动常见为 json-file。长期运行容器建议配置日志轮转,否则 /var/lib/docker/containers/<container-id>/ 下的日志文件可能持续增长。
可以在 /etc/docker/daemon.json 中配置:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "3"
}
}
重启 Docker daemon:
sudo systemctl restart docker
注意:daemon 级别配置通常只影响新建容器。已经存在的容器是否生效,需要按实际版本和配置验证,稳妥做法是重建容器。
5.5 Docker daemon 基础配置
常见 daemon 配置文件路径:
/etc/docker/daemon.json
一个适合测试环境的示例:
{
"data-root": "/var/lib/docker",
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "3"
},
"default-address-pools": [
{
"base": "172.30.0.0/16",
"size": 24
}
]
}
配置前先检查 JSON 格式:
python3 -m json.tool /etc/docker/daemon.json
重启并验证:
sudo systemctl restart docker
sudo systemctl status docker --no-pager
docker info
如果重启失败,优先查看:
journalctl -u docker -n 100 --no-pager
6. 验证与测试
6.1 基础健康检查
安装后建议固定执行这组检查:
docker version
docker info
docker compose version
docker buildx version
docker run --rm hello-world
判断成功的关键不是背某段输出,而是确认:
docker version同时能显示 Client 和 Server 信息。docker info能正常返回 daemon、storage driver、cgroup driver、registry 等信息。hello-world能拉取镜像并运行。docker compose version能显示 Compose v2 插件版本。- 普通用户是否能执行 Docker 命令符合你的权限规划。
6.2 端口映射验证
启动 Nginx:
docker run -d --name port-test -p 8088:80 nginx:alpine
验证本机访问:
curl -I http://127.0.0.1:8088
验证监听端口:
ss -lntp | grep 8088 || true
验证容器端口配置:
docker port port-test
docker inspect port-test --format '{{json .NetworkSettings.Ports}}'
如果本机能访问、远端不能访问,问题通常不在 Docker 容器,而在云安全组、服务器防火墙或上游网络策略。
6.3 数据持久化验证
创建命名卷并写入文件:
docker volume create persist-test
docker run --rm \
-v persist-test:/data \
alpine sh -c 'date > /data/created-at.txt && cat /data/created-at.txt'
再次启动新容器读取:
docker run --rm \
-v persist-test:/data \
alpine cat /data/created-at.txt
如果第二次能读到文件,说明数据保存在命名卷中,而不是临时容器可写层中。
6.4 资源限制验证
启动一个带资源限制的容器:
docker run -d \
--name limited-nginx \
--memory 128m \
--cpus 0.5 \
nginx:alpine
查看限制和实时资源:
docker inspect limited-nginx --format 'Memory={{.HostConfig.Memory}} NanoCPUs={{.HostConfig.NanoCpus}}'
docker stats limited-nginx
这里的数值单位不一定直观:内存通常是字节,CPU 可能以 NanoCPUs 表示。运维手册中应写清楚人类可读参数,例如 --memory 128m、--cpus 0.5,不要只记录 inspect 里的底层值。
6.5 清理实验环境
清理本文创建的测试容器:
docker rm -f web-demo nginx-bind nginx-volume port-test limited-nginx 2>/dev/null || true
清理测试卷:
docker volume rm nginx-logs persist-test 2>/dev/null || true
按需清理未使用资源:
docker system df
docker container prune
docker image prune
docker volume prune
不要在生产服务器上随手执行 docker system prune -a --volumes。这条命令会清理未使用镜像、容器、网络和卷,影响面很大,必须先确认数据备份和业务状态。
7. 故障排查
这张矩阵把安装后最常见的问题按证据入口归类:服务状态、权限、镜像拉取、容器日志、端口映射、磁盘空间和 daemon 配置。排障时先收集证据,再决定是否改配置或清理资源。
7.1 Cannot connect to the Docker daemon
典型现象:
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
排查顺序:
sudo systemctl status docker --no-pager
sudo journalctl -u docker -n 100 --no-pager
ls -l /var/run/docker.sock
常见原因:
- Docker 服务没有启动。
/etc/docker/daemon.jsonJSON 格式错误。- Docker 数据目录权限或磁盘异常。
- 当前用户没有访问 Docker socket 的权限。
- 系统升级后 containerd 或依赖服务异常。
7.2 普通用户执行 Docker 提示 permission denied
检查当前用户组:
id
ls -l /var/run/docker.sock
如果是开发机,可以加入 docker 组:
sudo usermod -aG docker "$USER"
newgrp docker
如果是生产服务器,不建议简单扩大用户权限。应明确谁可以操作 Docker、操作是否需要 sudo、命令是否有审计记录。
7.3 镜像拉取失败
常见现象包括 DNS 失败、TLS 失败、连接超时、认证失败、rate limit。
排查命令:
curl -I https://registry-1.docker.io/v2/
docker pull nginx:alpine
docker login
docker info | grep -i proxy -A3
处理方向:
- 检查 DNS、默认路由、防火墙和代理。
- 内网环境配置 registry mirror 或私有仓库。
- 私有镜像确认
docker login的 registry 地址是否正确。 - CI 环境避免匿名频繁拉取公共镜像,尽量使用认证账号或内部缓存。
7.4 容器启动后立即退出
先查看退出状态:
docker ps -a
docker logs <container>
docker inspect <container> --format 'ExitCode={{.State.ExitCode}} Error={{.State.Error}}'
常见原因:
- 容器主进程执行完成,所以正常退出,例如
alpine echo hello。 - 启动命令写错,entrypoint 或 command 不存在。
- 配置文件挂载路径错误。
- 端口、权限、依赖服务、环境变量缺失。
- 应用自身启动失败。
容器不是虚拟机,容器内的主进程结束,容器就会退出。想要容器长期运行,镜像必须以前台进程作为主进程,例如 Nginx 的 daemon off 模式。
7.5 端口映射失败或访问不通
如果启动时报端口占用:
docker run -d --name web -p 8080:80 nginx:alpine
排查:
ss -lntp | grep 8080 || true
docker ps --format 'table {{.Names}}\t{{.Ports}}'
如果容器已启动但访问不通:
docker logs web
docker exec web nginx -T
docker port web
curl -I http://127.0.0.1:8080
再从外部访问时,需要检查云安全组、主机防火墙、NAT、负载均衡和上游 ACL。
7.6 磁盘空间被 Docker 占满
查看 Docker 占用:
docker system df
sudo du -sh /var/lib/docker
查看大日志文件:
sudo find /var/lib/docker/containers -name '*-json.log' -size +100M -ls
处理建议:
- 给 Docker 配置日志轮转。
- 清理无用容器、悬空镜像、构建缓存。
- 对生产环境先确认容器、镜像和卷的用途,再清理。
- 长期运行环境把
/var/lib/docker放在可监控、可扩容的磁盘上。
构建缓存清理:
docker builder prune
7.7 daemon 配置后 Docker 无法启动
如果修改 /etc/docker/daemon.json 后 Docker 起不来,先检查 JSON:
sudo python3 -m json.tool /etc/docker/daemon.json
sudo journalctl -u docker -n 100 --no-pager
常见问题:
- JSON 多了尾随逗号。
data-root路径不存在或权限不对。default-address-pools和现有网络冲突。- 配置项拼写错误。
- 代理配置写在了错误位置。
修改 daemon 配置前建议备份:
sudo cp /etc/docker/daemon.json /etc/docker/daemon.json.$(date +%F-%H%M%S).bak
8. 运维建议
8.1 建立最小标准安装手册
企业内部不要让每个工程师从搜索引擎复制不同安装命令。建议维护一份内部标准,至少包括:
- 支持的操作系统版本。
- Docker Engine 和插件安装来源。
- 是否允许普通用户加入 docker 组。
/var/lib/docker是否独立挂载。- daemon 日志轮转配置。
- 镜像仓库和代理地址。
- 基础验证命令。
- 升级和回滚方式。
这份标准可以很短,但必须可复制、可审计、可回滚。
8.2 生产容器不要只靠 docker run
docker run 适合学习、临时验证和排障。生产环境至少应该把参数固化到 Compose 文件、systemd unit、Ansible playbook 或平台化发布系统中。否则一旦主机重装或容器被删除,很难准确复原当时的启动参数。
短期可以用下面命令反查容器配置:
docker inspect <container>
但 inspect 是结果,不是期望状态。真正可维护的方式是把配置写进版本库。
8.3 给容器日志和数据划边界
不要把业务数据写在容器可写层。推荐原则:
- 数据库、上传文件、状态数据放到命名卷、bind mount 或外部存储。
- 容器日志设置大小限制,并接入集中日志系统。
- 配置文件用只读挂载。
- 临时缓存可以留在容器可写层,但要能承受容器重建后丢失。
8.4 升级前先做兼容性验证
Docker Engine、containerd、Buildx、Compose 插件都可能影响构建、网络、日志和运行行为。升级前至少验证:
docker version
docker compose version
docker run --rm hello-world
docker run --rm -p 18080:80 nginx:alpine
docker compose config
docker compose up -d
如果生产环境依赖特定 storage driver、特殊网络、GPU、私有 registry 或老版本 Compose 文件,更要先在测试环境复现。
8.5 把 Docker 主机纳入基础设施监控
建议监控以下指标:
- Docker daemon 是否运行。
/var/lib/docker所在磁盘使用率。- 容器数量、重启次数、退出状态。
- 容器 CPU、内存、网络和块设备 I/O。
- 大日志文件增长速度。
- 镜像拉取失败、容器启动失败等事件。
Docker 是应用交付工具,也是宿主机上的高权限运行时。只监控应用进程、不监控 Docker 主机,会在磁盘、网络、日志和权限问题上留下盲区。
9. 安装前的决策清单
安装 Docker 之前,先确认这台机器的角色。开发电脑、测试服务器、CI 构建机、单机生产服务器和 Kubernetes 节点,对 Docker 的安装方式、权限边界和升级节奏并不一样。开发电脑可以优先使用 Docker Desktop,因为它集成了图形界面、Compose、Kubernetes 可选能力和本地体验;Linux 服务器通常优先安装 Docker Engine,因为运行路径更清晰,也更适合纳入系统服务、监控和配置管理。
第二个决策是数据目录放在哪里。Docker 默认数据目录通常位于 /var/lib/docker,镜像、容器层、卷和构建缓存都会消耗这里的磁盘。如果根分区很小,安装后很快会遇到磁盘不足。生产服务器应提前规划独立磁盘或分区,并把 Docker 数据目录容量纳入监控。
第三个决策是普通用户是否加入 docker 组。加入后可以免 sudo 执行 Docker 命令,但这基本等价于授予该用户控制宿主机 Docker 的高权限。开发机可以按团队规则配置;生产服务器上应谨慎,只给受控运维账号或自动化账号,并保留审计。
第四个决策是镜像来源。默认访问 Docker Hub 适合学习,但企业网络可能需要代理、镜像加速、私有 registry 或云厂商镜像仓库。安装时就要确认能否稳定拉取基础镜像,不能等上线时才发现网络访问受限。
第五个决策是版本和升级策略。Docker Engine、containerd、Buildx、Compose 插件都会影响构建和运行行为。生产环境不建议无计划自动升级,应先在测试环境验证核心工作负载、网络、卷、日志和镜像构建,再安排维护窗口升级。
10. 基础命令的学习顺序
学习 Docker 基础命令时,不建议一次性背完整 CLI。更有效的顺序是围绕容器生命周期展开。
第一组命令回答“镜像从哪里来”:
docker pull nginx:alpine
docker images
docker image inspect nginx:alpine
第二组命令回答“容器如何启动和停止”:
docker run --name web -d -p 8080:80 nginx:alpine
docker ps
docker stop web
docker start web
docker rm -f web
第三组命令回答“容器内部发生了什么”:
docker logs web
docker exec -it web sh
docker inspect web
docker stats web
第四组命令回答“网络和数据如何接入”:
docker network ls
docker volume ls
docker run --name web -d -p 8080:80 -v webdata:/usr/share/nginx/html nginx:alpine
第五组命令回答“如何清理实验环境”:
docker ps -a
docker rm -f web
docker image prune
docker volume prune
清理命令要格外谨慎。学习环境可以 prune,生产环境必须先确认镜像、容器和卷的业务归属。尤其是 docker volume prune,它会删除未被容器引用的卷,但“未被引用”不等于“不再需要”。如果业务容器临时停止,数据卷可能被误删。
11. 安装后的基线配置
安装完成后,建议建立一份 Docker 主机基线。基线不需要复杂,但要覆盖运行时、日志、权限、网络和数据。
日志方面,至少要限制容器日志大小。否则一个异常循环输出日志的容器,就可能把 /var/lib/docker 打满。可以通过 daemon 配置设置默认日志驱动和大小,例如 json-file 的 max-size、max-file。如果已经有集中日志平台,可以把容器日志接入 Fluent Bit、Vector、Promtail 或其他采集器。
权限方面,要明确谁能执行 Docker 命令。Docker socket 是高权限入口,任何能访问 /var/run/docker.sock 的用户或容器,都可能创建特权容器、挂载宿主机路径或读取敏感数据。不要把 Docker socket 随意挂进业务容器,也不要把所有开发者都加入生产服务器的 docker 组。
网络方面,要记录默认 bridge、自定义网络、端口发布和宿主机防火墙之间的关系。Docker 会操作 iptables/nftables 规则,不同发行版和安全策略下行为可能不同。安装后应测试端口发布、容器出网、容器间通信和防火墙规则是否符合预期。
数据方面,要确认 /var/lib/docker 所在磁盘、备份策略和清理策略。镜像层、容器可写层、命名卷、构建缓存都会增长。没有容量监控的 Docker 主机,迟早会因为磁盘打满影响所有容器。
12. 一台 Docker 主机的交付验收
如果把 Docker 安装到团队共享服务器或生产服务器,建议按下面清单验收:
| 类别 | 验收项 | 证据 |
|---|---|---|
| 版本 | Docker Engine、containerd、Buildx、Compose | docker version、docker compose version |
| 服务 | daemon 开机启动、状态正常 | systemctl status docker |
| 镜像 | 能拉取官方测试镜像或私有仓库镜像 | docker pull hello-world |
| 容器 | 能启动、停止、删除测试容器 | docker run --rm hello-world |
| 端口 | 端口发布可从预期来源访问 | Nginx 测试容器和浏览器/curl |
| 数据 | 命名卷重建后数据保留 | 删除容器后重建验证 |
| 日志 | 日志大小限制或采集生效 | daemon 配置和日志平台 |
| 权限 | docker 组成员受控 | getent group docker |
| 磁盘 | Docker 数据目录容量可监控 | docker system df、系统监控 |
| 备份 | 配置、Compose 文件、数据卷策略明确 | 文档和备份记录 |
这张验收表可以避免“安装成功但不可运维”。尤其是共享服务器,谁可以启动容器、容器能暴露哪些端口、数据放在哪里、日志是否可控,都需要在安装后立即明确。
13. 升级与回滚
Docker 升级前要先确认影响面。Docker Engine 升级可能影响 daemon 行为、网络规则、日志驱动、storage driver、BuildKit、Compose 插件和镜像构建。普通学习环境可以直接按官方文档升级;生产环境要先在测试主机验证核心容器。
升级前建议记录:
docker version
docker info
docker compose version
docker system df
docker network ls
docker volume ls
docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}'
升级后再执行同样命令对比。还要验证至少一个端口发布容器、一个带命名卷的容器、一个 Compose 应用和一次镜像构建。如果团队依赖 GPU、私有 registry、代理、特殊 storage driver 或老版本 Compose 语法,这些都要单独验证。
回滚策略取决于安装方式。通过官方 apt/yum 仓库安装时,可以保留旧版本包信息,必要时降级;通过 Docker Desktop 时,要关注桌面端版本和虚拟机数据;通过自动化脚本安装时,要保留脚本版本和包源。无论哪种方式,真正关键的是业务数据不能只存在容器可写层,否则回滚 Docker 版本也无法恢复数据。
14. 从单机命令走向声明式配置
本文展示了大量 docker run 命令,但它们更适合学习和临时验证,不适合作为长期交付方式。原因很简单:命令历史不可审计,参数容易遗漏,团队无法清楚知道期望状态。
当一个容器开始包含端口、卷、环境变量、网络、重启策略和资源限制时,就应该把它写成 Compose 文件或其他声明式配置。这样配置可以进入版本库,可以评审,可以回滚,也可以被 CI/CD 或自动化平台调用。后续 Compose 文章会继续展开这一点。
基础命令仍然重要,因为排障时经常需要 docker ps、logs、inspect、exec、stats 来看真实状态。但运行状态和期望配置要分开:CLI 用于观察和临时操作,Compose/脚本/平台用于表达长期期望状态。
15. Docker 主机的常见故障复盘
15.1 Docker daemon 无法启动
安装后最常见的问题是 daemon 起不来。不要只反复执行 systemctl restart docker,要先看日志和配置。常见原因包括 daemon.json JSON 格式错误、配置了不存在的 registry mirror、数据目录权限异常、storage driver 与内核不兼容、iptables/nftables 规则冲突、磁盘已满。
排查顺序可以这样:
systemctl status docker --no-pager
journalctl -u docker -n 100 --no-pager
sudo dockerd --validate --config-file /etc/docker/daemon.json
df -h
docker info
如果是 daemon 配置错误,优先回滚最近修改的 /etc/docker/daemon.json,再重启服务。不要为了让 Docker 启动而删除整个 /var/lib/docker,那会影响镜像、容器和卷,可能直接造成数据丢失。
15.2 容器端口发布后访问不通
端口访问不通要分层检查。第一层看容器是否运行,第二层看应用是否在容器内监听正确地址,第三层看端口是否发布到宿主机,第四层看宿主机防火墙和云安全组,第五层看客户端访问路径。
docker ps
docker logs <container>
docker exec <container> ss -lntp
docker port <container>
ss -lntp | grep 8080
curl -v http://127.0.0.1:8080
一个典型错误是应用只监听 127.0.0.1。在容器内监听本地回环地址,宿主机即使发布端口,也不一定能访问应用。更稳妥的方式是让容器内服务监听 0.0.0.0,再通过 Docker 端口发布和防火墙控制外部访问。
15.3 磁盘被镜像、日志和卷占满
Docker 主机磁盘打满后,容器可能无法启动、日志无法写入、数据库写入失败,甚至 daemon 本身异常。排查时先看整体占用:
docker system df
docker ps --size
du -sh /var/lib/docker/* 2>/dev/null
清理时要区分对象。镜像可以按未使用状态清理,容器可以清理退出状态,构建缓存可以按时间清理,但卷必须确认业务归属。很多数据事故来自把 volume 当成缓存清掉。生产环境建议先导出清理候选清单,由业务或运维确认后再执行。
16. 安装文档如何沉淀
完成一次 Docker 安装后,应该把结果沉淀成团队文档,而不是只留下命令历史。文档至少包含:操作系统版本、Docker 安装来源、Docker Engine 版本、Compose 版本、daemon 配置、数据目录、日志策略、普通用户权限、registry 配置、代理配置、验证命令、回滚方式。
如果团队有多台 Docker 主机,文档还应该变成自动化脚本或配置管理任务。手工安装可以作为第一次探索,但长期应该用 Ansible、Shell 脚本、云初始化、镜像模板或平台能力统一。否则每台主机的 Docker 版本、日志限制、registry、权限和数据目录都会慢慢漂移。
安装文档还要标注“不适用范围”。比如本文以 Ubuntu 和 Docker 官方仓库为主,如果是 RHEL、Debian、Windows、macOS、离线环境、国产操作系统或云厂商托管容器服务,安装路径都需要单独复核官方文档。把范围写清楚,比给出一个看似万能的脚本更可靠。
17. 学完本篇后的练习
建议完成三个练习。第一,安装 Docker 后运行 hello-world 和 Nginx,记录完整验证命令。第二,创建一个命名卷,写入文件,删除容器后重建,确认数据保留。第三,故意启动一个端口冲突容器,观察错误日志并写出排查过程。
这三个练习分别覆盖 daemon、端口和数据。它们比单纯背命令更有价值,因为生产问题往往就发生在这些位置。后续进入 Dockerfile、网络和数据卷时,这些基础命令会反复用到。
18. 多环境安装差异
不同环境安装 Docker 的关注点不同。开发电脑更关注体验,例如 Docker Desktop、代理、文件共享、资源配额和本地 Kubernetes;测试服务器更关注和生产一致,例如 Docker Engine 版本、Compose 插件、私有镜像仓库和自动化部署;生产服务器更关注安全、审计、容量、日志和升级窗口。
离线环境还要单独处理。不能访问公网时,需要提前准备 Docker Engine 安装包、依赖包、镜像 tar 包或私有 registry。离线安装文档要写清包版本、校验方式、导入镜像命令和升级路径。不要在离线现场临时找包,否则很容易出现版本不一致或来源不可追踪。
云服务器也有特殊点。安全组、云防火墙、弹性网卡、云盘挂载和云监控都会影响 Docker 使用。端口发布后外部不能访问,不一定是 Docker 问题,也可能是安全组没放行;数据卷写入慢,不一定是容器问题,也可能是云盘性能规格不够。安装验证时要同时检查宿主机、Docker 和云平台三层。
19. 基础命令和生产操作的边界
初学者常用 docker run -it --rm 做实验,这是好习惯,因为环境干净、容易清理。但生产服务通常不能这样运行。生产容器需要重启策略、日志策略、数据卷、网络、健康检查、资源限制和配置管理。命令越长,越应该沉淀成 Compose 或自动化配置。
同样,docker exec 适合排障,不适合长期变更。进入容器里手工改配置,容器重建后就会丢失,也无法审计。正确做法是把配置写到镜像、挂载文件或声明式配置中,再重建容器。容器化的核心价值就是让运行状态可重建,而不是让容器变成另一台被手工维护的服务器。
安装和命令学习的最终目标,是让 Docker 主机进入可重复管理状态。也就是说,换一台新主机时,团队能按同一份文档或脚本完成安装;容器异常时,能用同一组命令定位 daemon、镜像、容器、网络和卷;升级失败时,能按记录回滚。做到这一点,Docker 才从个人工具变成团队基础设施。
如果只会在一台机器上手工安装,却无法解释包源、版本、数据目录、日志限制、权限和回滚方式,就还不能把这台 Docker 主机交给团队长期使用。安装完成后的交付记录,和安装命令本身同样重要。
后续所有容器实践都建立在这台主机的可靠性之上;主机基线不稳,镜像、网络和数据卷都会受到影响。
所以安装完成后要先验主机,再验容器,最后再验应用,不要把应用异常直接归因于 Docker 本身。
这条顺序也适用于后续所有 Docker 故障处理。
先确认基础,再判断应用,最后沉淀记录并持续复验。
20. 总结
本文完成了 Docker 容器化实战系列的第二步:从安装 Docker Engine 到掌握基础命令。核心结论如下:
- 服务器优先使用 Docker 官方仓库安装 Docker Engine,开发电脑优先使用 Docker Desktop。
- 安装 Docker 不只是装一个 CLI,还包括 daemon、containerd、Buildx、Compose 等组件。
docker run是学习 Docker 的入口,但生产配置应该沉淀为 Compose、脚本或自动化平台。- 排障要围绕 daemon 状态、用户权限、镜像拉取、容器日志、端口映射和数据卷展开。
- Docker 数据目录、日志轮转、socket 权限和镜像仓库,是从学习环境走向生产环境必须提前规划的部分。
下一篇会进入镜像构建与 Dockerfile。到那一步,重点会从“如何运行别人做好的镜像”转向“如何把自己的应用做成可交付、可复用、可缓存、可安全扫描的镜像”。
参考资料
- Docker Docs:Install Docker Engine on Ubuntu
- Docker Docs:Install Docker Engine
- Docker Docs:Docker Desktop
- Docker Docs:docker container run CLI reference
- Docker Docs:Running containers
- Docker Docs:Docker CLI reference
- [验证环境:Ubuntu 24.04 LTS / Ubuntu 22.04 LTS 安装路径;命令依据 Docker 官方文档 2026-05-19 检索]