1、镜像是什么
镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含 运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件。
2、docker镜像加载原理
2.1、 UnionFS (联合文件系统)
UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统, 它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系 统下(unite several directories into a single virtual filesystem)。Union 文件系统是 Docker 镜像的基 础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件 系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录
2. 2、Docker镜像加载原理
docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。
bootfs(boot file system)主要包含bootloader和kernel, bootloader主要是引导加载kernel, Linux刚启 动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs。这一层与我们典型的Linux/Unix系统是 一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已 由bootfs转交给内核,此时系统也会卸载bootfs。
rootfs (root file system) ,在bootfs之上。包含的就是典型 Linux 系统中的 /dev, /proc, /bin, /etc 等标 准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。
平时我们安装进虚拟机的CentOS都是好几个G,为什么Docker这里才200M?
对于一个精简的OS,rootfs 可以很小,只需要包含最基本的命令,工具和程序库就可以了,因为底层直 接用Host的kernel,自己只需要提供rootfs就可以了。由此可见对于不同的linux发行版, bootfs基本是一 致的, rootfs会有差别, 因此不同的发行版可以公用bootfs。
3、分层管理
当我们pull一个镜像,是一层层下载(观察日志)
思考:为什么Docker镜像要采用这种分层的结构呢?
最大的好处,我觉得莫过于是资源共享了!比如有多个镜像都从相同的Base镜像构建而来,那么宿主机 只需在磁盘上保留一份base镜像,同时内存中也只需要加载一份base镜像,这样就可以为所有的容器服 务了,而且镜像的每一层都可以被共享
可以通过命令查看镜像分层方式
[root@kuangshen home]# docker image inspect redis:latest
[
// .....
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:c2adabaecedbda0af72b153c6499a0555f3a769d52370469d8f6bd6328af9b13",
"sha256:744315296a49be711c312dfa1b3a80516116f78c437367ff0bc678da1123e990",
"sha256:379ef5d5cb402a5538413d7285b21aa58a560882d15f1f553f7868dc4b66afa8",
"sha256:d00fd460effb7b066760f97447c071492d471c5176d05b8af1751806a1f905f8",
"sha256:4d0c196331523cfed7bf5bafd616ecb3855256838d850b6f3d5fba911f6c4123",
"sha256:98b4a6242af2536383425ba2d6de033a510e049d9ca07ff501b95052da76e894"
]
},
"Metadata": {
"LastTagTime": "0001-01-01T00:00:00Z"
}
}
]
比如我们pull一个tomcat镜像,有6层镜像,pull下来之后,此时镜像都是只读的,当以此镜像新建容器启动时,一个新的可写层被加载到镜像的顶部!我们对此容器层进行一些操作(发布应用等)之后就形成了一个新的镜像,可以通过容器创建一个新的镜像进行发布
4、镜像提交
docker commit 从容器创建一个新的镜像。
docker commit 提交容器副本使之成为一个新的镜像!
# 语法
docker commit -m="提交的描述信息" -a="作者" 容器id 要创建的目标镜像名:[标签名]
测试
# 1、从Docker Hub 下载tomcat镜像到本地并运行 -it 交互终端 -p 端口映射
docker run -it -p 8080:8080 tomcat
# 2、进入tomcat容器
docker exec -it 容器id /bin/bash
# 注意:坑爹:docker启动官方tomcat镜像的容器,发现404是因为使用了加速器,而加速器里的
tomcat的webapps下没有root等文件!反而有个webapps.dist里有对应文件,cp -r
到webapps下!
root@aba865b53114:/usr/local/tomcat# cp -r webapps.dist/* webapps
此时访问已经有内容
curl localhost:8080
# 3、上面版本的tomcat和官网tomcat镜像已经有区别,我们使用它为模板commit一个
tomcat新镜像, tomcat02
docker ps -l # 查看容器的id
# 注意:commit的时候,容器的名字不能有大写,否则报错:invalid reference format
docker commit -a="lph" -m="no tomcat docs" 1e98a2f815b0 tomcat02:1.1
sha256:cdccd4674f93ad34bf73d9db577a20f027a6d03fd1944dc0e628ee4bf17ec748
[root@lph /]# docker images # 查看,我们自己提交的镜像已经OK了!
# 4、这个时候,我们的镜像都是可以使用的,大家可以启动原来的tomcat,和我们新的tomcat02来
测试看看!
[root@lph ~]# docker run -it -p 8080:8080 tomcat02:1.1
# 如果你想要保存你当前的状态,可以通过commit,来提交镜像,方便使用,类似于 VM 中的快照!
如何tomcat02发布到仓库让别人使用,学习后面dockerfile
二、容器数据卷
1、问题
我们将应用和应用运行环境一起打包成镜像,将此将此镜像提交并发布供他人使用,这个就是docker里面。别人pull这个镜像之后可以使用此镜像创建一个容器并运行,但是运行过程中产生的数据也是存在容器内的,但是如果容器删除之后,容器内的数据也被删除,如果解决这个问题?
2、容器卷技术
如何将容器内产生的数据同步到Liunx本地文件系统这种技术就是卷技术,通过此技术达到容器数据的持久化和双向同步,并且容器卷技术支持容器间数据共享
2.1、使用容器卷
方式一:容器中直接使用命令来添加
# 命令
docker run -it -v 宿主机绝对路径目录:容器内目录 镜像名
# 测试
[root@lph ~]# docker run -it -v /home/ceshi:/home centos /bin/bash
看数据卷是否挂载成功
docker inspect 容器id
测试容器和宿主机之间数据共享:可以发现,在容器中,创建的会在宿主机中看到!
测试容器停止退出后,主机修改数据是否会同步!
1. 停止容器
2. 在宿主机上修改文件,增加些内容
3. 启动刚才停止的容器 4. 然后查看对应的文件,发现数据依旧同步!ok
2.2、docker安装mysql及数据持久化操作
docker images -a
docker ps -a
docker search mysql --filter=stars=20000
docker pull mysql
#启动挂载
docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:latest
#使用本地的navicat连接测试一下 3310
本地创建数据库可以看到数据同步到/home/mysq/data并且如果删除容器,然后发现远程连接失败!但是数据还是在本地
2.3、匿名和具名挂载
-v 容器路径
这种是匿名挂载,只指定了容器内路径 没有写外部路径
docker run -d -P --name nginx01 -v /etc/nginx nginx
#匿名挂载的缺点,就是不好维护,通常使用命令 docker volume维护
docker volume ls
-v 卷名:容器内路径
这种是具名挂载
docker run -d -P --name nginx02 -v nginxconfig:/etc/nginx nginx
查看挂载的路径
docker volume inspect nginxconfig
[
{
"CreatedAt": "2020-05-13T17:23:00+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/nginxconfig/_data",
"Name": "nginxconfig",
"Options": null,
"Scope": "local"
}
]
可以看到docker卷名挂载路径在/var/lib/docker/volumes下
-v /宿主主机路径::容器内路径
是具名挂载 指定路径挂载,参考上面的mysql方式
改变文件的读写权限
# ro: readonly #只读权限
# rw: readwrite #可读可写
# 一旦设置了ro 说明这个路径只能通过宿主机操作,容器内无法操作
docker run -d -P --name nginx02 -v nginxconfig:/etc/nginx:ro nginx
docker run -d -P --name nginx02 -v nginxconfig:/etc/nginx:rw nginx
3、通过Docker File 来添加(了解)
上面我们是通过commit提交镜像
DockerFile 是用来构建Docker镜像的构建文件,是由一些列命令和参数构成的脚本。 我们在这里,先体验下,后面我们会详细讲解 DockerFile !