1. Docker镜像是什么
- 镜像是一种轻量级,可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含某个软件所需的所有内容,包括代码,运行时,库,环境变量和配置文件。
- 所有的应用,直接打包docker镜像,就可以直接跑起来。
- 如何得到镜像?从远程仓库获得,朋友copy,或者我们自己制作一个镜像。
2. Docker镜像加载原理
- docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。
1. UnionFS(联合文件系统)
- UnionFS(联合文件系统): Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加(这一句是重点,一层层,分层结构),同时可以将不同目录挂载到同一个虚拟文件系统下。
- Union文件系统是Docker镜像的基础。镜像可以通过分层来进行继承, 基于基础镜像(没有父镜像), 可以制作各种具体的应用镜像。
- 特性: 一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。
- 好处:资源共享,节约空间。
2. 分层的理解
- 镜像都是一层层,类似叠蛋糕一样,一层层原料,最后组成一个蛋糕。
- 我们先拉取一个tomcat镜像,docker pull tomcat:jdk8-corretto,之后再拉取另一个tomcat镜像,docker pull tomcat:jdk11-corretto。
3. 如何提交一个自己的镜像
1. 相关命令:commit
```powershell
1. docker commit 提交容器成为一个新的副本
2. docker commit -m=“提交的描述信息" -a=”作者“ 容器id 目标镜像名:[tag]
```
2. 实战
- 我们都可以拉取的tomcat镜像中,webapps是空的,原来的欢迎页面等等都是在webapps.dist中,每次都要操作一下,就是觉得麻烦。
- 实现:自己提交一个镜像,使得每次运行这个tomcat镜像,直接有欢迎页面。
# 1. 先将tomcat运行起来
root@ubuntu:/home/mylinux# docker run -p 8080:8080 -d --name MyTomcat tomcat:jdk8-corretto
b56aec91e00fa6e0e7cc370502ad5479c6d7e9cb20c0e19d4dcee1239c8e78da
# 2. 进入tomcat容器
root@ubuntu:/home/mylinux# docker exec -it MyTomcat bash
bash-4.2# ls
BUILDING.txt CONTRIBUTING.md LICENSE NOTICE README.md RELEASE-NOTES RUNNING.txt bin conf lib logs native-jni-lib temp webapps webapps.dist work
# 3. 将webapps.dist 内容复制到webapps中
bash-4.2# cd webapps.dist/
bash-4.2# ls
ROOT docs examples host-manager manager
bash-4.2# cp -r ./ ../webapps
bash-4.2# cd ../webapps
bash-4.2# ls
ROOT docs examples host-manager manager
bash-4.2# exit
exit
# 4. 提交commit自己的镜像
root@ubuntu:/home/mylinux# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b56aec91e00f tomcat:jdk8-corretto "catalina.sh run" 5 minutes ago Up 5 minutes 0.0.0.0:8080->8080/tcp MyTomcat
# docker commit -m=“提交的描述信息" -a=”作者“ 容器id 目标镜像名:[tag]
root@ubuntu:/home/mylinux# docker commit -m "add webapps" b56aec91e00f MyTomcat:1.0
# 提示:名字必须是小写
invalid reference format: repository name must be lowercase
root@ubuntu:/home/mylinux#
root@ubuntu:/home/mylinux# docker commit -m "add webapps" b56aec91e00f mytomcat:1.0
sha256:c20fc856cf0638357437ee7e02da8f4e77576de1faf705124060c0ed4546ab78
# 5. 查看结果
root@ubuntu:/home/mylinux# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mytomcat 1.0 c20fc856cf06 About a minute ago 381MB
tomcat jdk8-corretto cf20ebdc4989 30 hours ago 376MB
# 6. 测试,使用mytomcat镜像创建容器,直接运行,发现可以直接在浏览器输入ip:8081 看到欢迎页面
# 使用8081是因为之前容器已经使用了本地的8080端口了
root@ubuntu:/home/mylinux# docker run -p 8081:8080 -d --name mytomcat mytomcat:1.0
d9577281c3b0f86348dc27019b700b63d16ae64c8e65e1b40159257ae347f0ce
3. 小结
- 如果你想要保存当前容器的状态,就可以通过commit提交,获得一个镜像
- 就好比我们以前学习vm的时候,快照
- 命令:docker commit -m “提交信息” -a “作者” 容器id 目标镜像名:[tag]
- 注意是容器的id哦
4. 容器数据卷
1. 概念
- 我们知道容器相当于一台小型的虚拟机,有自己的文件系统,那如果数据都在容器中,而我们又删除容器,此时数据就会丢失,比如mysql的数据丢失则是一件很恐怖的事情。因此我们急需===>数据可以持久化.
- 而容器之间可以有一个数据共享的技术,docker容器中产生的数据,同步到本地,这就是数据卷。
- 数据卷使用的是:目录的挂载,将我们容器内的目录,挂载到linux上面。
- 比如:mysql /usr/mysql =====> /home/mysql 挂载到了本地上。
- 容器的持久化和同步操作,容器间也是可以数据共享的。
- 使用数据卷:
直接使用命令来挂载 -v
docker run -it -v 主机目录:容器内目录
2. 实战
1. 初步使用数据卷
# 1. 我们先准备个centos
root@ubuntu:/home/mylinux# docker pull centos
Using default tag: latest
latest: Pulling from library/centos
7a0437f04f83: Pull complete
Digest: sha256:5528e8b1b1719d34604c87e11dcd1c0a20bedf46e83b5632cdeac91b8c04efc1
Status: Downloaded newer image for centos:latest
docker.io/library/centos:latest
# 2. 在本地上创建一个文件夹,为了与centos挂载
root@ubuntu:/home/mylinux# cd ..
root@ubuntu:/home# mkdir centos
root@ubuntu:/home# ls
centos
# 3. 启动centos镜像。
# 使用命令来挂载 -v
# docker run -it -v 主机目录:容器内目录 运行的镜像
# 对于centos运行为什么要用-it 之前解释过了,在下面的博客中的其他命令,第一大点中有
# https://blog.csdn.net/xueyijin/article/details/111479219
# -v /home/centos:/home 意思是将本机的/home/centos文件与容器centos的/home直接绑定
root@ubuntu:/home# docker run -it -v /home/centos:/home centos
[root@b0605f23b4f0 /]#
# 4. 我们在centos容器内进入home目录下,创建一个test.txt文本
[root@b0605f23b4f0 /]# cd home/
[root@b0605f23b4f0 home]# touch test.txt
[root@b0605f23b4f0 home]#
# 注意:看前面的标识,root@b0605f23b4f0 home 是centos容器的
# root@ubuntu 是本机ubuntu的
# 我们在本机上查看 home目录,惊奇发现有了。
root@ubuntu:/home/centos# ls
test.txt
# 5. 我们停止容器后,观察本机是否还有此文件
root@ubuntu:/home/centos# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b0605f23b4f0 centos "/bin/bash" 11 minutes ago Up 11 minutes naughty_hoover
root@ubuntu:/home/centos# docker stop b0605f23b4f0
b0605f23b4f0
# 结果还在
root@ubuntu:/home/centos# ls
test.txt
# 6. 我们先不启动容器,直接在test.txt的文件夹中添加内容。
root@ubuntu:/home/centos# vi test.txt
root@ubuntu:/home/centos# cat test.txt
hello world
# 重新启动centos容器
root@ubuntu:/home# docker run -it -v /home/centos:/home centos
[root@51b8a28a3af3 /]# cd /home
# 惊奇发现,数据居然同步过去了。
[root@51b8a28a3af3 home]# cat test.txt
hello world
# 7. 在centos容器中修改test.txt文件且删除centos容器以及镜像
[root@51b8a28a3af3 home]# echo I am centos > test.txt
[root@51b8a28a3af3 home]# cat test.txt
I am centos
[root@51b8a28a3af3 home]# exit
exit
root@ubuntu:/home# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos latest 300e315adb2f 2 weeks ago 209MB
# 直接删除镜像 跟容器
root@ubuntu:/home# docker rmi -f centos
Untagged: centos:latest
Untagged: centos@sha256:5528e8b1b1719d34604c87e11dcd1c0a20bedf46e83b5632cdeac91b8c04efc1
Deleted: sha256:300e315adb2f96afe5f0b2780b87f28ae95231fe3bdd1e16b9ba606307728f55
# 查看本机的home目录下,发现还在
# 这就是数据卷 持久化的作用了
root@ubuntu:/home# cd centos/
root@ubuntu:/home/centos# ls
test.txt
root@ubuntu:/home/centos# cat test.txt
I am centos
2. 实战mysql数据同步
# 1. 先拉取镜像
root@ubuntu:/home# docker pull mysql
# 在homt目录下创建两个文件
root@ubuntu:/home# mkdir mysql
root@ubuntu:/home# cd mysql/
root@ubuntu:/home/mysql# mkdir data
root@ubuntu:/home/mysql# ls
data
root@ubuntu:/home/mysql# cd ..
root@ubuntu:/home#
# 2. 对于mysql的启动,前提说明
# MYSQL_ROOT_PASSWORD=自己的密码
# 本变量必填,它指定了 MySQL root 的用户的密码。
# /var/lib/mysql 是mysql的数据存放位置
# /home/mysql/data 是自己本机的映射
# 使用3308 是因为本机之前就安装了mysql
root@ubuntu:/home# docker run -it -d -p 3308:3306 -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql
# 3. 启动并加入容器
root@ubuntu:/home# docker run -it -d -p 3308:3306 -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql
2f51cd5c2727ed7a72bfb5ea46b4771d25f1ed24586c609383ca71ef8c67d2b2
root@ubuntu:/home# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2f51cd5c2727 mysql "docker-entrypoint.s…" 6 seconds ago Up 4 seconds 33060/tcp, 0.0.0.0:3308->3306/tcp zealous_austin
root@ubuntu:/home# docker exec -it 2f51cd5c2727 bash
root@2f51cd5c2727:/# cd bin/
# 进入mysql服务
root@2f51cd5c2727:/bin# mysql -uroot -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 10
Server version: 8.0.22 MySQL Community Server - GPL
Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
# 4. 查看本机的homte/mysql/data文件中,发现有数据了,mysql持久化也做好了。
root@ubuntu:/home/mysql/data# ls
2f51cd5c2727.err binlog.000002 ca.pem #ib_16384_0.dblwr ibdata1 ibtmp1 mysql.ibd public_key.pem sys
auto.cnf binlog.index client-cert.pem #ib_16384_1.dblwr ib_logfile0 #innodb_temp performance_schema server-cert.pem undo_001
binlog.000001 ca-key.pem client-key.pem ib_buffer_pool ib_logfile1 mysql private_key.pem server-key.pem undo_002
# 5. 测试一下,创建一个helloworld数据库
# 在mysql容器中创建
mysql> create database helloworld
-> ;
Query OK, 1 row affected (0.03 sec)
# 在本机home/mysql/data查看,发现有helloworld数据
root@ubuntu:/home/mysql/data# ls | grep helloworld
helloworld
# 6. 停止原来的mysql容器,再创建一个新的mysql02容器,直接挂载/home/mysql/data数据
# 查看新的mysql02容器中,是否有helloworld数据库
# 停止原来的且删除原来容器
root@ubuntu:/home# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2f51cd5c2727 mysql "docker-entrypoint.s…" 11 minutes ago Up 11 minutes 33060/tcp, 0.0.0.0:3308->3306/tcp zealous_austin
root@ubuntu:/home# docker rm -f 2f51cd5c2727
2f51cd5c2727
# 创建新容器mysql02 并挂载之前的/home/mysql/data
root@ubuntu:/home# docker run -it -d -p 3308:3306 --name mysql02 -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql
01bc338ad0ac6a3fdc751e049f1717b4d2fe4e350f9ffd307fb353d5dc9ed5ca
# 进入mysql容器
root@ubuntu:/home# docker exec -it mysql02 bash
root@01bc338ad0ac:/# cd bin/
# 查看mysql中是否有helloworld数据库
root@01bc338ad0ac:/bin# mysql -uroot -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.22 MySQL Community Server - GPL
Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| helleworld |
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.01 sec)
mysql>
3. 初步小结
- 对于数据卷来说,尤其是根据上面mysql实战可以得出:
- 一开始本地 /home/mysql/data 中没有内容,会直接把mysql容器中的数据同步出来
- 我们之后删除了第一个mysql容器,并重新创建一个全新的mysql02容器,并挂载本地 /home/mysql/data,此时本地 /home/mysql/data是有数据的。
- 挂载后我们发现,本地 /home/mysql/data的数据同步到了新的mysql02容器中,因为有helloworld数据库了。
- 因此:大家有feel了吧。
5. 具名和匿名挂载(了解)
-
挂载也可以分为三种:
1. 指定路径挂载--------> -v /宿主机路径:容器内路径 2. 具名挂载----------->-v 卷名:容器内路径 3. 匿名挂载----------->-v 容器内路径 # 没有多大区别,我们常用的是指定路径挂载 # 用刚刚mysql来举例子
# 匿名(没有指定挂载路径) docker run -it -d -P -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql # 具名(没有指定挂载路径,但是取了一个名字) docker run -it -d -P -v juming-mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql # 指定 docker run -it -d -P -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql # 这里就提出一个问题 如果是匿名或者具名,那么挂载之后的东西放在哪里呢? # 使用docker volume ls 查看挂载 root@ubuntu:/home/mysql/data# docker volume ls DRIVER VOLUME NAME local 1c59e5f79225ce95c23d5a892d8de30759377cac03e333e564f71bea17b9f005 local 2ebaaae9a2cb8a606318f0e5c822eff9602248bd6533b41cec7dcdc8e94ea3b1 # 刚刚指定的具名挂载在这里,这也是为什么要具名了,方便查看 # 如果是匿名的话,则就是后面一大串数据,实际上是容器的id local juming-mysql # 查看这些卷的位置 # docker volume inspect 卷名 root@ubuntu:/home/mylinux# docker volume inspect juming-mysql [ { "CreatedAt": "2020-11-30T18:29:20-08:00", "Driver": "local", "Labels": null, # 数据卷的位置 "Mountpoint": "/var/lib/docker/volumes/juming-mysql/_data", "Name": "juming-mysql", "Options": null, "Scope": "local" } ] # 进入查看 root@ubuntu:/home/mysql/data# cd /var/lib/docker/volumes/juming-mysql/_data root@ubuntu:/var/lib/docker/volumes/juming-mysql/_data# ls 44200fb24004.err binlog.000002 ca.pem #ib_16384_0.dblwr ibdata1 #innodb_temp performance_schema server-cert.pem undo_001 auto.cnf binlog.index client-cert.pem #ib_16384_1.dblwr ib_logfile0 mysql private_key.pem server-key.pem undo_002 binlog.000001 ca-key.pem client-key.pem ib_buffer_pool ib_logfile1 mysql.ibd public_key.pem sys # 小结 所有的docker容器内的卷,没有指定目录的情况下都是在/var/lib/docker/volumes/xxx
6. 容器之间数据卷
-
容器之间(两个或者多个)也可以使用数据卷,进行数据的同步。
-
使用的命令是 --volumes-from。
-
实践:
# 1. 先拉取centos root@ubuntu:/home# docker pull centos # 2. 在本机的home目录下创建 container文件 root@ubuntu:/home# mkdir container root@ubuntu:/home# ls container # 3. 启动一个centos1容器,并将home目录 挂载到本机/home/container # 注意:容器之间的数据卷,前提是要有挂载 root@ubuntu:/home# docker run -it -d --name centos1 -v /home/container/:/home centos aef2ed44dafebbf19c1e48c587fe4a89558fadd3898176c64b6faf2c0674cced # 4. 启动centos2容器,并与centos1容器进行挂载 root@ubuntu:/home# docker run -it -d --name centos2 --volumes-from centos1 centos 03b8fc40d736ac5f1fee151fe5e2cb7e4736cdbc156be62027fa96feae11feb5 # 5. 之后进入centos1容器内/home目录下,创建test.txt root@ubuntu:/home# docker exec -it centos1 bash [root@aef2ed44dafe /]# cd home/ [root@aef2ed44dafe home]# echo "" > test.txt # 6. 在本机上查看 /home/container目录,以及centos2容器/home目录 # 在本机上 root@ubuntu:/home/container# ls test.txt # centos2容器上 [root@03b8fc40d736 home]# ls test.txt # 7. 之后在centos2容器上,疯狂修改 [root@03b8fc40d736 home]# echo "" > hello.txt [root@03b8fc40d736 home]# echo "" > world.txt [root@03b8fc40d736 home]# ls hello.txt test.txt world.txt # 8. 在centos1容器上查看 [root@aef2ed44dafe home]# ls hello.txt test.txt world.txt # 9. 把centos1停止并删除后,在centos2中疯狂修改,看看本地是否有同步 # centos1停止并删除 root@ubuntu:/home/container# docker rm -f centos1 centos1 # centos2中疯狂修改 [root@03b8fc40d736 home]# echo "" > centos2.txt [root@03b8fc40d736 home]# echo "" > kkkk.txt [root@03b8fc40d736 home]# ls centos2.txt hello.txt kkkk.txt test.txt world.txt # 10. 查看本地是否同步 # 同步 root@ubuntu:/home/container# ls centos2.txt hello.txt kkkk.txt test.txt world.txt
-
小结:容器之间数据卷同步,前提是要有挂载。数据卷容器的生命周期一直持续到没有容器使用为止。例如:上面的例子,如果我在启动一个centos3容器并–volume-from centos2,再把centos2停止并删除,再centos3容器上的修改,本地/home/container还是可以同步的。除非,都删除了。