第一章: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:

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

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
Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐