現在安裝 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 的工作方式,則更適合作為另一篇文章單獨介紹。