Docker 保姆级教程:5大章节、从入门到生产,别再说环境问题了
第一章:Docker 到底是什么?
1.1 为什么需要 Docker?
先想一个现实问题:
你开发一个网站。
你的电脑:
Windows
Python 3.12
MySQL 8
Redis 7
Nginx
各种依赖包
你的朋友电脑:
Mac
Python 3.10
MySQL 5.7
没有Redis
服务器:
Linux
Python版本不同
缺少库
结果:
你:
“我电脑运行正常啊!”
服务器:
“为什么启动不了?”
这就是经典问题:
环境不一致。
Docker 的目标:
把程序运行所需要的一切环境,打包成一个标准单位。
这个单位叫:
Container(容器)
比如你的项目:
网站程序
+
Python环境
+
依赖库
+
Linux系统工具
+
配置文件
+
运行命令
全部装进一个盒子:
┌─────────────────┐
│ Docker 容器 │
│ │
│ Python │
│ Django │
│ MySQL连接 │
│ 配置文件 │
│ 网站代码 │
└─────────────────┘
拿到任何机器:
docker run
直接运行。
2. Docker 和虚拟机有什么区别?
很多初学者会混淆。
传统虚拟机
例如 VMware:
电脑
|
|-- Windows
| |
| Linux虚拟机
| |
| 应用
每个虚拟机都有:
- 完整操作系统
- 内核
- 系统文件
非常重。
Docker:
电脑
|
Docker Engine
|
|-- 容器1
| 应用
|
|-- 容器2
| 应用
|
|-- 容器3
应用
共享系统内核。
所以:
| 虚拟机 | Docker | |
|---|---|---|
| 启动 | 分钟 | 秒级 |
| 大小 | GB | MB |
| 性能 | 一般 | 接近原生 |
| 隔离 | 强 | 强 |
| 部署 | 慢 | 快 |
3. Docker 的三个核心概念
你必须牢牢记住:
Image 镜像
↓
Container 容器
↓
Volume 数据
3.1 Image(镜像)
镜像是什么?
简单理解:
镜像 = 创建容器的模板
类似:
手机:
系统安装包
电脑:
Windows ISO文件
Docker:
Image
例如:
官方提供:
nginx镜像
mysql镜像
redis镜像
python镜像
比如:
下载 nginx:
docker pull nginx
得到:
nginx image
然后:
docker run nginx
创建:
nginx container
关系:
Image
|
| 创建
↓
Container
3.2 Container(容器)
容器是什么?
一句话:
容器就是正在运行的镜像。
比如:
镜像:
nginx模板
运行:
docker run nginx
产生:
nginx容器
查看:
docker ps
输出:
CONTAINER ID
IMAGE
STATUS
PORT
3.3 Volume(数据卷)
问题:
如果容器删除:
docker rm mysql
数据库怎么办?
数据也没了。
所以:
数据不能放容器里面。
应该:
容器
mysql程序
|
|
↓
Volume
数据库文件
容器坏了:
重新创建。
数据还在。
4. 安装 Docker
Linux(Ubuntu)
更新:
sudo apt update
安装:
sudo apt install docker.io
启动:
sudo systemctl start docker
设置开机启动:
sudo systemctl enable docker
检查:
docker version
看到:
Docker version xxx
成功。
5. 第一次运行 Docker
执行:
docker run hello-world
发生什么?
Docker:
- 查找本地有没有 hello-world 镜像
没有:
- 去 Docker Hub 下载
然后:
- 创建容器
- 输出:
Hello from Docker!
结束。
6. Docker 常用命令(必须熟练)
查看版本
docker version
查看镜像
docker images
例如:
REPOSITORY
nginx
TAG
latest
SIZE
187MB
下载镜像
docker pull 镜像名
例如:
docker pull nginx
创建并运行容器
docker run nginx
后台运行
生产最常用:
docker run -d nginx
-d:
detach
后台运行。
查看运行中的容器
docker ps
查看所有:
docker ps -a
停止容器
docker stop 容器ID
例如:
docker stop abc123
删除容器
docker rm 容器ID
删除镜像
docker rmi 镜像名
例如:
docker rmi nginx
7. 实战:运行一个网站
运行 nginx:
docker run -d nginx
但是:
浏览器访问不了。
为什么?
因为:
容器端口没有暴露。
正确:
docker run -d \
-p 8080:80 \
nginx
解释:
-p 外部端口:容器端口
也就是:
你的电脑8080
↓
Docker
↓
nginx 80
访问:
http://你的IP:8080
看到:
Welcome to nginx
成功。
8. Docker 的真实工作流程
以后工作基本都是:
第一步
找镜像:
Docker Hub
例如:
mysql
redis
nginx
python
node
第二步
启动:
docker run
第三步
配置:
端口:
-p
数据:
-v
环境变量:
-e
例如:
MySQL:
docker run -d \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=123456 \
mysql
9. 你现在应该建立的思维模型
不要想:
“Docker 是安装软件。”
错误。
应该想:
“Docker 是运行隔离环境。”
例如:
以前:
电脑
安装:
python
mysql
redis
nginx
现在:
电脑
Docker
|
|-- python容器
|
|-- mysql容器
|
|-- redis容器
|
|-- nginx容器
每个软件一个环境。
第一阶段练习
你现在可以练:
练习1
安装 Docker。
执行:
docker version
练习2
下载 nginx:
docker pull nginx
练习3
运行:
docker run -d -p 8080:80 nginx
浏览器打开:
localhost:8080
练习4
查看:
docker ps
停止:
docker stop 容器ID
删除:
docker rm 容器ID
第二章:Docker 镜像 Image 彻底搞懂
上一章我们知道:
Image(镜像)
|
↓
Container(容器)
镜像是创建容器的模板。
但是很多人只会:
docker pull nginx
docker run nginx
却不知道:
- 镜像到底是什么文件?
- 为什么一个镜像几百 MB?
- 为什么下载很快?
- 为什么可以自己制作镜像?
- Docker Hub 上那么多镜像怎么选?
这一章把这些讲透。
1. 镜像到底是什么?
一句话:
Docker 镜像就是一个只读的文件系统快照 + 启动程序配置。
听起来抽象。
我们拆开。
假设你要运行一个 Python 网站。
普通方式:
你需要安装:
Ubuntu系统
↓
Python
↓
pip
↓
Django
↓
代码
↓
配置文件
Docker 镜像就是把这些全部保存下来:
python-web镜像
里面:
Ubuntu基础环境
Python解释器
Django框架
项目代码
启动命令
配置
然后:
docker run python-web
Docker 根据这个模板创建容器。
2. 镜像不是一个完整系统
很多新人误解:
Docker镜像是不是一个虚拟机?
不是。
比如:
Ubuntu镜像:
Ubuntu镜像
|
|-- 文件系统
|-- bash
|-- apt
|-- 一些工具
但是:
没有:
真实硬件
BIOS
完整Linux内核
它共享宿主机内核。
例如:
你的电脑:
Linux Kernel
|
|
Docker
|
+-- Ubuntu容器
|
+-- CentOS容器
|
+-- Debian容器
它们共享下面那个 Linux 内核。
3. Docker 镜像从哪里来?
最大的仓库:
Docker Hub
地址:
里面有:
官方镜像:
nginx
mysql
redis
python
node
ubuntu
例如:
搜索 nginx:
你会看到:
nginx
Official Image
这种可信度最高。
4. docker pull 到底发生了什么?
执行:
docker pull nginx
Docker 做:
第一步:
去仓库找:
nginx:latest
什么意思?
后面解释。
第二步:
下载镜像。
下载过程中:
你可能看到:
Pulling fs layer
a1b2c3 Download complete
d4e5f6 Download complete
这里出现一个重要概念:
Layer(镜像层)
5. 镜像为什么是一层一层的?
Docker 镜像不是一个大文件。
它像千层蛋糕:
nginx配置
----------------
nginx程序
----------------
Linux工具
----------------
Ubuntu基础
----------------
空白
每一层叫:
Layer
为什么设计成这样?
因为可以复用。
例如:
两个项目:
项目A:
Ubuntu
Python
Django
代码A
项目B:
Ubuntu
Python
Flask
代码B
共同部分:
Ubuntu
Python
只需要下载一次。
结构:
代码A
|
Django
|
Python
|
Ubuntu
代码B
|
Flask
|
Python
|
Ubuntu
底层共享。
好处:
- 节省空间
- 下载快
- 构建快
6. 查看镜像
命令:
docker images
例如:
REPOSITORY TAG IMAGE ID SIZE
nginx latest a6b7c8 187MB
mysql 8.0 d9e8f7 500MB
解释:
REPOSITORY
镜像名字:
例如:
nginx
mysql
redis
TAG
版本标签。
例如:
mysql:8.0
意思:
mysql 镜像
版本:
8.0
如果:
docker pull mysql
默认:
mysql:latest
7. latest 是不是最新?
这是一个大坑。
很多人认为:
latest = 最新版本
错误。
latest 只是:
作者设置的默认标签。
例如:
今天:
mysql:latest
可能:
mysql 8.4
半年后:
mysql:latest
可能:
mysql 9
生产环境不要:
mysql:latest
应该:
mysql:8.0
固定版本。
8. IMAGE ID 是什么?
例如:
IMAGE ID
a6b7c8d9
类似身份证。
两个名字:
nginx:latest
nginx:1.27
可能:
其实是同一个镜像。
例如:
nginx:latest
|
|
↓
IMAGE ID abc123
nginx:1.27
|
|
↓
IMAGE ID abc123
9. 查看镜像详细信息
命令:
docker inspect nginx
你可以看到:
创建时间
环境变量
启动命令
网络
挂载信息
这是排查问题的重要命令。
10. 删除镜像
删除:
docker rmi nginx
如果提示:
image is being used
原因:
有容器使用它。
查看:
docker ps -a
删除容器:
docker rm 容器ID
再删除镜像。
11. 镜像和容器的关系(重点)
很多人搞混:
镜像:
静态的。
安装包
模板
不会变化。
容器:
动态的。
运行中的程序
会产生变化。
关系:
Image
|
|
docker run
↓
Container
|
|
运行产生数据
例如:
下载:
mysql镜像
创建:
mysql容器
你创建10个数据库:
mysql容器1
mysql容器2
mysql容器3
它们都是:
同一个mysql镜像
12. 查看镜像历史
命令:
docker history nginx
输出:
IMAGE
CREATED BY
ADD ubuntu
RUN apt install nginx
COPY nginx.conf
你会看到:
这个镜像是怎么一步一步制作出来的。
这就是以后 Dockerfile 的基础。
13. 镜像大小优化思维
生产环境很重要。
例如:
错误:
Ubuntu 5GB
+
Python
+
你的程序
最终:
6GB。
优化:
使用:
python:slim
可能:
几百 MB。
甚至:
alpine
几十 MB。
例如:
普通:
python:3.12
900MB
优化:
python:3.12-slim
150MB
14. 搜索镜像
命令:
docker search nginx
但是实际开发:
更多使用 Docker Hub 网站搜索。
看:
- 下载量
- 官方认证
- 更新时间
- 文档
15. 企业使用镜像的流程
真实公司:
一般不是直接:
docker pull
然后运行。
而是:
开发:
写代码
↓
制作镜像:
Dockerfile
↓
构建:
docker build
↓
上传:
docker push
↓
服务器:
docker pull
↓
运行:
docker run
流程:
代码
|
↓
Dockerfile
|
↓
Image
|
↓
Registry
|
↓
Container
本章必须掌握的命令
| 功能 | 命令 |
|---|---|
| 下载镜像 | docker pull |
| 查看镜像 | docker images |
| 删除镜像 | docker rmi |
| 搜索镜像 | docker search |
| 查看详情 | docker inspect |
| 查看历史 | docker history |
| 查看占用 | docker system df |
第三章:Docker 容器 Container 深入理解
前面我们学了:
- 镜像 Image 是模板
- 容器 Container 是运行中的实例
现在进入 Docker 最核心的部分。
真正工作中,你每天操作最多的就是:
docker run
docker ps
docker logs
docker exec
docker stop
docker rm
1. 容器到底是什么?
一句话:
容器就是镜像启动之后产生的一个运行环境。
比如:
你有一个镜像:
nginx镜像
执行:
docker run nginx
Docker 创建:
nginx容器
结构:
镜像 Image
|
|
docker run
|
↓
容器 Container
+----------------------+
| |
| nginx程序 |
| nginx配置 |
| 临时文件 |
| 进程 |
| 网络 |
+----------------------+
2. 容器不是虚拟机
很多初学者理解错误:
认为:
一个容器 = 一个小电脑
不是。
容器本质:
一个被隔离的 Linux 进程。
例如:
你运行 nginx:
docker run nginx
实际上:
Linux里面多了一个进程:
PID 1234 nginx
只是 Docker 给它:
- 文件隔离
- 网络隔离
- 资源限制
所以看起来像独立机器。
3. 第一次理解 docker run
命令:
docker run nginx
实际上做了很多事情:
流程:
docker run nginx
|
|
↓
1. 检查有没有 nginx 镜像
|
|
↓
2. 没有就 pull
|
|
↓
3. 创建容器
|
|
↓
4. 分配网络
|
|
↓
5. 启动 nginx 进程
|
|
↓
6. 输出日志
4. docker run 的完整结构
以后你会经常看到:
docker run [参数] 镜像 [命令]
例如:
docker run \
-d \
--name web \
-p 8080:80 \
nginx
拆开:
-d
后台运行:
-d
叫:
detach
例如:
docker run nginx
你的终端:
一直显示日志
不能输入。
使用:
docker run -d nginx
立即返回:
abc123456
容器后台运行。
5. 给容器取名字
默认:
docker run nginx
Docker 自动生成:
类似:
happy_morse
不好记。
推荐:
docker run \
--name my-nginx \
nginx
查看:
docker ps
结果:
NAME
my-nginx
以后:
docker stop my-nginx
不用记 ID。
6. 端口映射 -p(超级重要)
这是 Docker 最常用参数。
例如:
运行 nginx:
docker run -d nginx
问题:
浏览器访问不了。
为什么?
因为:
容器内部:
nginx
监听:
80端口
但是:
外部电脑不知道。
需要:
docker run \
-d \
-p 8080:80 \
nginx
意思:
电脑8080端口
↓
Docker
↓
容器80端口
↓
nginx
访问:
http://localhost:8080
多端口映射
例如:
一个网站:
HTTP 80
HTTPS 443
可以:
docker run \
-p 8080:80 \
-p 8443:443 \
nginx
7. 查看运行中的容器
命令:
docker ps
例如:
CONTAINER ID IMAGE STATUS PORTS
abc123 nginx Up 0.0.0.0:8080->80
解释:
CONTAINER ID
容器身份证:
abc123
IMAGE
来自哪个镜像:
nginx
STATUS
状态:
Up
表示运行。
PORTS
端口:
8080->80
表示:
外部8080
映射
容器80。
8. 查看所有容器
注意:
docker ps
只能看到运行中的。
停止的:
看不到。
全部:
docker ps -a
例如:
CONTAINER ID
abc123 nginx Up
def456 mysql Exited
Exited:
表示退出。
9. 容器为什么会退出?
这是新人最大的问题。
例如:
运行:
docker run ubuntu
结果:
马上结束。
为什么?
因为:
Ubuntu镜像默认:
没有持续运行程序。
容器生命周期:
取决于里面的主进程。
规则:
主进程结束,容器结束。
例如:
nginx:
nginx进程
一直运行
↓
容器一直运行
ubuntu:
bash执行完
↓
没有进程
↓
容器退出
10. 查看容器日志
生产排查最重要。
命令:
docker logs 容器名
例如:
docker logs my-nginx
实时查看:
docker logs -f my-nginx
-f:
类似:
tail -f
11. 进入正在运行的容器
这是 Docker 必学技能。
例如:
进入 nginx:
docker exec -it my-nginx bash
解释:
exec
执行命令。
-i
interactive
保持输入。
-t
分配终端。
合起来:
-i -t
进入交互终端
进去后:
你看到:
root@abc123:/#
你现在:
已经进入容器内部。
12. 容器里面是什么?
进去:
ls
看到:
bin
etc
usr
var
像 Linux。
但是:
这是容器自己的文件系统。
例如:
容器:
/etc/nginx
宿主机:
/etc/nginx
不是一个。
13. exec 和 attach 区别
很多人混淆。
exec
推荐。
例如:
docker exec -it nginx bash
特点:
创建一个新的终端。
attach
连接原来的主进程。
例如:
docker attach nginx
风险:
退出可能导致容器停止。
生产少用。
14. 停止容器
正常:
docker stop nginx
过程:
发送 SIGTERM
等待
结束
强制:
docker kill nginx
区别:
stop
优雅关闭
kill
直接杀掉
15. 启动已经停止的容器
例如:
停止:
docker stop nginx
重新启动:
docker start nginx
注意:
这不是创建新容器。
只是:
旧容器重新启动
16. 删除容器
删除:
docker rm nginx
但是:
运行中的不能删。
强制:
docker rm -f nginx
17. 自动删除容器
测试非常有用:
docker run --rm nginx
意思:
容器结束后:
自动删除。
适合:
测试任务。
18. 查看容器详细信息
命令:
docker inspect nginx
里面有:
容器ID
网络
IP地址
挂载
环境变量
启动命令
排错神器。
19. 查看容器资源占用
类似 Linux:
top
Docker:
docker stats
显示:
CPU
Memory
Network
Disk
例如:
nginx
CPU 0.5%
MEM 20MB
20. 限制容器资源
生产环境非常重要。
限制内存:
docker run \
--memory=512m \
nginx
限制 CPU:
docker run \
--cpus=1 \
nginx
意思:
最多:
1个CPU核心
512MB内存
21. 容器完整生命周期
记住这个图:
创建
docker create
↓
启动
docker start
↓
运行
docker ps
↓
停止
docker stop
↓
删除
docker rm
22. 企业实际操作流程
例如公司部署一个 Java 服务:
拿到镜像:
company/app:v1
运行:
docker run \
-d \
--name app \
-p 8080:8080 \
app:v1
查看:
docker ps
看日志:
docker logs -f app
进入:
docker exec -it app bash
重启:
docker restart app
第三章必须掌握命令
| 功能 | 命令 |
|---|---|
| 运行容器 | docker run |
| 查看运行 | docker ps |
| 查看全部 | docker ps -a |
| 查看日志 | docker logs |
| 进入容器 | docker exec -it |
| 停止 | docker stop |
| 启动 | docker start |
| 删除 | docker rm |
| 查看详情 | docker inspect |
| 资源监控 | docker stats |
第四章:Docker 数据卷 Volume(真正生产必学)
前面我们学了:
- Image:镜像,是模板
- Container:容器,是运行实例
现在出现一个非常重要的问题:
如果容器删除了,里面的数据怎么办?
这就是 Docker Volume(数据卷)存在的意义。
1. 为什么需要 Volume?
先看一个例子。
运行 MySQL:
docker run \
-d \
--name mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
mysql
现在:
数据库运行了。
进入:
docker exec -it mysql bash
查看:
ls /var/lib/mysql
你会看到:
数据库文件
例如:
users
orders
products
现在删除容器:
docker rm -f mysql
然后重新创建:
docker run \
-d \
--name mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
mysql
进去:
ls /var/lib/mysql
结果:
空的。
你的数据:
没了。
为什么?
因为:
容器里的文件属于容器。
结构:
宿主机
Docker
|
|
↓
Container
|
|
↓
MySQL数据
删除容器:
整个文件系统删除。
2. Volume 是什么?
一句话:
Volume 是 Docker 专门用来保存数据的地方,它独立于容器生命周期。
以前:
容器
mysql程序
+
数据库文件
现在:
容器
mysql程序
|
|
↓
Volume
数据库文件
关系:
Container
MySQL程序
|
|
↓
Volume
数据文件
删除容器:
Container 删除
↓
Volume 保留
↓
数据还在
3. Docker 数据存在哪里?
Linux 默认:
/var/lib/docker/volumes/
例如:
/var/lib/docker/
volumes/
mysql_data/
里面:
数据库文件
但是:
不要直接修改这里。
让 Docker 管理。
4. 创建 Volume
命令:
docker volume create mysql_data
查看:
docker volume ls
结果:
DRIVER
local
NAME
mysql_data
查看详情:
docker volume inspect mysql_data
例如:
Mountpoint:
/var/lib/docker/volumes/mysql_data/_data
5. 使用 Volume
重点:
-v
参数。
格式:
-v volume名字:容器路径
例如:
MySQL:
docker run \
-d \
--name mysql \
-v mysql_data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
mysql
解释:
mysql_data
↓
映射
↓
/var/lib/mysql
也就是:
MySQL 数据:
实际保存:
mysql_data
而不是容器。
6. 测试数据持久化
完整实验:
第一步
创建数据库:
docker exec -it mysql bash
进入:
mysql -uroot -p
密码:
123456
创建:
CREATE DATABASE test;
退出:
exit;
第二步
删除容器:
docker rm -f mysql
第三步
重新创建:
docker run \
-d \
--name mysql \
-v mysql_data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
mysql
进入:
mysql -uroot -p
查看:
SHOW DATABASES;
你会发现:
test
还在。
这就是 Volume。
7. Volume 三种方式
Docker 保存数据有三种常见方式。
第一种:匿名 Volume
例如:
docker run \
-v /var/lib/mysql \
mysql
Docker 自动创建:
随机名字volume
例如:
a8f7d9xxxx
缺点:
不好管理。
第二种:命名 Volume(推荐)
例如:
-v mysql_data:/var/lib/mysql
名字:
mysql_data
优点:
清楚。
生产常用。
第三种:绑定宿主机目录 Bind Mount
例如:
-v /data/mysql:/var/lib/mysql
意思:
宿主机:
/data/mysql
映射:
容器:
/var/lib/mysql
结构:
服务器
/data/mysql
|
|
↓
容器
/var/lib/mysql
8. Volume 和 Bind Mount 区别
| Volume | Bind Mount | |
|---|---|---|
| 管理者 | Docker | 用户 |
| 位置 | Docker管理 | 自己指定 |
| 安全 | 高 | 一般 |
| 生产 | 推荐 | 也常用 |
| 开发代码 | 少用 | 常用 |
9. 开发中为什么喜欢 Bind Mount?
比如写 Python:
你的代码:
/home/project
容器:
/app
运行:
docker run \
-v /home/project:/app \
python
效果:
修改代码:
马上同步。
不用:
重新 build 镜像。
非常适合开发。
10. 查看 Volume
列表:
docker volume ls
详情:
docker volume inspect mysql_data
删除:
docker volume rm mysql_data
注意:
如果正在使用:
不能删除。
11. 清理没用的 Volume
开发机器经常积累垃圾:
查看:
docker volume ls
删除无用:
docker volume prune
会提示:
Are you sure?
确认:
删除所有未使用 Volume。
12. Docker 数据备份
假设:
mysql_data
需要备份。
方法:
启动临时容器:
docker run \
--rm \
-v mysql_data:/data \
-v $(pwd):/backup \
ubuntu \
tar czf /backup/mysql.tar.gz /data
结果:
当前目录:
mysql.tar.gz
恢复:
tar xzf mysql.tar.gz
13. 生产数据库 Docker 设计
错误:
MySQL
↓
容器内部存数据
风险:
容器删除:
数据丢失。
正确:
MySQL Container
|
|
↓
mysql_volume
|
|
↓
持久化磁盘
另外:
生产通常:
- 定期备份
- 主从复制
- 云硬盘
- 监控
14. 一个真实案例
公司部署:
网站系统
包含:
Nginx
↓
Java服务
↓
MySQL
↓
Redis
Docker:
nginx container
java container
mysql container
|
|
↓
mysql_volume
redis container
|
|
↓
redis_volume
代码和数据分离。
15. Volume 常见坑
坑1:忘记挂载
运行:
docker run mysql
生产危险。
应该:
docker run \
-v mysql_data:/var/lib/mysql \
mysql
坑2:删除容器以为数据没了
如果用了 Volume:
容器没了
数据还在
坑3:权限问题
例如:
Permission denied
原因:
宿主机目录权限。
解决:
检查:
ls -l
修改:
chmod
chown
本章核心思想
记住一句话:
容器负责运行,Volume 负责保存。
生产设计:
程序
↓
Container
数据
↓
Volume
不要混在一起。
第五章:Docker 网络 Network(容器之间如何通信)
前面我们学:
- Image:程序模板
- Container:运行环境
- Volume:保存数据
现在进入 Docker 的另一个核心:
容器之间如何连接?
真实项目几乎不会只有一个容器。
例如一个网站:
用户
|
↓
Nginx
|
↓
Java后端
|
↓
MySQL
|
↓
Redis
这些都是不同容器。
问题来了:
Nginx 怎么找到 Java?
Java 怎么找到 MySQL?
答案:
Docker Network。
1. Docker 网络是什么?
简单理解:
Docker Network 是 Docker 创建的一套虚拟网络,让容器之间可以通信。
类似现实:
电脑:
电脑A
|
交换机
|
电脑B
Docker:
容器A
|
Docker网络
|
容器B
2. Docker 默认网络
安装 Docker 后:
查看:
docker network ls
你会看到:
NETWORK ID NAME DRIVER
xxxx bridge bridge
xxxx host host
xxxx none null
三个默认网络:
| 网络 | 作用 |
|---|---|
| bridge | 最常用 |
| host | 共享主机网络 |
| none | 没有网络 |
3. 默认 bridge 网络
这是 Docker 默认模式。
例如:
运行:
docker run -d nginx
Docker 自动:
创建容器:
nginx容器
IP:
172.17.0.2
结构:
宿主机
192.168.1.100
|
|
Docker bridge
|
|
172.17.0.2
nginx容器
查看:
docker inspect nginx
找到:
IPAddress
172.17.0.2
4. 容器之间可以直接 IP 通信吗?
可以。
例如:
创建两个容器:
container A
IP:
172.17.0.2
container B
IP:
172.17.0.3
A:
访问:
172.17.0.3
可以通信。
但是:
有一个巨大问题。
5. 容器 IP 为什么不能直接用?
因为:
容器 IP 会变化。
例如:
今天:
mysql
172.17.0.5
明天:
重新创建:
mysql
172.17.0.8
你的程序配置:
DB_HOST=172.17.0.5
废了。
所以:
生产不用 IP。
用:
容器名字。
6. 自定义网络(重点)
推荐方式。
创建网络:
docker network create my-network
查看:
docker network ls
出现:
my-network
现在运行 MySQL:
docker run \
-d \
--name mysql \
--network my-network \
-e MYSQL_ROOT_PASSWORD=123456 \
mysql
运行 Java:
docker run \
-d \
--name app \
--network my-network \
my-java-app
现在:
app 可以通过:
mysql
访问数据库。
不是:
172.17.0.5
而是:
mysql:3306
7. Docker DNS 是怎么工作的?
你可能疑惑:
为什么:
mysql
能找到数据库?
因为 Docker 内置 DNS。
类似:
互联网:
www.baidu.com
↓
IP地址
Docker:
mysql
↓
172.18.0.2
流程:
Java容器
请求:
mysql:3306
↓
Docker DNS
↓
找到mysql容器IP
↓
连接
8. 实战:MySQL + Web 容器通信
创建网络:
docker network create app-net
启动数据库:
docker run \
-d \
--name mysql \
--network app-net \
-e MYSQL_ROOT_PASSWORD=123456 \
mysql
启动另一个容器:
docker run \
-it \
--rm \
--network app-net \
ubuntu bash
进入:
安装工具:
apt update
apt install mysql-client
测试:
mysql \
-h mysql \
-uroot \
-p
输入:
123456
成功连接。
注意:
这里:
-h mysql
不是:
-h 172.xxx.xxx.xxx
9. 容器端口和网络的区别
很多新人搞混。
例如:
MySQL:
容器内部:
3306端口
两个容器:
Java
|
|
mysql:3306
不需要:
-p 3306:3306
为什么?
因为:
它们在 Docker 网络内部。
什么时候需要 -p?
外部访问:
例如:
你的电脑:
Navicat
|
↓
MySQL容器
需要:
-p 3306:3306
总结:
| 场景 | 需要-p吗 |
|---|---|
| 容器访问容器 | 不需要 |
| 电脑访问容器 | 需要 |
| 公网访问 | 需要 |
10. host 网络模式
命令:
docker run \
--network host \
nginx
特点:
容器直接使用宿主机网络。
结构:
普通:
宿主机
192.168.1.10
|
Docker
|
容器
172.x.x.x
host:
宿主机
192.168.1.10
|
|
容器直接使用
优点:
性能高。
缺点:
隔离差。
一般:
- 高性能服务
- 网络代理
才使用。
11. none 网络
完全关闭网络:
docker run \
--network none \
ubuntu
里面:
没有网络。
用途:
安全测试。
12. 查看网络详情
命令:
docker network inspect my-network
看到:
Containers:
mysql
172.18.0.2
app
172.18.0.3
13. 一个真实生产架构
假设:
电商网站:
用户
|
↓
Nginx容器
|
↓
后端容器
|
↓
MySQL容器
Docker:
创建:
shop-network
加入:
nginx
backend
mysql
redis
网络:
shop-network
|
|
+ nginx
|
+ backend
|
+ mysql
|
+ redis
所有服务:
通过名字访问。
例如:
后端配置:
数据库地址:
mysql
端口:
3306
14. Docker 网络常见问题
问题1:
容器 ping 不通。
检查:
是否同一个网络:
docker network inspect xxx
问题2:
使用 IP 写配置。
错误:
DB_HOST=172.18.0.3
正确:
DB_HOST=mysql
问题3:
以为 -p 是容器通信必须。
错误:
app连接mysql
需要mysql -p 3306
不需要。
15. 网络命令总结
| 功能 | 命令 |
|---|---|
| 查看网络 | docker network ls |
| 创建网络 | docker network create |
| 删除网络 | docker network rm |
| 查看详情 | docker network inspect |
| 连接网络 | docker network connect |
| 断开网络 | docker network disconnect |
本章练习
练习1:创建网络
docker network create test-net
练习2:启动两个容器
容器A:
docker run \
-d \
--name nginx1 \
--network test-net \
nginx
容器B:
docker run \
-it \
--rm \
--network test-net \
ubuntu bash
安装 ping:
apt update
apt install iputils-ping
测试:
ping nginx1
如果通:
说明 Docker DNS 正常。
练习3:思考
为什么:
Java连接MySQL
推荐:
mysql:3306
而不是:
172.18.0.5:3306
到这里,你已经掌握 Docker 四大核心:
Image
|
↓
Container
|
↓
Volume
|
↓
Network
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)