Docker 与容器解析:面向初学者的 Docker 工作原理指南
Source: Dev.to
现代软件开发已经不再仅仅是编写代码。它还涉及 在任何地方可靠地运行这些代码——无论是在你的笔记本电脑、测试环境还是生产环境。这就是容器化和 Docker 的用武之地。
在本篇博客中,我们将分解说明:
- 什么是容器
- 为什么会创建 Docker
- Docker 的内部工作原理
……以一种即使你完全是新手也能轻松理解的方式。
为什么我们需要容器
在容器出现之前,应用程序通常直接部署在服务器或虚拟机上。这导致了若干问题:
| 问题 | 描述 |
|---|---|
| 环境漂移 | 不同环境(开发、测试、生产)表现不一致 |
| 依赖冲突 | 应用程序在库、运行时等方面产生冲突 |
| 部署和回滚困难 | 手动步骤多,发布窗口长,存在停机时间 |
| 可扩展性差 | 增加容量意味着克隆整个服务器/虚拟机 |
开发者需要一种方法来将应用程序及其运行所需的所有内容打包,并在任何地方以相同方式运行它。
什么是容器
容器是一个 轻量级、可移植的单元,它打包了:
- 应用代码
- 运行时(Node、Python、Java 等)
- 库和依赖
- 配置
容器 共享宿主操作系统内核,但在隔离的用户空间中运行,使其快速且高效。
集装箱类比
- 船只并不关心内部的内容。
- 集装箱可以在船只、卡车或港口之间移动。
- 内部的一切保持不变。
虚拟机 vs. 容器
| 特性 | 虚拟机 | 容器 |
|---|---|---|
| 操作系统 | 每个虚拟机都有完整的客体操作系统 | 共享宿主操作系统内核 |
| 启动时间 | 几分钟 | 秒甚至毫秒 |
| 资源使用 | 较高 | 轻量级 |
| 隔离 | 强 | 进程级别隔离 |
| 可移植性 | 有限 | 非常高 |
类比:
虚拟机就像为每位客人租一整栋房子。
容器就像在同一栋楼里租房间。
容器化之前的痛点
- 依赖地狱 – 一个应用需要 Node 16,另一个需要 Node 18 → 升级其中一个会导致另一个坏掉。
- “在我的笔记本上能跑”综合症 – 在开发者的笔记本上可以运行,QA 环境失败,生产环境因操作系统版本、库、配置或运行时不同而崩溃。
- 扩展痛点 – 为了处理更多流量,你需要克隆服务器/虚拟机,重新配置所有内容,然后等待。
- 手动部署 – 发布窗口长,回滚容易出错,频繁出现停机。
容器能解决什么
- 相同的容器可以在任何地方运行 – 再也没有环境漂移。
- 通过运行更多容器来扩展 – 快速、低成本且自动化。
- 通过切换容器版本实现回滚 – 简单且可靠。
进入 Docker
Docker 是一个帮助你:
- 打包你的应用 – 包含运行所需的一切。
- 在任何机器上以相同方式运行 – “构建一次我的应用,随处运行。”
与手动设置环境不同,Docker 使用容器来实现自动化。
Docker 之前
- 容器已经存在,但难以使用。
- 每家公司都有自己的定制工具。
- 开发者在环境搭建和一致性方面苦苦挣扎。
Docker 的答案
- 标准化格式 –
Dockerfile与镜像。 - 简洁命令 –
docker build、docker run。 - 轻松共享镜像 – 注册表(Docker Hub、GHCR、私有注册表)。
Docker 直接解决了我们讨论的问题:
| 问题 | Docker 解决方案 |
|---|---|
| 依赖冲突 | 每个应用都有自己的容器 |
| 环境不匹配 | 同一镜像在任何地方都能运行 |
| 部署缓慢 | 几秒钟内启动容器 |
| 回滚困难 | 轻松切换镜像版本 |
Docker 并没有消除复杂性——它 把复杂性整齐地打包。
Docker 在现代工作流中的定位
- 本地开发 – 所有开发者使用相同的设置。
- CI/CD 流水线 – 可预测的构建和测试。
- 微服务 – 每个服务在自己的容器中运行。
- 云端与 Kubernetes – Docker 镜像是标准单元。
Docker 通常是 迈向 的第一步:
- Kubernetes
- DevOps
- 云原生架构
Source: …
Docker 构建模块
| Component | 功能说明 |
|---|---|
| Docker Client | 你在终端输入的命令(docker build、docker run)或 GUI 调用的操作。向守护进程发送请求。 |
Docker Daemon (dockerd) | 在后台运行的服务,真正负责构建镜像和运行容器。 |
containerd & runc | 守护进程使用的底层工具,用于把镜像转化为运行中的进程。你不必记住它们的细节——只需了解 Docker 将实际的进程创建委托给这些专用工具。 |
| Image | 冻结的快照(只读),类似配方或蓝图。 |
| Container | 镜像的运行实例。会在只读层之上添加一个薄的可写层,使应用在运行时能够修改文件。 |
| Dockerfile | 包含构建镜像指令的简单文本文件(基镜像、要复制的文件、要执行的命令)。docker build 读取它并创建镜像。 |
| Registry | 存放镜像的仓库(Docker Hub、GitHub Container Registry、私有仓库等)。实现从任意位置 docker push 与 docker pull。 |
Docker 依赖的内核特性
- Namespaces – 为容器提供独立的进程、网络、文件系统等视图。可以把命名空间想象成一个私人房间:看不到其他房间的内容。
- cgroups(control groups) – 限制容器可以使用的 CPU、内存或磁盘等资源。可以把 cgroup 看作房间的电力限制器。
它们共同让容器表现得像 不需要完整操作系统开销的隔离环境。
镜像层
每个 Dockerfile 步骤都会生成一个 层。如果层的内容没有变化,这些层会被 缓存,因此合理安排 Dockerfile 的顺序可以加快构建速度。
网络
Docker 为每个容器分配网络接口,并允许你映射主机端口(-p host:container),从而使服务可被访问。
数据卷
对于需要在容器重启后仍然保留的数据,请使用 卷。卷将数据保存在容器临时可写层之外。
示例 Dockerfile
# Use an official Node runtime as a parent image
FROM node:18-alpine
# Set working directory inside the container
WORKDIR /app
# Copy package.json and package-lock.json first (for caching)
COPY package*.json ./
# Install app dependencies
RUN npm ci --only=production
# Copy the rest of the application source code
COPY . .
# Expose the port the app runs on
EXPOSE 3000
# Define the command to run the app
CMD ["node", "index.js"]
构建镜像:
docker build -t my-node-app:1.0 .
运行容器:
docker run -d -p 8080:3000 --name my-app my-node-app:1.0
TL;DR
Docker 是一个 小型系统,帮助你打包应用并在任何地方以相同方式运行。通过理解上述概念——容器、镜像、Dockerfile、仓库以及底层内核特性——你就可以在工作流中采用 Docker,并顺利迈向现代云原生架构。
运行容器化的 Node.js 应用
在本节中,你将通过复制粘贴命令实际运行一个容器化的应用。无需任何 Docker 经验。我们将容器化一个非常简单的 Node.js Web 服务器。
前置条件
- 已安装 Docker(
docker --version能正常运行) - 任意操作系统(Windows / macOS / Linux)
1. 创建项目文件夹
mkdir simple-docker-app
cd simple-docker-app
2. 创建应用源码
index.js
const http = require('http');
const PORT = 3000;
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello from Docker Container!');
});
server.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
package.json
{
"name": "simple-docker-app",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"start": "node index.js"
}
}
3. 编写 Dockerfile
创建一个名为 Dockerfile(无扩展名)的文件,内容如下:
# Use an official Node.js runtime
FROM node:18
# Set working directory inside container
WORKDIR /app
# Copy package files first (for caching)
COPY package*.json ./
# Install dependencies
RUN npm install
# Copy application source code
COPY . .
# Expose application port
EXPOSE 3000
# Start the application
CMD ["npm", "start"]
4. 构建 Docker 镜像
在 与 Dockerfile 同一文件夹 中运行以下命令:
docker build -t simple-web-app .
这会创建一个名为
simple-web-app的 Docker 镜像。
5. 运行容器
docker run -p 3000:3000 simple-web-app
- 容器内部的 3000 端口被映射到主机的 3000 端口。
6. 验证应用
打开浏览器并访问:
http://localhost:3000
你应该会看到:
Hello from Docker Container!
这到底发生了什么?
- Docker 将你的应用 + Node.js + 配置打包成一个 镜像。
- 从该镜像创建了一个 容器。
- 容器内部的 3000 端口映射到了你的机器。
- 应用在任何地方都以相同的方式运行。
为什么这很重要
- 任何开发者的笔记本 都能运行该应用。
- 可以在 CI/CD 流水线 中使用。
- 在 云服务器 上无需额外配置即可运行。
Docker 不仅是一个工具——它是软件构建和交付方式的根本转变。
容器的优势
- 消除环境差异。
- 简化部署。
- 自信地实现扩展。
如果你已经了解
- 什么是容器。
- 为什么会有 Docker。
- Docker 的内部工作原理。
…那么你已经可以在真实项目中使用 Docker 了!