一、Docker镜像
1、什么是Docker镜像?
- 镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的有内容,包括代码、运行时、库、环境变量和配置文件。
2、UnionFS(联合文件系统)
- Union文件系统(UnionFS)是一一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一 次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。
- 镜像可以通过分层来进行继承,基于基础镜像(没有父镜像)可以制作各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录
3、镜像加载原理
- Docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统是UnionFS联合文件系统。
bootfs:
主要包含bootloader和kernel, bootloader主要是引导加载kernel, Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权己由bootfs转交给内核,此时系统也会卸载bootfs。
rootfs :
在bootfs之上。 包含的就是典型Linux系统中的**/dev, /proc, /bin, /etc等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu**,Centos等等。
平时安装的虚拟机的Centos都是好几个G ,但是docker这里才要200M
- 对于一个精简的OS, rootfs可 以很小,只需要包括最基本的命令、工具和程序库就可以了,因为底层直接用Host的kernel,自只需要提供rootfs就行了。
- 由此可见对于不同的linux发行版,bootfs基本是一致的,rootfs会有差别,因此不同的发行版可以公用bootfs。
- 所以虚拟机启动是分钟级的,容器是秒级的!!!
4、分层的镜像
#查看镜像分层命令
docker image inspect
重点:所有的Docker镜像都起始于一个基础镜像层,当需要进行修改或者增加新的内容的时候,就会在当前镜像层之上,创建新的镜像层。
示例:
- 假如基于Ubuntu 16.04 创建一个新的镜像,这就是新镜像的第一层;如果在该镜像中添加Python包,就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创建第三个镜像层。如下图所示:
- 在添加额外的镜像层的同时,镜像始终保持当前所有镜像的组合,例如每个镜像层包含3个文件,而镜像包含了来自两个镜像层的6个文件。
- 下图中在外部看来整个镜像只有6个文件,这是因为最上层中的文件7是文件5的一个更新版。
- 上图可以看出上层镜像层中的文件覆盖了底层镜像层中的文件,这样就使得文件的更新版作为一个新镜像层添加到镜像当中。Docker通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统。如下图所示:
5、为什么使用分层结构?
最大好处就是资源共享。
比如:有多个镜像都从相同的base镜像构建而来,那么宿主机只需在磁盘上保存一份base镜像,
同时内存中也只需加载一份base镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。
特点:
Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部,这一层通常被称为容器层,容器层之下都叫镜像层!如下图所示。
6、commit镜像
docker commit 提交容器副本使之称为一个新的镜像
docker commit -m=“提交的描述信息” -a="作者" 容器id 目标镜像名:[TAG]
案例演示:
由于默认的Tomcat镜像的webapps文件夹中没有任何内容,需要从webapps.dist中拷贝文件到webapps文件夹。
下面自行制作镜像:就是从webapps.dist中拷贝文件到webapps文件夹下,并提交该镜像作为一个新的镜像。使得该镜像默认的webapps文件夹下就有文件。具体命令如下:
#1、启动Tomcat容器
[root@hcz666 ~]# docker run -it tomcat /bin/bash
root@b5d0f2414eba:/usr/local/tomcat# cd webapps
root@b5d0f2414eba:/usr/local/tomcat/webapps# ls
root@b5d0f2414eba:/usr/local/tomcat/webapps# cd ../
#2、将webapps.dist中拷贝文件到webapps下
root@b5d0f2414eba:/usr/local/tomcat# cp -r webapps.dist/* webapps
root@b5d0f2414eba:/usr/local/tomcat# cd webapps
root@b5d0f2414eba:/usr/local/tomcat/webapps# ls
ROOT docs examples host-manager manager
#ctrl+P+Q
root@b5d0f2414eba:/usr/local/tomcat/webapps# [root@hcz666 ~]#
[root@hcz666 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b5d0f2414eba tomcat "/bin/bash" About a minute ago Up About a minute 8080/tcp stoic_ramanujan
[root@hcz666 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b5d0f2414eba tomcat "/bin/bash" 9 minutes ago Up 8 minutes 8080/tcp stoic_ramanujan
[root@hcz666 ~]# docker exec -it b5d0f2414eba /bin/bash
root@b5d0f2414eba:/usr/local/tomcat# cd webapps
root@b5d0f2414eba:/usr/local/tomcat/webapps# ls
ROOT docs examples host-manager manager
root@b5d0f2414eba:/usr/local/tomcat/webapps# cd ../
#ctrl+P+Q
root@b5d0f2414eba:/usr/local/tomcat# read escape sequence
[root@hcz666 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b5d0f2414eba tomcat "/bin/bash" 20 minutes ago Up 20 minutes 8080/tcp stoic_ramanujan
#3、提交镜像作为一个新的镜像
[root@hcz666 ~]# docker commit -m="add webapps" -a="hcz" b5d0f2414eba mytomcat:1.0
sha256:924ea2a2ebdfd7e1d96e5b0ef038177dff0d3ed0ebb36f9711c0b061757ca511
[root@hcz666 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mytomcat 1.0 924ea2a2ebdf 15 seconds ago 673MB
tomcat latest 266d1269bb29 11 days ago 668MB
nginx latest dd34e67e3371 12 days ago 133MB
mysql 8.0 5a4e492065c7 12 days ago 514MB
mysql latest 5a4e492065c7 12 days ago 514MB
portainer/portainer latest 580c0e4e98b0 5 months ago 79.1MB
hello-world latest d1165f221234 5 months ago 13.3kB
centos latest 300e315adb2f 8 months ago 209MB
#4、运行新的容器
[root@hcz666 ~]# docker run -it mytomcat:1.0 /bin/bash
root@eb6d0213cc42:/usr/local/tomcat# cd webapps
root@eb6d0213cc42:/usr/local/tomcat/webapps# ls
ROOT docs examples host-manager manager
root@eb6d0213cc42:/usr/local/tomcat/webapps# [root@hcz666 ~]#
[root@hcz666 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
eb6d0213cc42 mytomcat:1.0 "/bin/bash" 17 seconds ago Up 15 seconds 8080/tcp condescending_mirzakhani
b5d0f2414eba tomcat "/bin/bash" 23 minutes ago Up 23 minutes 8080/tcp stoic_ramanujan
二、Docker容器数据卷
1、数据卷
(1)数据卷是什么?
先来看看Docker的理念:
将运用与运行的环境打包形成容器运行,运行可以伴随着容器,但是我们对数据的要求希望是持久化的,容器之间希望有可能共享数据。
Docker容器产生的数据,如果不通过docker commit生成新的镜像,使得数据做为镜像的一部分保存下来,那么当容器删除后,数据自然也就没有了。为了能保存数据在docker中我们使用卷。|
(2)数据卷能干嘛?
概述:
卷就是目录或文件,卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此Docker不会在容器删除时删除其挂载的数据卷。
特点:
数据卷可在容器之间共享或重用数据
卷中的更改可以直接生效
数据卷中的更改不会包含在镜像的更新中
数据卷的生命周期一直持续到没有容器使用它为止
总结:
容器的持久化
容器间继承+共享数据
(3)数据卷怎么样使用?
方式一:直接使用命令添加(-v)
#添加命令
docker run -it -v /主机目录:/容器内目录 镜像名
#挂载命令
docker inspect 容器id
示例:
1、使用命令进行添加
#在第一个会话中
#使主机上的/home/demo目录和容器的/home目录进行挂载
[root@hcz666 ~]# docker run -it -v /home/demo:/home centos /bin/bash
[root@c3e071951e83 /]# cd /home
[root@c3e071951e83 home]# ls
[root@c3e071951e83 home]#
2、查看数据卷是否挂载成功
#在第二个会话中
[root@hcz666 ~]# cd /home #进入主机的/home目录下
[root@hcz666 home]# ls #发现demo文件夹已经挂载过来了
demo demo.java hcz hcz1.txt hcz666 hcz.txt hilde lighthouse test2 www zsx
[root@hcz666 home]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c3e071951e83 centos "/bin/bash" 2 minutes ago Up 2 minutes dazzling_blackwell
eb6d0213cc42 mytomcat:1.0 "/bin/bash" 22 hours ago Up 22 hours 8080/tcp condescending_mirzakhani
b5d0f2414eba tomcat "/bin/bash" 23 hours ago Up 23 hours 8080/tcp stoic_ramanujan
3a5b0d6c5f23 tomcat "catalina.sh run" 42 hours ago Up 22 hours 0.0.0.0:6656->8080/tcp, :::6656->8080/tcp tomcat01
#查看挂载是否成功
[root@hcz666 home]# docker inspect c3e071951e83
[
{
"Id": "c3e071951e83a6c192a36e15d1ea4a1a669c7e15247972bf330c1ea9bbb0c6e2",
"Created": "2021-08-30T23:33:28.235392277Z",
"Path": "/bin/bash",
"Args": [],
3、容器和宿主机之间数据共享
- 向容器的/home目录下创建一个文件,主机的/home/demo文件夹自动同步
4、容器停止退出后,主机修改后的数据自动同步
实战:Mysql数据持久化
1、使用命令进行添加
#创建容器命令
[root@hcz666 home]# docker run -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=123456 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql --name mysql03 mysql:8.0
-----------------------------------------
#命令说明:
-p(端口映射) 12345:3306:将主机的3307端口映射到docker容器的3306端口。
--name(容器名字) mysq:运行服务名字
-v(数据卷) /home/mysql/conf:/etc/mysql/conf.d :将主机/home/mysql录下的conf挂载到容器的/etc/mysql/conf.d
/home/mysql/data:/var/lib/mysql :将主机/home/mysql目录下的data目录挂载到容器的/var/lib/mysql
-e(环境配置) MYSQL_ ROOT_ PASSWORD=123456: 初始化root用户的密码。
-d(后台运行) mysql:8.0:后台程序运行mysql8.0
2、查看数据卷是否挂载成功
3、连接本地Navicat进行测试
具体可以看:[Docker03:Docker常用安装实例_hcz666的博客-CSDN博客]
4、在本地连接创建一个test数据库,查看一下主机中是否有同步
5、删除容器,挂载在本地的数据卷依旧没有丢失
拓展:具名挂载和匿名挂载
匿名挂载:
#匿名挂载:就只是写了容器内的路径,没有写宿主机的路径
-v 容器内路径
[root@hcz666 home]# docker run -d -P --name nginx03 -v /etc/nginx nginx
61072689ca5ad9625cf16a05b253b54e9afd3dc0a6656a7aed9289fe075d0360
#查看所有的volume的情况
[root@hcz666 home]# docker volume ls
DRIVER VOLUME NAME
local 117c36fa03f7f9604ed1614b2ac4742dc01fd52411ecf4d1ed80c53fbb934d85
local b9a3f1325dbcc6b6ef1195b4cec7b3ac5cdabad1812fa59f3cf542817d4a7274
local c71af64016a451112d65039f46e3dc6feaf735e1e7653dbfe99e4bcff4bf347c
local e7134e61b7e023a3f2bcebf970459f61f4cc5048d4448322f65377027b8cdb98
local ee6f64526d36c075c785979e0080d80dec4dc56a876419c2b030e70c5edfa107
[root@hcz666 home]#
具名挂载:
#具名挂载:就只是写了卷名和容器内的路径,同样也没有写宿主机的路径
-v 卷名 容器内路径
[root@hcz666 home]# docker run -d -P --name nginx05 -v juming-ngnix:/etc/nginx nginx
5e19716b3dc56ce655dc2bdf189f7eccc96ad332da2cee1536d2d89bb44f0219
[root@hcz666 home]# docker volume ls
DRIVER VOLUME NAME
local 0b0093b3473bc17c1349bf713fdca0810e08d11509bae2e73ac0df3cf1413197
local 117c36fa03f7f9604ed1614b2ac4742dc01fd52411ecf4d1ed80c53fbb934d85
local b9a3f1325dbcc6b6ef1195b4cec7b3ac5cdabad1812fa59f3cf542817d4a7274
local c71af64016a451112d65039f46e3dc6feaf735e1e7653dbfe99e4bcff4bf347c
local e7134e61b7e023a3f2bcebf970459f61f4cc5048d4448322f65377027b8cdb98
local ee6f64526d36c075c785979e0080d80dec4dc56a876419c2b030e70c5edfa107
local juming-ngnix
#查看这个卷名
[root@hcz666 home]# docker volume inspect juming-ngnix
[
{
"CreatedAt": "2021-08-31T09:25:40+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/juming-ngnix/_data",
"Name": "juming-ngnix",
"Options": null,
"Scope": "local"
}
]
[root@hcz666 home]#
所有的docker容器内的卷,如果没有指定宿主机目录的情况下,默认都是在路径下:/var/lib/docker/volumes/juming-ngnix/_data"
区别:
#如何确定是具名挂载还是匿名挂载,还是指定路径挂载
-v 容器内路径 #具体挂载
-v 卷名:容器内路径 #具名挂载
-v /宿主机路径:容器内路径 #指定路径挂载
方式二:DockerFile添加
#可以在DockerFile中使用VOLUME指令来给镜像添加一个或多个数据卷
VOLUME ["volume01","volume02"] #这里属于匿名挂载
#说明:
- 出于可移植和分享的目的,只用方式一不能够直接在DockerFile中实现
- 由于宿主机目录是依赖于特定宿主机的,并不能够保证所有的宿主机上都存在这样的特定的目录
示例:
1、创建自定义文件夹
[root@hcz666 home]# mkdir docker-test-volume
[root@hcz666 home]# ls
demo docker-test-volume hcz1.txt hcz.txt lighthouse test2 zsx
demo.java hcz hcz666 hilde mysql www
[root@hcz666 home]# cd docker-test-volume/
[root@hcz666 docker-test-volume]# pwd
/home/docker-test-volume
2、创建一个dockerfile文件,名字随意
#构建脚本
FROM centos
VOLUME ["volume01","volume02"] #这里属于匿名挂载
CMD echo "--------finished--------"
CMD /bin/bash
3、build后生成镜像
#构建自定义镜像命令
[root@hcz666 docker-test-volume]# docker build -f /home/docker-test-volume/dockerfile -t hcz/centos:1.0 .
4、启动容器
[root@hcz666 docker-test-volume]# docker run -it 45648d270480 /bin/bash
4、查看主机对应默认的地址
[root@hcz666 _data]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
23de7c512bc1 45648d270480 "/bin/bash" 9 minutes ago Up 9 minutes magical_noyce
[root@hcz666 _data]# docker inspect 23de7c512bc1
……省略……
"Mounts": [
{
"Type": "volume",
"Name": "b0227290658396c919bccf35dca0d3cb58c9c24cb552cd4fedfab617c62ea02d",
"Source": "/var/lib/docker/volumes/b0227290658396c919bccf35dca0d3cb58c9c24cb552cd4fedfab617c62ea02d/_data",
"Destination": "volume01",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
},
{
"Type": "volume",
"Name": "30f4ff1fcc1722912bfc7528dd3e7869d88033de31a236301538b21f393a3c8e",
"Source": "/var/lib/docker/volumes/30f4ff1fcc1722912bfc7528dd3e7869d88033de31a236301538b21f393a3c8e/_data",
"Destination": "volume02",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
……省略……
5、测试数据同步
2、数据卷容器
(1)什么是数据卷容器
(2)容器间传递共享(–volumes -from)
1、先启动一个父容器docker01
[root@hcz666 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hcz/centos 1.0 45648d270480 43 minutes ago 209MB
[root@hcz666 ~]# docker run -it --name docker01 hcz/centos:1.0
[root@d93a04629b62 /]# ls -l
total 56
lrwxrwxrwx 1 root root 7 Nov 3 2020 bin -> usr/bin
drwxr-xr-x 5 root root 360 Aug 31 02:44 dev
drwxr-xr-x 1 root root 4096 Aug 31 02:44 etc
drwxr-xr-x 2 root root 4096 Nov 3 2020 home
lrwxrwxrwx 1 root root 7 Nov 3 2020 lib -> usr/lib
lrwxrwxrwx 1 root root 9 Nov 3 2020 lib64 -> usr/lib64
drwx------ 2 root root 4096 Dec 4 2020 lost+found
drwxr-xr-x 2 root root 4096 Nov 3 2020 media
drwxr-xr-x 2 root root 4096 Nov 3 2020 mnt
drwxr-xr-x 2 root root 4096 Nov 3 2020 opt
dr-xr-xr-x 131 root root 0 Aug 31 02:44 proc
dr-xr-x--- 2 root root 4096 Dec 4 2020 root
drwxr-xr-x 11 root root 4096 Dec 4 2020 run
lrwxrwxrwx 1 root root 8 Nov 3 2020 sbin -> usr/sbin
drwxr-xr-x 2 root root 4096 Nov 3 2020 srv
dr-xr-xr-x 13 root root 0 Aug 31 02:05 sys
drwxrwxrwt 7 root root 4096 Dec 4 2020 tmp
drwxr-xr-x 12 root root 4096 Dec 4 2020 usr
drwxr-xr-x 20 root root 4096 Dec 4 2020 var
drwxr-xr-x 2 root root 4096 Aug 31 02:44 volume01
drwxr-xr-x 2 root root 4096 Aug 31 02:44 volume02
- 启动后在volume01目录下新增一个文件
2、继续启动docker02和docker03容器并继承docker01
3、返回docker01查看数据
4、删除docker01、docker02修改后docker03是否能访问
5、删除docker02后docker03是否能访问
6、新建docker04继承docker03,然后删除docker03
(3)实战
多个MySQL实现数据共享
#第一个数据库
[root@hcz666 home]# docker run -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=123456 -v /etc/mysql/conf.d -v /var/lib/mysql --name mysql01 mysql:8.0
#第二个数据库
[root@hcz666 home]# docker run -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=123456 -v /etc/mysql/conf.d -v /var/lib/mysql --name mysql02 --volumes -from mysql01 mysql:8.0
#第三个数据库
[root@hcz666 home]# docker run -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=123456 -v /etc/mysql/conf.d -v /var/lib/mysql --name mysql03 --volumes -from mysql01 mysql:8.0
(4)结论
容器之间配置信息的传递,数据卷的生命周期一直持续到没有容器使用它为止;但是一旦持久化到了本地,这个时候,本地的数据是不会删除的。