第一章: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
启动分钟秒级
大小GBMB
性能一般接近原生
隔离
部署

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:

  1. 查找本地有没有 hello-world 镜像

没有:

  1. 去 Docker Hub 下载

然后:

  1. 创建容器
  2. 输出:
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

地址:

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 区别

VolumeBind 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

更多推荐