引言
本篇整理了我学习
Docker
时的一些笔记。
部署环境:Windows 10 Professional Workstation
Docker 是 PaaS 提供商 dotCloud 开源的一个基于 LXC 的高级容器引擎,源代码托管在 Github 上, 基于go语言并遵从Apache2.0协议开源。
Docker自2013年以来非常火热,无论是从 github 上的代码活跃度,还是Redhat在RHEL6.5中集成对Docker的支持, 就连 Google 的 Compute Engine 也支持 docker 在其之上运行。
- 环境管理复杂 - 从各种OS到各种中间件到各种app, 一款产品能够成功作为开发者需要关心的东西太多,且难于管理,这个问题几乎在所有现代IT相关行业都需要面对。
- 云计算时代的到来 - AWS的成功, 引导开发者将应用转移到 cloud 上, 解决了硬件管理的问题,然而中间件相关的问题依然存在 (所以openstack HEAT和 AWS cloudformation 都着力解决这个问题)。开发者思路变化提供了可能性。
- 虚拟化手段的变化 - cloud 时代采用标配硬件来降低成本,采用虚拟化手段来满足用户按需使用的需求以及保证可用性和隔离性。然而无论是KVM还是Xen在 docker 看来,都在浪费资源,因为用户需要的是高效运行环境而非OS, GuestOS既浪费资源又难于管理, 更加轻量级的LXC更加灵活和快速。
- LXC的移动性 - LXC在 linux 2.6 的 kernel 里就已经存在了,但是其设计之初并非为云计算考虑的,缺少标准化的描述手段和容器的可迁移性,决定其构建出的环境难于迁移和标准化管理(相对于KVM之类image和snapshot的概念)。docker 就在这个问题上做出实质性的革新。这是docker最独特的地方。
面对上述几个问题,docker设想是交付运行环境如同海运,OS如同一个货轮,每一个在OS基础上的软件都如同一个集装箱,用户可以通过标准化手段自由组装运行环境,同时集装箱的内容可以由用户自定义,也可以由专业人员制造。这样,交付一个软件,就是一系列标准化组件的集合的交付,如同乐高积木,用户只需要选择合适的积木组合,并且在最顶端署上自己的名字( 最后一个标准化组件是用户的app )。这也就是基于docker的PaaS产品的原型。
Hello World
官方文档
Docker vs VM
优点
配置快 - 提供独立的开发环境,便于开发, 由于 Docker 可以在各种各样的环境中使用,而基础架构不要求与应用程序的环境相关联,因此不存在兼容性问题。
提高工作效率 - 这是一种类似于集装箱的概念,在开发之初就将项目放到一个类似于集装箱的独立环境进行开发,到部署的时候只是部署集装箱环境,而集装箱环境已经被所有的系统指定了统一标准,不存在兼容问题,所以可以提高工作效率。
应用隔离 - Docker 提供用于在隔离环境中运行应用程序的容器。每个容器都是独立,并允许执行任何类型的应用程序,并且不存在入侵和病毒感染的问题,甚至可以使用沙箱进行病毒隔离。
云集 - 它是 Docker 容器的集群和调度工具。 Swarm 使用 Docker API作为其前端,这有助于我们使用各种工具来控制它。 它还可以将 Docker 主机集群控制为一个虚拟主机。 这是一个用于启用可插拔后端的自组织引擎组。
路由网 - 它能够将可用节点上已发布端口的传入请求路由到活动容器,实现连接。
服务 - 服务是允许指定集群内的容器状态的任务列表。 每个任务表示一个应该运行的容器的一个实例,并且 Swarm 在节点之间调度它们。
安全管理 - 安全性和管理应当是一个高优先级的考虑因素;企业用户不应再把它们当作应用程序迁移至容器的最后一步。反之,企业必须从一开始就做好安全性和管理的规划,把它们的功能纳入应用程序的开发过程中,并在应用程序运行过程中积极主动地关注这些方面。
局限
Docker 是基于 Linux64 bit的,无法在 32bit 的 Linux/Windows/unix环境下使用。
LXC 是基于 cgroup等 linux kernel 功能的,因此container的 guest 系统只能是 linux base 的。
隔离性相比KVM之类的虚拟化方案还是有些欠缺,所有 container 公用一部分的运行库。
网络管理相对简单,主要是基于 namespace 隔离,cgroup 的 cpu 和 cpuset 提供的cpu功能相比 KVM 的等虚拟化方案相比难以度量(所以 Dotcloud 主要是按内存收费)。
Docker 对 disk 的管理比较有限,container 随着用户进程的停止而销毁,container 中的 log 等用户数据不便收集。
Welcome To Docker
PS C:\Users\P7XXTM1-G> docker run hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
Docker 帮助命令
docker version
查看 Docker 版本信息。
PS C:\Users\P7XXTM1-G> docker version
Client: Docker Engine - Community
Cloud integration: 1.0.9
Version: 20.10.5
API version: 1.41
Go version: go1.13.15
Git commit: 55c4c88
Built: Tue Mar 2 20:14:53 2021
OS/Arch: windows/amd64
Context: default
Experimental: true
Server: Docker Engine - Community
Engine:
Version: 20.10.5
API version: 1.41 (minimum version 1.12)
Go version: go1.13.15
Git commit: 363e9a8
Built: Tue Mar 2 20:15:47 2021
OS/Arch: linux/amd64
Experimental: false
......
docker info
查看 Docker 信息。
PS C:\Users\P7XXTM1-G> docker info
Client:
Context: default
Debug Mode: false
Plugins:
app: Docker App (Docker Inc., v0.9.1-beta3)
buildx: Build with BuildKit (Docker Inc., v0.5.1-docker)
scan: Docker Scan (Docker Inc., v0.5.0)
Server:
Containers: 2
Running: 0
Paused: 0
Stopped: 2
Images: 2
Server Version: 20.10.5
Storage Driver: overlay2
Backing Filesystem: extfs
Supports d_type: true
Native Overlay Diff: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Cgroup Version: 1
Plugins:
Volume: local
Network: bridge host ipvlan macvlan null overlay
Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
Swarm: inactive
Runtimes: io.containerd.runc.v2 io.containerd.runtime.v1.linux runc
Default Runtime: runc
Init Binary: docker-init
containerd version: 269548fa27e0089a8b8278fc4fc781d7f65a939b
runc version: ff819c7e9184c13b7c2607fe6c30ae19403a7aff
init version: de40ad0
Security Options:
seccomp
Profile: default
Kernel Version: 5.4.72-microsoft-standard-WSL2
Operating System: Docker Desktop
OSType: linux
Architecture: x86_64
CPUs: 6
Total Memory: 12.44GiB
Name: docker-desktop
ID: LJH4:2VZK:AH4N:WRBD:A27I:KKRD:IWQP:C4ML:D753:TVQD:53ES:YECZ
Docker Root Dir: /var/lib/docker
Debug Mode: false
Registry: https://index.docker.io/v1/
Labels:
Experimental: false
Insecure Registries:
127.0.0.0/8
Registry Mirrors:
https://w3z80w3y.mirror.aliyuncs.com/
https://hub-mirror.c.163.com/
Live Restore Enabled: false
WARNING: No blkio throttle.read_bps_device support
WARNING: No blkio throttle.write_bps_device support
WARNING: No blkio throttle.read_iops_device support
WARNING: No blkio throttle.write_iops_device support
docker xx –help
查看 Docker 命令的帮助文档。
例如:docker images --help
PS C:\Users\P7XXTM1-G> docker images --help
Usage: docker images [OPTIONS] [REPOSITORY[:TAG]]
List images
Options:
-a, --all Show all images (default hides intermediate images)
--digests Show digests
-f, --filter filter Filter output based on conditions provided
--format string Pretty-print images using a Go template
--no-trunc Don't truncate output
-q, --quiet Only show image IDs
Docker 镜像命令
docker images
查看本机所有 Docker 镜像。
- -a, –all 列出所有镜像
- -q, –quite 只显示镜像id
-aq可在后续 删除镜像命令 时配合使用
PS C:\Users\P7XXTM1-G> docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker/getting-started latest 021a1b85e641 3 months ago 27.6MB
hello-world latest bf756fb1ae65 14 months ago 13.3kB
docker search 镜像关键词
搜索 Docker 镜像。
PS C:\Users\P7XXTM1-G> docker search ubuntu
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
ubuntu Ubuntu is a Debian-based Linux operating sys… 11944 [OK]
dorowu/ubuntu-desktop-lxde-vnc Docker image to provide HTML5 VNC interface … 504 [OK]
......
docker pull 镜像名[:tag]
拉取 Docker 镜像。
PS C:\Users\P7XXTM1-G> docker pull mysql:latest
latest: Pulling from library/mysql # 如果不指定 tag,则默认 latest
a076a628af6f: Pull complete # 分层下载,联合文件系统
f6c208f3f991: Pull complete
88a9455a9165: Pull complete
406c9b8427c6: Pull complete
7c88599c0b25: Pull complete
25b5c6debdaf: Pull complete
43a5816f1617: Pull complete
1a8c919e89bf: Pull complete
9f3cf4bd1a07: Pull complete
80539cea118d: Pull complete
201b3cad54ce: Pull complete
944ba37e1c06: Pull complete
Digest: sha256:feada149cb8ff54eade1336da7c1d080c4a1c7ed82b5e320efb5beebed85ae8c # 签名
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest # 真实地址
docker rmi 镜像
删除 Docker 镜像。
docker rmi -f 容器id # 删除指定镜像
docker rmi -f 容器id 容器id ... # 删除多个镜像
docker rmi -f $(docker images -aq) # 删除所有镜像
Docker 容器命令
docker run [可选参数] image
通过指定镜像,生成指定容器。
搭配 -it 与终端路径可对应进入指定 Linux 容器。
常用可选参数 | 说明 |
---|---|
–name=”Name” | 容器名 |
-d | 后台方式运行 |
-it | 使用交互方式运行,进入容器查看内容 |
-p ip:主机端口:容器端口 | 指定容器端口 |
-p 主机端口:容器端口(常用) | 指定容器端口 |
-p 容器端口 | 指定容器端口 |
-P | 指定随机端口 |
PS C:\Users\P7XXTM1-G> docker run -it ubuntu /bin/bash
root@33339890e94c:/# ls
bin boot dev etc home lib lib32 lib64 libx32 media mnt opt proc root run sbin srv sys tmp usr var
root@33339890e94c:/# cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04.2 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.2 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal
root@33339890e94c:/#
exit
退出
且停止容器
root@33339890e94c:/# exit
exit
PS C:\Users\P7XXTM1-G>
若要退出容器,但
不想停止容器
,则通过快捷键 Ctrl + P + Q
即可。
root@cd9e271f0792:/#
PS C:\Users\P7XXTM1-G> docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cd9e271f0792 ubuntu "/bin/bash" 7 seconds ago Up 6 seconds serene_hopper
PS C:\Users\P7XXTM1-G>
docker ps
查看运行的容器。
常用可选参数 | 说明 |
---|---|
-a | 列出当前正在运行的容器与历史运行容器 |
-n=? | 显示最近运行的容器,”?” 可指定输出条目,如:-n=1,则输出最近一条记录 |
-q | 只显示容器编号 |
PS C:\Users\P7XXTM1-G> docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
PS C:\Users\P7XXTM1-G> docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
33339890e94c ubuntu "/bin/bash" 5 minutes ago Exited (0) About a minute ago inspiring_zhukovsky
PS C:\Users\P7XXTM1-G>
docker rm 容器id
删除容器
docker rm 容器id # 删除指定容器,不能删除正在运行的容器,如果要强制删除则需要通过 rm -f 执行
docker rm -f $(docker ps -aq) # 删除所有容器
docker ps -aq|xargs docker rm # 删除所有容器(管道锁)
容器的 启动/重启/停止/强制停止 命令
docker start 容器id # 启动容器
docker restart 容器id # 重启容器
docker stop 容器id # 停止当前正在运行的容器
docker kill 容器id # 强制停止当前正在运行的容器
Docker 其他常用命令
docker run -d 镜像名
以后台启动方式启动容器。
此时若后台启动的容器中没有前台应用
,则 Docker 会停止该后台容器,则使用 docker ps 命令将不会后台运行容器。
若需要容器在后台保持运行,则必须有一个前台进程。
PS C:\Users\P7XXTM1-G> docker run -d ubuntu
e0f36dc3a166a6dd9c612d26b17e845a8a3a0a2c071f47b8fd9f8cf9ee78082a
docker logs
查看容器日志。
常用可选参数 | 说明 |
---|---|
-f | 打印日志 |
-t | 以时间戳字符串输出 |
–tail | 输出日志条数 |
PS C:\Users\P7XXTM1-G> docker run -d ubuntu /bin/sh -c "while true;do echo hello-from-ubunut;sleep 1;done"
2f090441e6e80fcf526e664973e968fbf8b33d1228ea4a91d38a02d4661edc3a
PS C:\Users\P7XXTM1-G> docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2f090441e6e8 ubuntu "/bin/sh -c 'while t…" 4 seconds ago Up 2 seconds gallant_elgamal
PS C:\Users\P7XXTM1-G> docker logs -f -t --tail 10 2f090441e6e8
2021-03-18T05:13:02.218287300Z hello-from-ubunut
2021-03-18T05:13:03.219282500Z hello-from-ubunut
2021-03-18T05:13:04.220377900Z hello-from-ubunut
2021-03-18T05:13:05.221435600Z hello-from-ubunut
2021-03-18T05:13:06.223104800Z hello-from-ubunut
2021-03-18T05:13:07.223687300Z hello-from-ubunut
2021-03-18T05:13:08.224903600Z hello-from-ubunut
2021-03-18T05:13:09.225778500Z hello-from-ubunut
2021-03-18T05:13:10.226692700Z hello-from-ubunut
2021-03-18T05:13:11.227667300Z hello-from-ubunut
2021-03-18T05:13:12.228729200Z hello-from-ubunut
2021-03-18T05:13:13.229784400Z hello-from-ubunut
2021-03-18T05:13:14.230961900Z hello-from-ubunut
2021-03-18T05:13:15.232517700Z hello-from-ubunut
2021-03-18T05:13:16.233134900Z hello-from-ubunut
2021-03-18T05:13:17.234228900Z hello-from-ubunut
2021-03-18T05:13:18.235945200Z hello-from-ubunut
2021-03-18T05:13:19.236571400Z hello-from-ubunut
2021-03-18T05:13:20.238078900Z hello-from-ubunut
PS C:\Users\P7XXTM1-G>
docker stats
查看 Docker 资源占用情况。
ubuntu@DESKTOP-5IG459O:~$ docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
f3a8f8e37903 dreamy_tesla 0.00% 6.809MiB / 12.44GiB 0.05% 516B / 0B 0B / 0B 1
c08739536043 quirky_roentgen 0.00% 2.285MiB / 12.44GiB 0.02% 656B / 0B 0B / 0B 1
9e8cb66f4144 Elasticsearch 0.21% 2.224GiB / 12.44GiB 17.87% 1.8kB / 867B 0B / 0B 48
docker top 容器id
查看容器中的的进程信息。
PS C:\Users\P7XXTM1-G> docker run -d ubuntu /bin/sh -c "while true;do echo hello-from-ubunut;sleep 1;done"
a7e9449469b287e1cfc7c2768fa66c19113135421659568ca4da14b9ac9bcdd3
PS C:\Users\P7XXTM1-G> docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a7e9449469b2 ubuntu "/bin/sh -c 'while t…" 8 seconds ago Up 7 seconds great_chaum
PS C:\Users\P7XXTM1-G> docker top a7e9449469b2
UID PID PPID C STIME TTY TIME CMD
root 1720 1699 0 05:59 ? 00:00:00 /bin/sh -c while true;do echo hello-from-ubunut;sleep 1;done
root 1777 1720 0 06:00 ? 00:00:00 sleep 1
PS C:\Users\P7XXTM1-G>
docker inspect 容器id
查看容器信息。
PS C:\Users\P7XXTM1-G> docker run -d ubuntu
1147368a1740a8a9367f550447faa808bbf8fe3eb43a3fb5d890f88153ee2e80
PS C:\Users\P7XXTM1-G> docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1147368a1740 ubuntu "/bin/bash" 18 seconds ago Exited (0) 17 seconds ago naughty_engelbart
PS C:\Users\P7XXTM1-G> docker inspect 1147368a1740
[
{
"Id": "1147368a1740a8a9367f550447faa808bbf8fe3eb43a3fb5d890f88153ee2e80",
"Created": "2021-03-18T06:04:28.0414634Z",
"Path": "/bin/bash",
"Args": [],
"State": {
"Status": "exited",
"Running": false,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 0,
"ExitCode": 0,
"Error": "",
"StartedAt": "2021-03-18T06:04:28.2739845Z",
"FinishedAt": "2021-03-18T06:04:28.2748083Z"
},
"Image": "sha256:4dd97cefde62cf2d6bcfd8f2c0300a24fbcddbe0ebcd577cc8b420c29106869a",
"ResolvConfPath": "/var/lib/docker/containers/1147368a1740a8a9367f550447faa808bbf8fe3eb43a3fb5d890f88153ee2e80/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/1147368a1740a8a9367f550447faa808bbf8fe3eb43a3fb5d890f88153ee2e80/hostname",
"HostsPath": "/var/lib/docker/containers/1147368a1740a8a9367f550447faa808bbf8fe3eb43a3fb5d890f88153ee2e80/hosts",
"LogPath": "/var/lib/docker/containers/1147368a1740a8a9367f550447faa808bbf8fe3eb43a3fb5d890f88153ee2e80/1147368a1740a8a9367f550447faa808bbf8fe3eb43a3fb5d890f88153ee2e80-json.log",
"Name": "/naughty_engelbart",
"RestartCount": 0,
"Driver": "overlay2",
"Platform": "linux",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "",
"ExecIDs": null,
......
}
]
docker exec -it 容器id 终端地址
进入当前正在运行的容器,
开启新终端
。
常用的终端地址:
- /bin/bash(常用)
- /bin/sh
PS C:\Users\P7XXTM1-G> docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4172c4f6f390 ubuntu "/bin/bash" 7 seconds ago Up 5 seconds eloquent_bohr
PS C:\Users\P7XXTM1-G> docker exec -it 4172c4f6f390 /bin/bash
root@4172c4f6f390:/# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 06:11 pts/0 00:00:00 /bin/bash
root 10 0 0 06:12 pts/1 00:00:00 /bin/bash
root 19 10 0 06:12 pts/1 00:00:00 ps -ef
root@4172c4f6f390:/#
docker attach 容器id
进入当前正在运行的容器,但
不会开启新终端
,会继续以前终端的操作
PS C:\Users\P7XXTM1-G> docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4172c4f6f390 ubuntu "/bin/bash" About a minute ago Up About a minute eloquent_bohr
PS C:\Users\P7XXTM1-G> docker attach 4172c4f6f390
正在运行的终端指令......
docker cp 容器id:/容器目录 本地目录
从容器(无论容器是否运行)中将文件拷贝到外部。
ubuntu@DESKTOP-5IG459O:~$ docker run -it ubuntu /bin/bash
root@0619c363583e:/# ls
bin boot dev etc home lib lib32 lib64 libx32 media mnt opt proc root run sbin srv sys tmp usr var
root@0619c363583e:/# cd home/
root@0619c363583e:/home# ls
# 在容器中新建一个测试用的 test.file
root@0619c363583e:/home# touch test.file
root@0619c363583e:/home# ls
test.file
root@0619c363583e:/home# exit
exit
# 查看容器id
ubuntu@DESKTOP-5IG459O:~$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0619c363583e ubuntu "/bin/bash" 25 seconds ago Exited (0) 3 seconds ago optimistic_cartwright
# 将容器中的文件拷贝到本地(由于我未将 Docker 加入用户组,故在使用 Docker 的部分命令时需使用 sudo 权限)
ubuntu@DESKTOP-5IG459O:~$ sudo docker cp 0619c363583e:/home/test.file /home
# 查看 Docker 容器中的文件是否已拷贝到本地目录下
ubuntu@DESKTOP-5IG459O:~$ ls
ubuntu@DESKTOP-5IG459O:~$ cd /home/
ubuntu@DESKTOP-5IG459O:/home$ ls
test.file ubuntu
ubuntu@DESKTOP-5IG459O:/home$
docker commit
生成本地 Docker 自定义镜像。
常用可选参数 | 说明 |
---|---|
-a | 提交镜像作者 |
-m | 提交镜像信息 |
这里我们制作一个带有 Vim 编辑器的 Ubuntu 镜像(ubuntu-vim),并通过 docker commit 命令制作一个本地镜像。
当我们尝试对 Ubuntu 镜像添加软件或对一些系统配置进行修改时,我们就生成了一个属于自己的自定义镜像,通过使用自定义镜像,我们可以对日常工作时的项目进行客制化修改,并可以省去大部分需要因为配置开发环境与部署环境的高度重合的工作,
只需要对自定义镜像进行二次修改,即可满足需求再次上线。
docker commit -a "Peter Chen" -m "Add Vim" c79bc37440d2 ubuntu-vim
sha256:8e9d1c74cd2404d7c006c5f7074b1f00b61f8c10a22044ab5b24da68c34a67ae
ubuntu@DESKTOP-5IG459O:~$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu-vim latest 8e9d1c74cd24 4 seconds ago 168MB
ubuntu latest 4dd97cefde62 2 weeks ago 72.9MB
mysql latest c8562eaf9d81 2 months ago 546MB
redis latest 621ceef7494a 2 months ago 104MB
tomcat latest 040bdb29ab37 2 months ago 649MB
nginx latest f6d0b4767a6c 2 months ago 133MB
portainer/portainer-ce latest 980323c8eb3f 2 months ago 196MB
centos latest 300e315adb2f 3 months ago 209MB
kibana latest a674d23325b0 2 years ago 388MB
elasticsearch latest 5acf0e8da90b 2 years ago 486MB
ubuntu@DESKTOP-5IG459O:~$
Docker 命令简单应用
部署 Nginx
WSL2
下通过 Docker 命令部署Nginx
,通过端口映射到主机上的80
端口,并通过curl
命令对该端口内容进行查看。
Nginx 默认端口:80
ubuntu@DESKTOP-5IG459O:~$ docker run -d --name Nginx -p 80:80 nginx
ae4f49240c2af6e20faa786a8fc144b78aacb6c7625ff11cf7ea39e67193ac22
ubuntu@DESKTOP-5IG459O:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ae4f49240c2a nginx "/docker-entrypoint.…" 5 seconds ago Up 3 seconds 0.0.0.0:80->80/tcp Nginx
ubuntu@DESKTOP-5IG459O:~$ curl localhost:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
部署 Tomcat
WSL2
下通过 Docker 命令部署Tomcat
,通过端口映射到主机上的8080
端口,并通过curl
命令对该端口内容进行查看。
Tomcat 默认端口:8080
ubuntu@DESKTOP-5IG459O:~$ docker run -d --name Tomcat -p 8080:8080 tomcat
1d5186fd99fae677916b5ddb7012a3277881bfefd8ee7da762b264b3aca05ddd
ubuntu@DESKTOP-5IG459O:~$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1d5186fd99fa tomcat "catalina.sh run" 4 seconds ago Up 4 seconds 0.0.0.0:8080->8080/tcp Tomcat
ubuntu@DESKTOP-5IG459O:~$ curl localhost:8080
<!doctype html><html lang="en"><head><title>HTTP Status 404 – Not Found</title><style type="text/css">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 404 – Not Found</h1><hr class="line" /><p><b>Type</b> Status Report</p><p><b>Description</b> The origin server did not find a current representation for the target resource or is not willing to disclose that one exists.</p><hr class="line" /><h3>Apache Tomcat/9.0.41</h3></body></html>
ubuntu@DESKTOP-5IG459O:~$
在这里我们会感受到 Docker 镜像的最小化体验,即我们通过 curl 命令直接访问是会报 404的,这是因为 Docker 的镜像通常只包含最小运行环境,会省去大量无用的资源。
在进入容器后,我们会发现 Tomcat 中的 webapps 文件夹目录下并无任何东西。
ubuntu@DESKTOP-5IG459O:~$ docker exec -it Tomcat /bin/bash
root@1d5186fd99fa:/usr/local/tomcat# whereis tomcat
tomcat: /usr/local/tomcat
root@1d5186fd99fa:/usr/local/tomcat# cd /usr/local/tomcat/
root@1d5186fd99fa:/usr/local/tomcat# ls
BUILDING.txt LICENSE README.md RUNNING.txt conf logs temp webapps.dist
CONTRIBUTING.md NOTICE RELEASE-NOTES bin lib native-jni-lib webapps work
root@1d5186fd99fa:/usr/local/tomcat# cd webapps
root@1d5186fd99fa:/usr/local/tomcat/webapps# ls
root@1d5186fd99fa:/usr/local/tomcat/webapps#
通过翻阅资料,我们可以知道:Tomcat 镜像会将原有 webapps 文件夹下的文件删除,如需要恢复则可通过将 webapps.dist 文件夹下的文件拷贝到 webapps 文件夹解决。
root@1d5186fd99fa:/usr/local/tomcat# cp -r webapps.dist/* webapps
root@1d5186fd99fa:/usr/local/tomcat# cd webapps
root@1d5186fd99fa:/usr/local/tomcat/webapps# ls
ROOT docs examples host-manager manager
root@1d5186fd99fa:/usr/local/tomcat/webapps#
ubuntu@DESKTOP-5IG459O:~$ curl localhost:8080
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Apache Tomcat/9.0.41</title>
<link href="favicon.ico" rel="icon" type="image/x-icon" />
<link href="tomcat.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="wrapper">
<div id="navigation" class="curved container">
<span id="nav-home"><a href="https://tomcat.apache.org/">Home</a></span>
<span id="nav-hosts"><a href="/docs/">Documentation</a></span>
<span id="nav-config"><a href="/docs/config/">Configuration</a></span>
<span id="nav-examples"><a href="/examples/">Examples</a></span>
<span id="nav-wiki"><a href="https://wiki.apache.org/tomcat/FrontPage">Wiki</a></span>
<span id="nav-lists"><a href="https://tomcat.apache.org/lists.html">Mailing Lists</a></span>
<span id="nav-help"><a href="https://tomcat.apache.org/findhelp.html">Find Help</a></span>
<br class="separator" />
</div>
<div id="asf-box">
<h1>Apache Tomcat/9.0.41</h1>
</div>
......
</body>
</html>
部署 Elasticsearch
WSL2
下通过 Docker 命令部署Elasticsearch
,通过端口映射到主机上的9200
端口,并通过curl
命令对该端口内容进行查看。
Elasticsearch 默认端口:9200
ubuntu@DESKTOP-5IG459O:~$ docker run -d --name Elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:latest
9e8cb66f41446d40ec2ce3dd8bd1aab7189e9c37daf5233795e25926bece5587
ubuntu@DESKTOP-5IG459O:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9e8cb66f4144 elasticsearch:latest "/docker-entrypoint.…" 4 seconds ago Up 2 seconds 0.0.0.0:9200->9200/tcp, 0.0.0.0:9300->9300/tcp Elasticsearch
ubuntu@DESKTOP-5IG459O:~$ curl localhost:9200
{
"name" : "03-Xaze",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "afbJDcPlTJuv2-FI0n7rIA",
"version" : {
"number" : "5.6.12",
"build_hash" : "cfe3d9f",
"build_date" : "2018-09-10T20:12:43.732Z",
"build_snapshot" : false,
"lucene_version" : "6.6.1"
},
"tagline" : "You Know, for Search"
}
ubuntu@DESKTOP-5IG459O:~$ docker status
docker: 'status' is not a docker command.
See 'docker --help'
ES 默认会占用大量内存,若想通过修改配置的方式对 ES 进行配置,可追加 -e [参数],对其进行环境配置。
此处我们将 ES 的内存限制为最小内存 64m,最大内存 1024m。
ubuntu@DESKTOP-5IG459O:~$ docker run -d --name Elasticsearch -p 9200:9200 -p 9300:9300 -e "-Xms=64m -Xmx=1024m" elasticsearch:latest
021abaaf2148248188c8add919576895dc9d61bca8834601d4947058616ce1ec
ubuntu@DESKTOP-5IG459O:~$ docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
021abaaf2148 Elasticsearch 0.17% 2.22GiB / 12.44GiB 17.84% 696B / 0B 0B / 0B 43
可视化管理工具
Portiner
官方地址:Portiner
Portiner 默认端口:9000
ubuntu@DESKTOP-5IG459O:~$ docker run -d -p 9000:9000 --name=Portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce
a60bf182bf76b2ce5971cb47da02c6be15d4132b37364bf63987e98079195d30
ubuntu@DESKTOP-5IG459O:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a60bf182bf76 portainer/portainer-ce "/portainer" 2 seconds ago Up 2 seconds 8000/tcp, 0.0.0.0:9000->9000/tcp Portainer
ubuntu@DESKTOP-5IG459O:~$
Portainer 显示效果
容器数据卷
原理
当我们想要通过 Docker 进行数据持久化存储的时候,若我们将数据全部存放于 Docker 容器中,则当我们删除容器时,容器中的数据也就被我们一并删除,也就是通俗意义上讲的“删库跑路”。
现实中为了防止此类事情发生,通常可以通过容器数据卷技术,将容器中的目录挂载到外部目录(这个外部目录通常是当前计算机上的物理地址)。即:双向绑定,容器的持久化和同步操作,即使 Docker 中各个容器间互相隔离,但容器间也是可以数据共享的。
docker run -it -v 主机目录:容器内目录
在这里我们尝试将本地 Ubuntu WSL2 虚拟机上的目录挂载到 Docker 中新建的 Ubuntu 容器上。
本地挂载目录:/home/test,若本地无此目录,则 Docker 会帮助创建。
容器挂载目录:/home
ubuntu@DESKTOP-5IG459O:~$ docker run -it -v /home/test:/home ubuntu /bin/bash
通过 docker inspect,我们可以检查容器挂载信息。
ubuntu@DESKTOP-5IG459O:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
562e4b3c9d92 ubuntu "/bin/bash" 6 minutes ago Up 6 minutes nervous_darwin
ubuntu@DESKTOP-5IG459O:~$ docker inspect 562e4b3c9d92
[
{
"Id": "562e4b3c9d92cc41642ccaf6e4883ec328a9df205b0ea2d6c00e54fab253e42e",
"Created": "2021-03-23T01:33:55.8844317Z",
"Path": "/bin/bash",
"Args": [],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 1277,
"ExitCode": 0,
"Error": "",
"StartedAt": "2021-03-23T01:33:56.1845627Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
......
"Mounts": [
{
"Type": "bind",
"Source": "/home/test", # 容器内的挂载目录
"Destination": "/home", # 容器外的挂载目录
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],
......
}
]
ubuntu@DESKTOP-5IG459O:~$
测试 MySQL 数据
这里我们测试将容器中的 MySQL 配置文件挂载到外部,并将数据目录也挂载到外部,防止因为误删容器而导致的数据丢失。
建立一个通过 3306 端口映射到本地,配置文件与数据文件目录挂载到本地,MySQL root 账户密码为 root,容器名为 testMySQL 的 MySQL 容器。
本地挂载配置文件目录:/home/mysql/conf
容器配置文件目录:/etc/mysql/conf.d
本地挂载数据目录:/home/mysql/data
容器数据目录:/var/lib/mysql
ubuntu@DESKTOP-5IG459O:~$ docker run -d -p 3306:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root --name testMySQL mysql:latest
ubuntu@DESKTOP-5IG459O:~$ cd /home/
ubuntu@DESKTOP-5IG459O:/home$ ls
mysql ubuntu
ubuntu@DESKTOP-5IG459O:/home$ cd mysql/
ubuntu@DESKTOP-5IG459O:/home/mysql$ ls
conf data
ubuntu@DESKTOP-5IG459O:/home/mysql$ cd data/
ubuntu@DESKTOP-5IG459O:/home/mysql/data$ ls
'#ib_16384_0.dblwr' auto.cnf binlog.index client-cert.pem ib_logfile0 ibtmp1 performance_schema server-cert.pem undo_001
'#ib_16384_1.dblwr' binlog.000001 ca-key.pem client-key.pem ib_logfile1 mysql private_key.pem server-key.pem undo_002
'#innodb_temp' binlog.000002 ca.pem ib_buffer_pool ibdata1 mysql.ibd public_key.pem sys
# 这里我们通过 DataGrip,对映射出来的本地 3306 进行控制,并添加一个 test 表。
ubuntu@DESKTOP-5IG459O:/home/mysql/data$ ls
'#ib_16384_0.dblwr' auto.cnf binlog.index client-cert.pem ib_logfile0 ibtmp1 performance_schema server-cert.pem test
'#ib_16384_1.dblwr' binlog.000001 ca-key.pem client-key.pem ib_logfile1 mysql private_key.pem server-key.pem undo_001
'#innodb_temp' binlog.000002 ca.pem ib_buffer_pool ibdata1 mysql.ibd public_key.pem sys undo_002
ubuntu@DESKTOP-5IG459O:/home/mysql/data$ docker run -d -it /bin/bash mysql
假设我们删除容器,挂载目录中的数据文件也不会丢失。
ubuntu@DESKTOP-5IG459O:/home/mysql$ docker stop testMySQL
ubuntu@DESKTOP-5IG459O:/home/mysql$ docker rm testMySQL
testMySQL
ubuntu@DESKTOP-5IG459O:/home/mysql$ cd data/
ubuntu@DESKTOP-5IG459O:/home/mysql/data$ ls
'#ib_16384_0.dblwr' auto.cnf binlog.index client-cert.pem ib_logfile0 mysql private_key.pem server-key.pem undo_002
'#ib_16384_1.dblwr' binlog.000001 ca-key.pem client-key.pem ib_logfile1 mysql.ibd public_key.pem sys
'#innodb_temp' binlog.000002 ca.pem ib_buffer_pool ibdata1 performance_schema server-cert.pem undo_001
ubuntu@DESKTOP-5IG459O:/home/mysql/data$
PS:这里有一个
暂时未解决
的问题,即 Docker 的容器数据卷挂载会将本地目录覆盖容器内目录,即会隐藏容器内的文件。
ubuntu@DESKTOP-5IG459O:~$ docker exec -it testMySQL /bin/bash
root@a0a84f3635e0:/# whereis mysql
mysql: /usr/bin/mysql /usr/lib/mysql /etc/mysql
root@a0a84f3635e0:/# cd /etc/mysql/
root@a0a84f3635e0:/etc/mysql# ls
conf.d my.cnf my.cnf.fallback
root@a0a84f3635e0:/etc/mysql# cd conf.d/
root@a0a84f3635e0:/etc/mysql/conf.d# ls
root@a0a84f3635e0:/etc/mysql/conf.d#
匿名挂载
当我们尝试创建 Docker 容器卷时,若不指定容器卷的卷名直接挂载外部目录,就是匿名挂载。
这里我们生成一个测试用的 Nginx 容器,并通过匿名挂载方式
,挂载 Nginx 的配置文件目录。
docker run -d -P --name AnonymousMountNginx -v /etc/nginx nginx
1cbff8ab5b4c295384d1d0a508a6d828997cca6e992c5416fbc9c9668367c957
ubuntu@DESKTOP-5IG459O:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1cbff8ab5b4c nginx "/docker-entrypoint.…" 2 seconds ago Up 2 seconds 0.0.0.0:49153->80/tcp AnonymousMountNginx
docker volume … 命令是 Docker 的容器卷管理命令。
# 通过 docker volume ls 命令可查看当前 Docker 中的容器卷
# 未指定名字的就是匿名挂载卷(这里是43145ccdd2df15993af6a2077e044a8089e003b5a4e564be8dad03162aa8816b)
ubuntu@DESKTOP-5IG459O:~$ docker volume ls
DRIVER VOLUME NAME
local 43145ccdd2df15993af6a2077e044a8089e003b5a4e564be8dad03162aa8816b
# 通过 docker volume inspect [容器卷名]
docker volume inspect 43145ccdd2df15993af6a2077e044a8089e003b5a4e564be8dad03162aa8816b
[
{
"CreatedAt": "2021-03-23T06:39:05Z",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/43145ccdd2df15993af6a2077e044a8089e003b5a4e564be8dad03162aa8816b/_data",
"Name": "43145ccdd2df15993af6a2077e044a8089e003b5a4e564be8dad03162aa8816b",
"Options": null,
"Scope": "local"
}
]
ubuntu@DESKTOP-5IG459O:~$
Windows10 WSL2 Ubuntu20.04中的镜像位置:
\wsl$\docker-desktop-data\version-pack-data\community\docker\volumes
具名挂载
这里我们生成一个测试用的 Nginx 容器,并通过具名挂载方式
,挂载 Nginx 的配置文件目录。
ubuntu@DESKTOP-5IG459O:/mnt/c/Users/P7XXTM1-G$ docker run -d -P --name NamedMountNginx -v named-nginx-volume:/etc/nginx nginx
fa91bb3dd49f476874d99a1e1199ecf24dd309d4240535611156b6dc5f5ab10a
ubuntu@DESKTOP-5IG459O:/mnt/c/Users/P7XXTM1-G$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fa91bb3dd49f nginx "/docker-entrypoint.…" 5 seconds ago Up 4 seconds 0.0.0.0:49153->80/tcp NamedMountNginx
ubuntu@DESKTOP-5IG459O:/mnt/c/Users/P7XXTM1-G$ docker volume ls
DRIVER VOLUME NAME
local 43145ccdd2df15993af6a2077e044a8089e003b5a4e564be8dad03162aa8816b
local named-nginx-volume
ubuntu@DESKTOP-5IG459O:/mnt/c/Users/P7XXTM1-G$ docker volume inspect named-nginx-volume
[
{
"CreatedAt": "2021-03-25T02:31:48Z",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/named-nginx-volume/_data",
"Name": "named-nginx-volume",
"Options": null,
"Scope": "local"
}
]
ubuntu@DESKTOP-5IG459O:/mnt/c/Users/P7XXTM1-G$
区分
匿名挂载
-v 容器内路径
具名挂载
-v 卷名:容器内路径
指定路径挂载(普通挂载,也是匿名挂载)
-v /宿主机路径:容器内路径
读写权限
通过 -v 容器内路径:ro 或 rw 改变读写权限
- ro read-only # 只读
- rw read-and-write # 可读写
# ro
docker run -d -P --name NamedMountNginx -v named-nginx-volume:/etc/nginx:ro nginx
# rw
docker run -d -P --name NamedMountNginx -v named-nginx-volume:/etc/nginx:rw nginx
Docker File
即用来构建 Docker 镜像的构建文件。
编写脚本
创建 Docker File。
ubuntu@DESKTOP-5IG459O:~$ mkdir Test-Docker-File
ubuntu@DESKTOP-5IG459O:~$ ls
Test-Docker-File
ubuntu@DESKTOP-5IG459O:~$ cd Test-Docker-File/
ubuntu@DESKTOP-5IG459O:~/Test-Docker-File$ vim docker-file
docker-file 文件中的内容
通过编辑该文件,对 Docker 镜像进行客制化。
FROM ubuntu
VOLUME ["volume1", "volume2"]
CMD echo "---BUILD END---"
CMD /bin/bash
docker build
ubuntu@DESKTOP-5IG459O:~/Test-Docker-File$ docker build -f /home/ubuntu/Test-Docker-File/docker-file -t custom/ubuntu .
[+] Building 0.2s (5/5) FINISHED
=> [internal] load build definition from docker-file 0.0s
=> => transferring dockerfile: 123B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/ubuntu:latest 0.0s
=> [1/1] FROM docker.io/library/ubuntu 0.1s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:5212c89e92e63e84857aa6cb946d18b0e161adfb9a606ff1762e174d299aac57 0.0s
=> => naming to docker.io/custom/ubuntu 0.0s
ubuntu@DESKTOP-5IG459O:~/Test-Docker-File$
查看构建完成后的镜像
ubuntu@DESKTOP-5IG459O:~/Test-Docker-File$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest 4dd97cefde62 3 weeks ago 72.9MB
custom/ubuntu latest 5212c89e92e6 3 weeks ago 72.9MB
检查生成的镜像
ubuntu@DESKTOP-5IG459O:~/Test-Docker-File$ docker run -it custom/ubuntu /bin/bash
root@3e8bb3cc0c7a:/# ls -l
total 56
lrwxrwxrwx 1 root root 7 Feb 17 01:04 bin -> usr/bin
drwxr-xr-x 2 root root 4096 Apr 15 2020 boot
...
# 这里是我们在之前脚本中挂载的容器数据卷
drwxr-xr-x 2 root root 4096 Mar 29 13:55 volume1
drwxr-xr-x 2 root root 4096 Mar 29 13:55 volume2
root@3e8bb3cc0c7a:/#
我们在 volume1 文件夹中创建一个测试文件 testFile。
通过 docker inspect 命令,检查用客制化镜像所生成的容器
。
通过检查 Windows 中的 Docker Volume文件夹,验证我们创建的容器的正确性。
数据卷容器(待完善)
当容器与容器之间需要同步数据的时候,一般使用数据卷容器进行挂载。
使用场景示例:多个 MySQL 同步数据。
类似 Windows 中的共享文件夹
步骤:
- 创建父容器
- 通过 –volumes-from 命令,将子容器挂载到父容器
创建父容器
ubuntu@DESKTOP-5IG459O:~$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
custom/ubuntu latest 715329a7458b 5 weeks ago 72.9MB
ubuntu latest 4dd97cefde62 5 weeks ago 72.9MB
# 运行我们刚才创建的自定义容器,并运行,可以看到 VOLUME01 与 VOLUME02 为自定义容器中默认挂载的两个容器。
ubuntu@DESKTOP-5IG459O:~$ docker run -it --name Docker-Host custom/ubuntu
root@0d03cf71815e:/# ls -l
total 56
drwxr-xr-x 2 root root 4096 Apr 12 08:41 VOLUME01
drwxr-xr-x 2 root root 4096 Apr 12 08:41 VOLUME02
lrwxrwxrwx 1 root root 7 Feb 17 01:04 bin -> usr/bin
drwxr-xr-x 2 root root 4096 Apr 15 2020 boot
...
root@0d03cf71815e:/#
创建子容器
–volumes-from
# 查看正在运行中的父容器。
ubuntu@DESKTOP-5IG459O:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0d03cf71815e custom/ubuntu "/bin/sh -c /bin/bash" 2 minutes ago Up 2 minutes Docker-Host
# 通过 --volumes-from 命令,指定子容器所要继承的父容器。
ubuntu@DESKTOP-5IG459O:~$ docker run -it --name Docker-Child01 --volumes-from Docker-Host custom/ubuntu
# 运行子容器,可以看到挂载到父容器的 VOLUME01 与 VOLUME02 卷。
root@2864c4f3b8ba:/# ls -l
total 56
drwxr-xr-x 2 root root 4096 Apr 12 08:41 VOLUME01
drwxr-xr-x 2 root root 4096 Apr 12 08:41 VOLUME02
lrwxrwxrwx 1 root root 7 Feb 17 01:04 bin -> usr/bin
drwxr-xr-x 2 root root 4096 Apr 15 2020 boot
...
root@2864c4f3b8ba:/#
创建多个子容器,当我们在子容器中进行文件的修改,父容器也会同步。
PS:
只要有一个容器尚在,容器中的文件都不会被删除。
容器创建时使用的镜像已挂载了两个卷(VOLUME01 与 VOLUME02),所以是肯定有两个目录的,跟数据卷容器没关系。
–volumes-from 不是同步所有目录,而是同步挂载点,这就是同步 Docker-Child01 与 Docker-Child02,但在其他目录是不会同步的。