Docker 初学者指南:实用入门教程
· 12分钟阅读
📑 目录
Docker 通过解决臭名昭著的"在我的机器上可以运行"问题,彻底改变了软件开发。Docker 不是直接在你的系统上安装依赖项并处理版本冲突,而是将应用程序需要的所有内容打包到隔离的容器中,这些容器在任何地方都以相同的方式运行——从你的笔记本电脑到生产服务器。
如果你在 2026 年还没有学习 Docker,现在是时候了。它已成为应用程序部署的事实标准,被全球超过 1300 万开发者使用,并集成到几乎每个现代开发工作流程中。
什么是 Docker,为什么你应该关心?
Docker 是一个容器化平台,它将你的应用程序及其所有依赖项打包到一个称为容器的标准化单元中。可以把它想象成一个轻量级、可移植的包,其中包含运行软件所需的一切:代码、运行时、系统工具、库和设置。
在 Docker 之前,开发者面临持续的环境不一致问题。你的 Node.js 应用可能在运行 Node 18 的 MacBook 上完美运行,但在运行 Node 16 的同事的 Windows 机器上崩溃。或者更糟的是,它在开发环境中运行良好,但在生产环境中神秘地失败,因为系统库存在细微差异。
Docker 通过创建一致、可重现的环境来消除这些麻烦。当你容器化一个应用程序时,你就保证了它无论在哪里运行都会以相同的方式运行。
使用 Docker 的主要优势
- 跨环境的一致性: 开发、预发布和生产环境都运行相同的容器
- 更快的入职: 新团队成员可以在几分钟内开始贡献,而不是花费数天时间设置环境
- 隔离: 在同一台机器上运行具有冲突依赖项的多个项目而不会相互干扰
- 高效的资源使用: 容器共享主机操作系统内核,使它们比虚拟机轻得多
- 简化部署: 将整个应用程序堆栈作为单个工件交付
- 微服务架构: 将单体应用程序分解为可管理的、可独立部署的服务
专业提示: Docker 不仅用于生产部署。许多开发者使用它在本地运行数据库、缓存层和其他服务,而不会用安装程序弄乱他们的系统。一个项目需要 PostgreSQL,另一个项目需要 MySQL?在容器中运行两者而不会冲突。
核心概念:镜像、容器和 Dockerfile
在深入了解 Docker 命令和工作流程之前,理解三个核心概念至关重要。
Docker 镜像
镜像是一个只读模板,包含运行应用程序所需的一切。可以把它想象成面向对象编程中的类——它是一个蓝图,而不是一个运行实例。
镜像以层的形式构建,每一层代表一个更改或指令。这种分层架构实现了高效的存储和传输,因为 Docker 只需要下载或存储已更改的层。
你可以从 Docker Hub(官方注册表)拉取预构建的镜像,或构建自己的自定义镜像。流行的基础镜像包括 node、python、nginx、postgres 和 redis。
Docker 容器
容器是镜像的运行实例——就像从类实例化的对象。一个镜像可以生成多个容器,每个容器都独立运行,拥有自己隔离的文件系统、网络和进程空间。
容器在设计上是短暂的。当你停止并删除一个容器时,写入其中的任何数据都会消失,除非你使用卷明确配置了持久存储(稍后会详细介绍)。
Dockerfile
Dockerfile 是一个包含构建 Docker 镜像指令的文本文件。它本质上是一个配方,告诉 Docker 如何逐步组装你的应用程序环境。
Dockerfile 中的每条指令都会在镜像中创建一个新层。Docker 智能地缓存这些层,因此重建镜像只会处理已更改的层——使后续构建极快。
这是一个 Node.js 应用程序的最小 Dockerfile:
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
让我们分解每条指令的作用:
FROM指定基础镜像(Alpine Linux 上的 Node.js 20,一个最小发行版)WORKDIR设置容器内的工作目录COPY将文件从主机传输到容器中RUN在构建过程中执行命令(安装依赖项)EXPOSE记录应用程序监听的端口CMD定义启动容器时运行的默认命令
在你的系统上安装 Docker
Docker 的安装因操作系统而略有不同,但在所有主要平台上过程都很简单。
macOS 和 Windows
从官方网站下载并安装 Docker Desktop。Docker Desktop 包含你需要的一切:Docker 引擎、Docker CLI、Docker Compose 和一个用于管理容器的用户友好 GUI。
安装后,Docker Desktop 在后台运行,并添加一个菜单栏图标(macOS)或系统托盘图标(Windows),用于快速访问设置和运行中的容器。
Linux
在 Linux 上,使用你的发行版的包管理器直接安装 Docker Engine。对于 Ubuntu/Debian:
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER
注销并重新登录以使组成员资格生效,允许你在不使用 sudo 的情况下运行 Docker 命令。
验证安装
通过运行以下命令确认 Docker 正常工作:
docker --version
docker run hello-world
第二个命令拉取一个小型测试镜像并在容器中运行它。如果你看到欢迎消息,则 Docker 已安装并正常运行。
每个开发者都需要的基本 Docker 命令
掌握少数核心命令将涵盖你 90% 的日常 Docker 使用。这是一个全面的参考表:
| 命令 | 作用 | 常用选项 |
|---|---|---|
docker build -t myapp . |
从当前目录中的 Dockerfile 构建镜像 | -t 用名称标记镜像 |
docker run myapp |
从镜像创建并启动容器 | -d(分离模式)、-p(端口映射)、--name |
docker ps |
列出运行中的容器 | -a 显示所有容器(包括已停止的) |
docker stop [id] |
优雅地停止运行中的容器 | 使用容器 ID 或名称 |
docker rm [id] |
删除已停止的容器 | -f 强制删除运行中的容器 |
docker images |
列出系统上的所有镜像 | -a 显示中间镜像 |
docker rmi [image] |
删除镜像 | -f 强制删除 |
docker logs [id] |
查看容器输出和日志 | -f 实时跟踪日志输出 |
docker exec -it [id] sh |
在运行中的容器内打开交互式 shell | -it 启用交互式终端 |
docker pull [image] |
从注册表下载镜像 | 指定标签,如 nginx:1.25 |
docker compose up |
启动 docker-compose.yml 中定义的所有服务 | -d 在后台运行 |
docker compose down |
停止并删除 compose 文件中的所有容器 | -v 也删除卷 |
实用命令示例
使用端口映射和环境变量运行容器:
docker run -d \
--name my-postgres \
-p 5432:5432 \
-e POSTGRES_PASSWORD=secret \
postgres:16
这会在后台启动 PostgreSQL,将端口 5432 映射到你的主机,并设置数据库密码。
从容器查看实时日志:
docker logs -f my-postgres
在运行中的容器内执行命令:
docker exec -it my-postgres psql -U postgres
这会在容器内打开一个交互式 PostgreSQL shell。
快速提示: 你不需要输入完整的容器 ID。Docker 接受唯一前缀,所以如果你的容器 ID 是 a3f8b2c1d4e5,你可以使用 docker stop a3f,只要没有其他容器 ID 以这些字符开头。
编写你的第一个 Dockerfile
让我们为一个真实的 Node.js 应用程序构建一个完整的 Dockerfile,并逐步解释每个决策。
# 在 Alpine Linux 上使用特定版本的 Node.js(更小的镜像大小)
FROM node:20-alpine
# 如果需要,安装系统依赖项
RUN apk add --no-cache python3 make g++
# 设置工作目录
WORKDIR /app
# 首先复制包文件(以获得更好的层缓存)
COPY package*.json ./
# 仅安装生产依赖项
RUN npm ci --production --silent
# 复制应用程序源代码
COPY . .
# 为安全创建非 root 用户
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001 && \
chown -R nodejs:nodejs /app
# 切换到非 root 用户
USER nodejs
# 暴露应用程序端口
EXPOSE 3000
# 健康检查以监控容器状态
HEALTHCHECK --interval=30s --timeout=3s \
CMD node healthcheck.js || exit 1
# 启动应用程序
CMD ["node", "server.js"]
Dockerfile 最佳实践
顺序对缓存效率很重要。将频繁更改的指令(如 COPY . .)放在 Dockerfile 的末尾。这样,当只有源代码更改时,Docker 可以重用依赖项安装的缓存层。
使用 .dockerignore 文件从构建上下文中排除不必要的文件:
node_modules
npm-debug.log
.git
.env
*.md
.DS_Store
这通过防止 Docker 复制容器中不需要的文件来加快构建速度并减小镜像大小。
多阶段构建
对于编译语言或需要构建工具的应用程序,使用多阶段构建来保持最终镜像较小:
# 构建阶段
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# 生产阶段
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY --from=builder /app/dist ./dist
USER node
CMD ["node", "dist/server.js"]
最终镜像仅包含生产依赖项和编译后的工件,不包含构建工具或源代码。
用于多容器应用的 Docker Compose
真实世界的应用程序很少由单个服务组成。你通常需要一个 Web 应用程序、数据库、缓存、消息队列和其他支持服务。Docker Compose 允许你使用单个 YAML 配置文件定义和管理多容器应用程序。
这是一个典型 Web 应用程序堆栈的完整 docker-compose.yml:
version: '3.8'
services:
web:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://postgres:secret@db:5432/myapp
- REDIS_URL=redis://redis:6379
depends_on:
- db
- redis
volumes:
- ./logs:/app/logs
restart: unless-stopped
db:
image: postgres:16-alpine
environment:
- POSTGRES_DB=myapp
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=secret
volumes:
- pgdata:/var/lib/postgresql/data
ports:
- "5432:5432"
restart: unless-stopped
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redisdata:/data
restart: unless-stopped
nginx:
image: nginx:1.25-alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- web
restart: unless-stopped
volumes:
pgdata:
redisdata:
使用 Docker Compose
在后台启动所有服务:
dock