Docker-02 安装与配置:从能运行到可维护
1. 安装前先做选择
Docker 有两种常见形态:
| 形态 | 适合场景 | 主要组件 |
|---|---|---|
| Docker Engine | Linux 服务器、CI、生产环境 | dockerd、containerd、runc、CLI、Compose plugin |
| Docker Desktop | macOS、Windows 桌面开发 | Docker CLI + Linux VM + Desktop UI + 可选 Kubernetes |
macOS 和 Windows 的内核不是 Linux,Docker Desktop 会启动一个 Linux 虚拟机,让 Linux 容器运行在其中。因此 Desktop 里的“宿主机路径”“资源限制”和 Linux 服务器上看到的路径并不完全等价。
生产环境优先使用发行版官方仓库或 Docker 官方仓库的 Engine;不要把 Docker Desktop 当作服务器 daemon 使用。
2. Ubuntu 安装 Docker Engine
以下示例适用于较新的 Ubuntu。正式安装前先确认发行版和架构:
cat /etc/os-release
uname -m
2.1 清理冲突包
Ubuntu 可能预装 docker.io、docker-compose 等发行版包。不要在同一台机器上混用不同来源的 Docker 包:
sudo apt-get remove -y docker.io docker-doc docker-compose podman-docker containerd runc
这不会自动删除 /var/lib/docker 中的数据,但在生产机上仍应先确认包和数据目录。
2.2 添加 Docker 官方仓库
sudo apt-get update
sudo apt-get install -y ca-certificates curl
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
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo \"$VERSION_CODENAME\") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
如果公司网络不能访问官方仓库,应配置企业代理或使用可信的内部镜像仓库;不要随意下载来源不明的安装脚本。
2.3 启动和验证
sudo systemctl enable --now docker
sudo systemctl status docker --no-pager
sudo docker run --rm hello-world
docker version
docker compose version
docker version 同时显示 Client 和 Server。只有 Client 有输出而 Server 连接失败,通常表示 daemon 未启动、socket 权限不对或 DOCKER_HOST 指向了错误的地址。
3. RHEL、Rocky、AlmaLinux 安装
sudo dnf -y remove docker docker-client docker-client-latest \
docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine
sudo dnf -y install dnf-plugins-core
sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo dnf -y install docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now docker
sudo docker run --rm hello-world
启用了 SELinux 的主机不要为了让某个 bind mount 能写就全局关闭 SELinux。优先使用正确的标签选项(例如 :Z 或 :z,具体以发行版和安全策略为准),并确认容器确实需要写权限。
4. macOS 和 Windows:Docker Desktop
安装 Docker Desktop 后,验证:
docker version
docker run --rm hello-world
docker compose version
建议在 Desktop 设置中检查:
- CPU / Memory:Linux VM 的资源上限,不是无限使用宿主机资源。
- Disk image location / size:镜像、容器可写层、volume 通常存放在 Linux VM 的磁盘镜像中。
- File sharing:只有被共享的宿主机目录才能高效、安全地 bind mount 到容器。
- Resource saver:开发机休眠时 daemon 可能暂停,不能据此判断生产行为。
- Kubernetes:只为本地学习启用;它不是生产集群。
macOS 的 /Users/... 与 Linux 容器内的 /work 是两个不同视图。Compose 中写相对路径时,路径相对于 Compose 文件所在目录解析。
5. 让普通用户使用 Docker
Linux 上可以把用户加入 docker 组:
sudo usermod -aG docker "$USER"
newgrp docker
docker run --rm hello-world
这很方便,但必须知道它的安全含义:能访问 Docker socket 的用户通常可以启动一个挂载宿主根目录的高权限容器,因此在安全边界上近似拥有宿主机 root 权限。多租户服务器不要把加入 docker 组当作普通的“免 sudo”权限。
如果只是临时使用,可以继续使用 sudo docker ...;更强的隔离方案是 rootless Docker。
6. /etc/docker/daemon.json 常用配置
创建或修改前先确认文件不存在冲突,并使用 JSON 校验。一个开发/测试服务器示例:
{
"data-root": "/data/docker",
"log-driver": "local",
"log-opts": {
"max-size": "50m",
"max-file": "5"
},
"live-restore": true,
"default-address-pools": [
{
"base": "172.30.0.0/16",
"size": 24
}
]
}
字段含义:
| 配置 | 作用 | 注意事项 |
|---|---|---|
data-root |
改变镜像、容器、volume 等数据目录 | 迁移前停 daemon,确认磁盘和权限 |
log-driver |
设置默认容器日志驱动 | 已创建容器通常需要重建才完全采用新默认值 |
log-opts |
限制日志单文件大小和保留份数 | 避免 json-file 无限增长 |
live-restore |
daemon 重启期间尽量保持容器运行 | 不是升级和内核重启的高可用方案 |
default-address-pools |
为自定义网络分配地址池 | 避免和公司 VPN、VPC、宿主路由冲突 |
配置后检查并重启:
sudo dockerd --validate --config-file=/etc/docker/daemon.json
sudo systemctl restart docker
docker info
journalctl -u docker -n 100 --no-pager
不同 Docker 版本对 dockerd --validate 的支持可能不同;不支持时至少用 jq empty /etc/docker/daemon.json 检查 JSON,再查看 systemd 日志。
6.1 镜像加速与 insecure registry
可以在 daemon.json 中配置可信的镜像加速器:
{
"registry-mirrors": [
"https://mirror.example.com"
]
}
只有在隔离的测试网络中,才考虑 insecure-registries;生产环境应为私有 registry 配置 TLS 和正确的 CA,而不是关闭证书校验:
{
"insecure-registries": ["registry.test.local:5000"]
}
把 insecure-registries 带到生产会让镜像传输和凭据面临中间人攻击风险。
7. Compose v2 插件
现在推荐使用带空格的 docker compose,而不是旧的独立 Python docker-compose:
docker compose version
docker compose config
docker compose up -d
docker compose ps
docker compose logs -f
docker compose down
docker compose config 会合并 .env、变量替换和多个 Compose 文件,是启动前发现 YAML/变量错误的好习惯。
8. Rootless Docker
Rootless 模式让 daemon 和容器都以普通用户身份运行,降低 daemon 被攻破后直接获得宿主 root 的风险。代价包括低端口绑定、网络性能、cgroup 控制和部分存储驱动能力受限。
基本检查:
docker info --format '{{json .SecurityOptions}}'
docker info | grep -iE 'rootless|cgroup|storage driver'
是否使用 rootless 取决于内核、发行版、网络插件和业务约束;不要只因为“rootless”三个字就跳过功能验证。
9. 安装后的验收清单
# Client/Server 版本和上下文
docker version
docker context show
# daemon 运行状态
docker info
systemctl is-active docker
# 镜像拉取、容器启动、网络端口、日志
docker pull nginx:alpine
docker run -d --name docker-check -p 127.0.0.1:18080:80 nginx:alpine
curl -fsS http://127.0.0.1:18080
docker logs docker-check
docker rm -f docker-check
10. 常见安装故障
10.1 Cannot connect to the Docker daemon
按顺序检查:
systemctl status docker --no-pager
echo "${DOCKER_HOST:-<未设置>}"
docker context ls
ls -l /var/run/docker.sock
journalctl -u docker -n 100 --no-pager
常见原因是 daemon 没启动、当前用户没有 socket 权限、context 指向远程地址,或者 DOCKER_HOST 覆盖了默认 socket。
10.2 permission denied 访问 socket
确认用户组和当前会话:
id -nG
getent group docker
newgrp docker
加入用户组后,已有 shell 不一定马上获得新的附加组凭证;重新登录或使用 newgrp。
10.3 磁盘被 Docker 占满
docker system df
docker ps -a --size
du -sh /var/lib/docker
清理前先区分正在使用的镜像、容器和卷。docker system prune -a --volumes 可能删除未使用的卷和镜像,不能把它当作无害的“缓存清理”。
11. systemd、代理和证书的生产配置
11.1 daemon 代理和容器代理不是一回事
daemon 需要访问 registry 时,应给 docker.service 或 daemon 配置代理;容器内应用访问外网则通过容器环境变量/应用代理配置。只给当前 shell 设置 HTTP_PROXY,不一定会传给 systemd 启动的 dockerd。
systemd drop-in 示例:
sudo systemctl edit docker
[Service]
Environment="HTTP_PROXY=http://proxy.example.com:3128"
Environment="HTTPS_PROXY=http://proxy.example.com:3128"
Environment="NO_PROXY=localhost,127.0.0.1,registry.internal.example.com"
sudo systemctl daemon-reload
sudo systemctl restart docker
systemctl show docker --property=Environment
代理 URL 可能包含凭据,systemd 配置和 systemctl show 都可能暴露它。生产优先使用短期凭据、受限代理和严格的文件权限。
11.2 私有 registry CA
使用企业私有 CA 时,应让 Docker 信任正确证书,而不是直接配置 insecure-registries:
/etc/docker/certs.d/registry.example.com:5000/
└── ca.crt
sudo systemctl restart docker
docker login registry.example.com:5000
docker pull registry.example.com:5000/team/api:1.0.0
registry 地址带端口时,证书目录名也要带端口。还要确认系统时间、证书 SAN、代理是否做 TLS 中间人,以及镜像客户端实际连接的 hostname。
11.3 不要裸露远程 TCP API
下面的 daemon 监听会把高权限控制面暴露在 TCP 上,不能直接用于公网:
{
"hosts": ["unix:///var/run/docker.sock", "tcp://0.0.0.0:2375"]
}
未认证的 2375 端口常等价于远程 root。远程管理优先使用 Docker context + SSH:
docker context create server-a --docker host=ssh://ops@server-a
docker --context server-a version
确需 TLS API 时使用双向证书、监听私网地址、防火墙白名单和证书轮换,并确认 systemd ExecStart 与 daemon.json 没有重复定义 hosts。同一个选项同时出现在命令行和 JSON 中会导致 daemon 启动失败。
12. 版本升级与回滚
升级前先记录:
docker version
docker info > docker-info.before.txt
docker ps -a --no-trunc > containers.before.txt
docker image ls --digests > images.before.txt
docker volume ls > volumes.before.txt
升级流程应该包含:
- 查阅 Engine、containerd、runc、Compose 的 release notes 和弃用项。
- 在相同内核、存储驱动和网络配置的测试节点验证。
- 确认关键数据已做应用一致性备份,并实际恢复过。
- 先停或迁移业务流量,检查容器 restart policy 和
live-restore。 - 升级软件包,验证 daemon、网络、volume、日志和健康状态。
- 保留旧版本包、配置和回滚窗口,但不要假设内部 data-root 永远支持任意降级。
Linux 上查看可安装版本并显式选择:
apt-cache madison docker-ce
dnf list --showduplicates docker-ce
生产机不应在没有验证的情况下自动跨大版本升级。镜像构建器和运行节点的版本也应进入资产清单。
13. 安装完成后的深入验收
验收不止 hello-world:
# 镜像和多架构
docker pull alpine:3.20
docker image inspect alpine:3.20 --format '{{.Os}}/{{.Architecture}} {{.Id}}'
# 网络、DNS、出网
docker network create install-check
docker run --rm --network install-check alpine:3.20 \
sh -c 'cat /etc/resolv.conf; wget -qO- https://example.com >/dev/null'
# volume 和权限
docker volume create install-check-data
docker run --rm -v install-check-data:/data alpine:3.20 \
sh -c 'echo ok >/data/check && cat /data/check'
# 资源限制是否映射到 cgroup
docker run --rm --memory 128m --cpus 0.5 alpine:3.20 \
sh -c 'cat /sys/fs/cgroup/memory.max; cat /sys/fs/cgroup/cpu.max'
# 日志驱动和轮转配置
docker info --format '{{.LoggingDriver}} {{.DockerRootDir}} {{.CgroupVersion}}'
# 清理精确目标
docker volume rm install-check-data
docker network rm install-check
如果这些检查中某一项失败,先解决代理、CA、DNS、内核 controller、文件系统或权限问题,再把节点加入生产池。
14. 本篇小结
安装只是第一步,真正可维护的 Docker 环境还需要:明确数据目录、限制日志、规划网络地址池、保护 socket、固定 Compose 版本,并建立验证和故障排查习惯。生产变更前先备份 daemon.json、确认当前容器和 volume,再重启 daemon。
| 上一篇 | 下一篇 |
|---|---|
| 01-基础概念与架构 | 03-镜像容器与常用命令 |