Docker 入门与安装
本篇从零开始。完成后,你将能够:
- 说清楚镜像、容器和仓库分别是什么;
- 在 Windows、macOS 或 Ubuntu 上安装 Docker;
- 运行、查看并删除第一个容器;
- 看懂一条最基本的
docker run命令。
1. Docker 解决什么问题
一套应用通常不只有源代码,还依赖运行时、系统工具、第三方库和配置。直接把应用复制到另一台机器时,经常会遇到“我的电脑上能运行,换台机器就不行”。
Docker 的做法是把应用及其运行依赖制作成一个镜像(image)。其他机器拿到同一个镜像后,可以创建出行为基本一致的容器(container)。
可以先用下面的类比建立直觉:
| Docker 概念 | 类比 | 特点 |
|---|---|---|
| Dockerfile | 制作说明书 | 记录镜像如何构建 |
| 镜像 | 安装包或只读模板 | 可以复制、分发,不能直接修改 |
| 容器 | 按模板启动的应用进程 | 可以启动、停止和删除 |
| 仓库(Registry) | 应用商店 | 用于拉取和推送镜像 |
| 卷(Volume) | 独立数据盘 | 删除容器后仍可保留数据 |
| 网络(Network) | 容器专用局域网 | 让容器互相通信或对外提供服务 |
虚拟机通常包含完整的客户操作系统;容器共享宿主机内核,主要隔离进程、网络和文件系统。因此容器通常启动更快、占用更少,但隔离边界也不同于虚拟机。
2. Docker 是怎样工作的
当你执行 docker run nginx 时,大致发生以下过程:
- Docker CLI 把请求发送给 Docker Engine;
- Engine 检查本地是否有
nginx镜像; - 如果没有,就从 Docker Hub 拉取镜像;
- Engine 基于镜像创建容器,并启动镜像中定义的主进程;
- 主进程退出后,容器进入停止状态。
因此,镜像是模板,容器是模板的一次运行实例。同一个镜像可以同时创建多个彼此隔离的容器。
3. 安装前选择版本
个人电脑建议安装 Docker Desktop,它包含 Docker Engine、Docker CLI 和 Compose:
- Windows 10/11:使用 Docker Desktop,并选择 WSL 2 后端;
- macOS:根据芯片选择 Apple silicon 或 Intel 安装包;
- Linux 桌面:可以使用 Docker Desktop,也可以只安装 Docker Engine;
- Linux 服务器:通常只安装 Docker Engine 和 Compose 插件。
安装包以 Docker 官方安装文档 为准。不要从来源不明的网站下载安装包或一键脚本。
3.1 Windows 安装
- 在“启用或关闭 Windows 功能”中启用 WSL 相关功能,或在管理员 PowerShell 中安装 WSL;
- 安装 Docker Desktop;
- 在 Docker Desktop 设置中确认启用了 Use the WSL 2 based engine;
- 等待界面显示 Docker Engine 正在运行;
- 打开新的 PowerShell 或 Windows Terminal 验证。
# 安装或更新 WSL;执行后如有提示,请重启 Windows
wsl --install
# 查看已安装发行版及其 WSL 版本,VERSION 应为 2
wsl --list --verbose
# 验证 Docker 客户端和服务端是否可以通信
docker version
# 验证 Compose V2 是否可用
docker compose version
本系列的 Linux 风格命令可以在 WSL 终端中执行。PowerShell 对引号、环境变量和路径的处理略有不同,遇到差异时优先使用 WSL。
3.2 macOS 安装
下载并安装 Docker Desktop,启动后等待菜单栏中的 Docker 状态变为运行中,再打开“终端”执行:
# 同时显示 Docker CLI 和 Engine 的版本信息
docker version
# Compose V2 已集成在 docker 命令中,中间有一个空格
docker compose version
3.3 Ubuntu 安装 Docker Engine
下面以 Ubuntu 为例,通过 Docker 官方 APT 仓库安装。每组命令都可以直接复制执行。
# 删除可能冲突的旧包;未安装时不会造成问题
for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do
sudo apt-get remove -y "$pkg"
done
# 更新软件索引并安装添加仓库所需工具
sudo apt-get update
sudo apt-get install -y ca-certificates curl
# 创建 APT 密钥目录
sudo install -m 0755 -d /etc/apt/keyrings
# 下载 Docker 官方仓库签名密钥
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
添加与你的 Ubuntu 版本对应的软件仓库:
# 写入 Docker 官方 APT 仓库;命令会自动读取 CPU 架构和系统代号
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
# 安装 Engine、CLI、containerd、Buildx 和 Compose 插件
sudo apt-get update
sudo apt-get install -y \
docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
启动服务并验证:
# 立即启动 Docker,并设置为开机自动启动
sudo systemctl enable --now docker
# 确认服务状态;看到 active (running) 表示正常
sudo systemctl status docker --no-pager
# 首次验证可使用 sudo,避免用户权限尚未配置
sudo docker version
sudo docker run --rm hello-world
如果希望当前用户不加 sudo 也能运行 Docker:
# 创建 docker 组(已存在时忽略错误),再把当前用户加入该组
sudo groupadd docker 2>/dev/null || true
sudo usermod -aG docker "$USER"
# 让当前终端临时加载新组;重新登录也能永久生效
newgrp docker
# 确认现在可以不使用 sudo
docker run --rm hello-world
docker 组成员可以挂载宿主机目录或启动高权限容器,实际接近宿主机 root 权限。只把可信用户加入该组。共享服务器应评估 rootless Docker 或受限的 sudo 规则。
其他 Linux 发行版的软件包命令不同,请使用官方文档中对应发行版的安装步骤,不要直接套用 Ubuntu 命令。
4. 运行第一个 Web 容器
现在启动一个 Nginx Web 服务器:
# 后台运行 nginx,并把宿主机 8080 端口映射到容器 80 端口
docker run --detach \
--name beginner-web \
--publish 8080:80 \
nginx:1.27-alpine
第一次运行会看到若干 Pull complete,表示 Docker 正在下载镜像。最后输出的一长串字符是容器 ID。
打开浏览器访问 http://localhost:8080,应该看到 Nginx 欢迎页。没有图形界面的 Linux 服务器可执行:
# 请求本机 8080 端口;响应中应包含 Welcome to nginx
curl http://127.0.0.1:8080
查看正在运行的容器:
# 只显示当前正在运行的容器
docker ps
# 查看 beginner-web 最近 20 行日志
docker logs --tail 20 beginner-web
docker ps 中几个重要字段的含义:
| 字段 | 含义 |
|---|---|
CONTAINER ID | 容器短 ID,可代替名称用于命令参数 |
IMAGE | 创建容器所使用的镜像 |
STATUS | 容器运行状态和持续时间 |
PORTS | 宿主机端口到容器端口的映射 |
NAMES | 容器名称,本例为 beginner-web |
完成实验后停止并删除容器:
# 先停止容器的主进程
docker stop beginner-web
# 删除已停止的容器;镜像仍保留在本地
docker rm beginner-web
# 确认容器已经不存在;-a 会同时显示停止的容器
docker ps -a
5. 看懂 docker run
刚才的命令可以拆成以下部分:
| 参数 | 含义 |
|---|---|
docker run | 根据镜像创建并启动一个新容器 |
--detach / -d | 在后台运行 |
--name beginner-web | 为容器指定容易记忆的名称 |
--publish 8080:80 / -p 8080:80 | 将宿主机 8080 端口转发到容器 80 端口 |
nginx:1.27-alpine | 镜像名和标签;标签通常表示版本或变体 |
注意,docker run 每执行一次都会创建一个新容器。重新启动已有容器使用 docker start,而不是再次执行同样的 docker run。
6. 最小日常检查
# 查看客户端和服务端版本;只有 Client 往往说明 Engine 未运行
docker version
# 查看存储驱动、CPU、内存、镜像数量等系统信息
docker info
# 查看镜像、容器、卷和构建缓存分别占用多少空间
docker system df
# 查看本地已有镜像
docker image ls
常见安装问题
| 现象 | 原因和处理 |
|---|---|
Cannot connect to the Docker daemon | Engine 未启动;启动 Docker Desktop,或在 Linux 执行 sudo systemctl start docker |
permission denied ... docker.sock | 当前用户无权限;暂时使用 sudo,或重新登录使 docker 组生效 |
port is already allocated | 8080 已被占用;换成 -p 8081:80 |
| 拉取镜像超时 | 检查 DNS、代理和网络策略;不要随意关闭 TLS 校验 |
| Apple silicon 出现平台警告 | 镜像不包含 arm64 版本;优先更换多架构镜像 |
7. 本篇练习
- 把示例中的宿主机端口从
8080改成8081,确认新地址可以访问; - 分别执行
docker ps和docker ps -a,观察停止容器是否显示; - 删除容器后执行
docker image ls,确认镜像为什么仍然存在; - 用
docker run --help查找--rm参数的作用。
下一篇将使用 Dockerfile 制作自己的第一个镜像,并解释镜像标签、构建上下文和缓存。