现在安装 Docker 本身已经不是一件困难的事情。无论是查阅官方说明文档,还是直接让 AI 根据当前 Linux 环境生成安装命令,都可以很快完成部署。
真正值得理解的,是 Docker 从什么软件源安装,不同发行版之间有什么区别,以及 Docker 安装完成以后,镜像应该从哪里获取和分发。
Linux 上安装 Docker 的流程其实非常统一。Ubuntu 和 Debian 使用 APT,RHEL 和 Rocky Linux 使用 DNF,但最终安装的都是同一组 Docker Engine、CLI、containerd、Buildx 和 Compose 组件。
flowchart TD
A[Linux]
A --> B[Debian / Ubuntu]
A --> C[RHEL / Rocky Linux]
B --> D[APT Repository]
C --> E[DNF Repository]
D --> F[Docker Packages]
E --> F
F --> G[Docker Engine]
F --> H[Docker CLI]
F --> I[containerd]
F --> J[Buildx]
F --> K[Docker Compose]
本文按照这个共同流程介绍 Docker 的安装,而不是为不同发行版重复写几套几乎相同的教程。
1. Docker 安装了什么
我们平时说”安装 Docker”,实际上会安装多个组件:
docker-ce
docker-ce-cli
containerd.io
docker-buildx-plugin
docker-compose-plugin
其中,docker-ce 提供 Docker Engine,也就是长期运行在后台的 dockerd。docker-ce-cli 提供平时使用的 docker 命令,CLI 通过 Docker API 与 daemon 通信。containerd 负责更底层的 container 生命周期管理,Buildx 提供现代 image 构建能力,而 Compose plugin 用于管理多个 container 组成的服务。
它们之间可以简单理解为:
flowchart LR
A[Docker CLI]
B[Docker Engine]
C[containerd]
D[Container]
A -->|Docker API| B
B --> C
C --> D
现在 Docker Compose 已经作为 Docker CLI plugin 安装,因此应该使用 docker compose,而不是旧教程中常见的 docker-compose,也不再需要通过 pip install docker-compose 安装 Compose。
如果机器以前安装过系统仓库中的 Docker、旧版本 Docker 或其他兼容实现,可以先根据实际情况清理冲突软件包。但如果机器上已经存在正在使用的 Podman workload,不应该为了安装 Docker 而无脑删除 Podman。
2. 配置 Docker 软件源
不同 Linux 发行版安装 Docker 时,最大的差异其实就是 package manager 和 repository。
flowchart TD
A[Docker Repository]
A --> B[Debian]
A --> C[Ubuntu]
A --> D[RHEL]
A --> E[Rocky Linux]
B --> B1[linux/debian]
C --> C1[linux/ubuntu]
D --> D1[linux/rhel]
E --> E1[本文使用 linux/centos]
B1 --> F[APT]
C1 --> F
D1 --> G[DNF]
E1 --> G
Debian 和 Ubuntu 使用 APT。首先安装基础工具并创建 keyring:
sudo apt update
sudo apt install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
可以从 /etc/os-release 获取当前发行版:
. /etc/os-release
DISTRO="$ID"
CODENAME="${UBUNTU_CODENAME:-$VERSION_CODENAME}"
对于本文覆盖的系统:
Ubuntu -> DISTRO=ubuntu
Debian -> DISTRO=debian
下载对应的 Docker GPG key:
sudo curl -fsSL \
"https://download.docker.com/linux/${DISTRO}/gpg" \
-o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
然后创建 Docker APT source:
sudo tee /etc/apt/sources.list.d/docker.sources > /dev/null <<EOF
Types: deb
URIs: https://download.docker.com/linux/${DISTRO}
Suites: ${CODENAME}
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
最后更新 package index:
sudo apt update
RHEL 和 Rocky Linux 使用 DNF。首先安装 repository 管理工具:
sudo dnf install -y dnf-plugins-core
RHEL 可以直接使用 Docker 提供的 RHEL repository:
sudo dnf config-manager --add-repo \
https://download.docker.com/linux/rhel/docker-ce.repo
Rocky Linux 需要特别注意。
不要根据发行版名称自行构造:
https://download.docker.com/linux/rocky/
Docker 并没有提供这样的独立 repository。
本文在 Rocky Linux 上使用 Docker 的 CentOS repository:
sudo dnf config-manager --add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
Rocky Linux、RHEL 和 CentOS 都属于 Enterprise Linux 生态,对应的软件包通常可以看到:
.el9
.el10
例如 Rocky Linux 9 使用 EL9 软件包,Rocky Linux 10 使用 EL10 软件包。
配置完成以后,可以检查 repository 是否正常:
dnf repolist | grep docker
dnf list docker-ce --showduplicates
如果以前错误配置过:
download.docker.com/linux/rocky/
可以先删除对应的 /etc/yum.repos.d/docker-ce.repo,再重新配置。
3. 安装与基础配置
repository 配置完成以后,不同发行版之间已经几乎没有区别。
Debian 和 Ubuntu 使用:
sudo apt install -y \
docker-ce \
docker-ce-cli \
containerd.io \
docker-buildx-plugin \
docker-compose-plugin
RHEL 和 Rocky Linux 使用:
sudo dnf install -y \
docker-ce \
docker-ce-cli \
containerd.io \
docker-buildx-plugin \
docker-compose-plugin
安装完成以后启动 Docker:
sudo systemctl enable --now docker
检查版本:
docker --version
docker compose version
然后运行测试 container:
sudo docker run --rm hello-world
这条命令已经完成了一次最简单的 Docker 工作流:
flowchart LR
A[Docker Client]
B[Docker Engine]
C[Docker Registry]
D[Image]
E[Container]
A -->|docker run| B
B -->|本地没有 Image 时 pull| C
C --> D
D --> B
B -->|Create + Start| E
Docker daemon 默认需要 root 权限。如果希望普通用户直接运行 docker:
sudo usermod -aG docker "$USER"
重新登录 Shell 后即可:
docker ps
需要注意,能够访问 Docker daemon 的用户实际上拥有非常高的系统权限,因此不要随意把不可信用户加入 docker group。
Docker daemon 的主要配置文件是:
/etc/docker/daemon.json
默认数据目录是:
/var/lib/docker
如果系统盘比较小,或者机器有单独的数据盘,可以修改:
{
"data-root": "/data/docker"
}
然后:
sudo systemctl restart docker
如果默认磁盘空间足够,则没有必要为了”优化”而修改 Docker 数据目录。
4. Docker Registry 与镜像分发
Docker 安装完成以后,下一个经常遇到的问题就是:
Docker image 从哪里来?
例如:
docker pull nginx
实际上是在从 Registry 下载 image。
一个完整的 image reference 可以写成:
registry.example.com/project/nginx:1.0
其中包含 Registry、repository 和 tag。
flowchart LR
A[registry.example.com]
B[project/nginx]
C[1.0]
A -->|Registry| B
B -->|Repository| C
Docker Hub 本身就是一个公共 Registry。
如果只有一台服务器,直接使用公共 Registry 一般已经足够。但如果有多台服务器、CI/CD、内网环境或者公共 Registry 访问不稳定,就可以自己部署 Registry。
flowchart LR
A[Developer / CI]
B[Private Registry]
C[Server A]
D[Server B]
E[Server C]
A -->|docker push| B
B -->|docker pull| C
B -->|docker pull| D
B -->|docker pull| E
最简单的测试方式是:
docker run -d \
--name registry \
--restart always \
-p 5000:5000 \
registry:3
然后可以测试 push:
docker pull nginx:latest
docker tag nginx:latest \
localhost:5000/nginx:latest
docker push \
localhost:5000/nginx:latest
这里的 docker tag 并不是重新复制 image,而是给现有 image 增加一个新的 reference。reference 中的 Registry hostname 决定 docker push 应该把 image 上传到哪里。
长期运行时,应该把 Registry 数据持久化:
services:
registry:
image: registry:3
container_name: registry
restart: unless-stopped
ports:
- "127.0.0.1:5000:5000"
volumes:
- /data/registry:/var/lib/registry
然后:
docker compose up -d
这里故意只监听:
127.0.0.1:5000
因为一个没有 TLS 和认证的 Registry 不应该直接暴露到公网。
如果只是偶尔向另一台机器传一个 image,也没有必要一定部署 Registry。可以直接:
docker save -o nginx.tar nginx:latest
rsync -avP nginx.tar server:/tmp/
docker load -i /tmp/nginx.tar
两种方式的区别可以简单理解为:
flowchart TD
A[需要传输 Docker Image]
A --> B{是否长期、多机器使用?}
B -->|否| C[docker save / load]
B -->|是| D[Private Registry]
5. 使用 Nginx 为 Registry 提供 HTTPS
如果 Registry 需要被其他服务器长期访问,应该使用 HTTPS,并且配置访问控制。
一种比较容易维护的结构是:
flowchart TD
A[Docker Client]
B["Nginx<br/>registry.example.com:443"]
C["Docker Registry<br/>127.0.0.1:5000"]
D["/data/registry"]
A -->|HTTPS| B
B -->|HTTP| C
C -->|Persistent Data| D
Registry 本身只监听本机:
127.0.0.1:5000
域名、TLS certificate 和公网入口全部交给 Nginx。
例如:
server {
listen 443 ssl;
server_name registry.example.com;
ssl_certificate \
/etc/letsencrypt/live/registry.example.com/fullchain.pem;
ssl_certificate_key \
/etc/letsencrypt/live/registry.example.com/privkey.pem;
client_max_body_size 0;
location / {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 900;
proxy_request_buffering off;
}
}
client_max_body_size 0 可以避免 Docker image layer 因普通 Web 上传限制而失败。
如果 Nginx 本身也运行在 Docker 中,则不能再使用:
proxy_pass http://127.0.0.1:5000;
因为 container 内部的 127.0.0.1 指向 Nginx container 自己。
这时应该让 Nginx 和 Registry 位于同一个 Docker network,并通过 service name 访问:
proxy_pass http://registry:5000;
结构变成:
flowchart TD
A[Docker Client]
subgraph Docker Network
B[Nginx Container]
C["Registry Container<br/>registry:5000"]
end
D["/data/registry"]
A -->|HTTPS| B
B -->|HTTP| C
C --> D
只有 HTTPS 还不够。如果 Registry 可以从公网访问,还应该配置认证。
可以在 Nginx 上增加 Basic Authentication:
location / {
auth_basic "Docker Registry";
auth_basic_user_file /etc/nginx/registry.htpasswd;
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 900;
proxy_request_buffering off;
}
Docker client 登录:
docker login registry.example.com
之后就可以:
docker tag nginx:latest \
registry.example.com/nginx:latest
docker push \
registry.example.com/nginx:latest
其他服务器:
docker login registry.example.com
docker pull \
registry.example.com/nginx:latest
对于公网 Registry,不建议为了方便使用 HTTP insecure-registry。正常跨机器使用应该优先配置 HTTPS。
6. 总结
Linux 上安装 Docker,本质上并不存在几套完全不同的流程。
Ubuntu 和 Debian 使用 APT,RHEL 和 Rocky Linux 使用 DNF,真正有差异的主要是 repository 和 package manager:
flowchart TD
A[配置 Docker Repository]
A --> B[APT<br/>Debian / Ubuntu]
A --> C[DNF<br/>RHEL / Rocky Linux]
B --> D[安装 Docker Packages]
C --> D
D --> E[启动 Docker Engine]
E --> F[配置用户权限]
F --> G{如何获取和分发 Image?}
G -->|单机| H[Public Registry]
G -->|偶尔离线传输| I[docker save / load]
G -->|长期、多服务器| J[Private Registry]
Debian 和 Ubuntu 可以直接使用各自对应的 Docker APT repository。RHEL 可以使用 Docker 的 RHEL repository。Rocky Linux 没有独立的 linux/rocky Docker repository,本文使用 CentOS Docker repository 作为兼容性安装方案。
Docker 安装完成以后,如果只是单机运行应用,公共 Registry 通常已经足够;如果只是偶尔离线传输 image,docker save/load 更简单;如果存在 CI/CD、多服务器部署或者长期的镜像分发需求,则可以部署自己的 Registry,并通过 Nginx 提供 HTTPS 和认证。
到这里解决的是 Docker 基础设施层面的问题:
如何安装 Docker,以及 Docker image 如何获取、存储和分发。
至于 image、container、volume、bind mount、network、端口映射和 Docker Compose 的工作方式,则更适合作为另一篇文章单独介绍。