1. Docker 解决了什么问题?
在软件开发过程中,经常会遇到这样的问题:
"我的电脑上可以运行,为什么你的电脑运行不了?"
比如一个 Vue2 项目:
你的电脑:
Node.js 14
npm 6
Vue2
webpack 4
项目运行正常:
arduino
npm run dev
打开:
makefile
localhost:8080
可以看到页面。
但是同事拉取代码后运行:
arduino
npm install
npm run dev
却报错:
go
Node version mismatch
webpack dependency error
npm install failed
为什么?
因为代码虽然一样,但是运行代码的环境不一样。
2. 一个应用不仅仅是代码
很多初学者会认为:
项目 = 源代码
例如:
css
my-project
├── src
├── package.json
└── README.md
实际上,一个项目真正运行起来,需要很多额外条件:
diff
应用
+
运行环境
+
依赖
+
配置
例如一个 Node 项目:
Node项目
├── 源代码
│
├── Node.js
│
├── npm
│
├── 第三方依赖
│
└── 环境变量
代码只是其中一部分。
如果缺少运行环境,代码无法工作。
3. 传统解决方案的问题
过去部署项目,通常需要手动配置服务器。
例如:
开发人员:
css
电脑A
Node 14
Redis
MySQL
npm
测试服务器:
css
服务器B
Node 16
Redis版本不同
MySQL配置不同
生产服务器:
服务器C
Node 18
系统不同
依赖不同
每换一台机器,都需要重新配置环境。
于是出现一个问题:
能不能把程序运行需要的一切环境一起打包?
这就是 Docker 要解决的问题。
4. Docker 的核心思想
Docker 的核心理念:
把应用和它运行所需要的环境一起打包。
也就是说:
以前:
服务器
├── Node
├── npm
├── 项目代码
└── 配置
现在:
Docker
┌─────────────────┐
│ 应用 │
│ │
│ Node环境 │
│ │
│ npm依赖 │
│ │
│ 配置 │
└─────────────────┘
这个整体就是一个 Docker 镜像(Image)。
5. 什么是 Image(镜像)?
Image 可以理解为:
一个应用运行环境的模板。
例如:
一个 Node 项目的 Docker Image:
arduino
node-app-image
里面包含:
├── Node.js
├── npm
├── 项目代码
├── node_modules
└── 配置文件
这个 Image 可以复制。
比如:
开发环境:
arduino
node-app-image
测试服务器:
arduino
node-app-image
生产服务器:
arduino
node-app-image
大家运行的是同一个环境。
因此:
开发环境 = 测试环境 = 生产环境
减少了大量环境问题。
6. 什么是 Container(容器)?
Image 是模板。
但是模板不能直接运行。
就像:
程序安装包
不能直接使用
需要安装后运行
Docker 中:
Image
↓
创建
↓
Container
Container 就是真正运行起来的应用实例。
例如:
一个 Node Image:
arduino
node-image
启动:
arduino
docker run node-image
Docker 创建:
Container
里面运行:
Node服务
这个 Container 才是真正工作的程序。
Image 和 Container 的关系
可以简单理解:
kotlin
Image
类似:
类(class)
模板
Container
类似:
对象(object)
运行实例
一个 Image 可以创建多个 Container。
例如:
markdown
Node Image
↓
┌────────────┐
│ Container1 │
└────────────┘
↓
┌────────────┐
│ Container2 │
└────────────┘
同一个应用,可以启动多个实例。
7. Docker 和虚拟机有什么区别?
很多人第一次接触 Docker,会觉得:
Docker 是不是一个轻量级虚拟机?
两者确实类似:
都是隔离运行环境。
但是实现方式不同。
虚拟机
虚拟机模拟完整电脑:
markdown
服务器
└── 虚拟机
├── 操作系统
│
├── 系统库
│
└── 应用
例如:
服务器是 Linux。
虚拟机里面再安装:
Windows
然后运行程序。
缺点:
- 体积大
- 启动慢
- 资源消耗高
Docker
Docker 不需要完整操作系统。
它共享宿主机内核:
css
服务器
├── Docker
│
├── Container A
│ └── Node应用
│
├── Container B
│ └── MySQL
│
└── Container C
└── Redis
优点:
- 启动快
- 占用资源少
- 更适合部署大量服务
8. Docker 在真实项目中的位置
一个现代 Web 项目通常不是一个程序。
例如:
一个电商网站:
用户
↓
前端
React/Vue
↓
后端
Node/Java
↓
数据库
MySQL
↓
缓存
Redis
这些服务可能运行在不同环境。
Docker 可以分别管理:
Docker
├── React Container
├── Node Container
├── MySQL Container
└── Redis Container
每个服务拥有自己的运行环境。
9. 一个简单例子:Vue2 项目 Docker 化
假设你的 Vue2 项目:
lua
vue-project
├── src
├── package.json
└── webpack.config.js
以前运行:
arduino
npm install
npm run dev
依赖:
Node
npm
webpack
Vue
Docker 后:
创建 Image:
arduino
vue-image
包含:
Node
npm
Vue依赖
项目代码
运行:
arduino
docker run vue-image
得到:
vue-container
里面运行:
arduino
npm run dev
结果:
无论在哪台电脑:
只要有 Docker:
arduino
docker run vue-image
项目都可以运行。
10. Dockerfile:告诉 Docker 如何创建环境
Docker 怎么知道:
- 安装什么 Node?
- 复制哪些代码?
- 启动什么命令?
答案是:
Dockerfile。
例如:
sql
FROM node:14
WORKDIR /app
COPY . .
RUN npm install
CMD ["npm","run","dev"]
含义:
选择 Node 环境:
css
FROM node:14
进入工作目录:
bash
WORKDIR /app
复制项目:
sql
COPY . .
安装依赖:
RUN npm install
启动项目:
css
CMD ["npm","run","dev"]
Docker 根据这个文件创建 Image。
流程:
arduino
Dockerfile
↓
docker build
↓
Image
↓
docker run
↓
Container
11. Docker 最核心的三个概念
学习 Docker,只需要先抓住三个东西:
Image
镜像。
负责:
描述应用运行环境。
Container
容器。
负责:
真正运行应用。
Dockerfile
构建规则。
负责:
告诉 Docker 如何创建 Image。
关系:
markdown
Dockerfile
↓
Image
↓
Container
12. 总结
Docker 解决的核心问题:
让应用和运行环境一起交付。
以前:
diff
代码
+
人工配置环境
容易出现:
你的电脑能运行
我的电脑不能运行
Docker:
diff
应用
+
运行环境
+
依赖
↓
Image
↓
Container
让应用拥有一致的运行环境。
下一篇会进入实际部署流程:
《Docker 部署 Web 服务:从 Node 到 Nginx 反向代理》
重点理解:
- Node 服务如何运行在 Docker 中
- 为什么生产环境需要 Nginx
- Nginx 如何作为统一入口
- Docker 如何连接多个服务
- 一个请求从浏览器到后端到底经过什么流程