镜像是什么?
镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需要的所有内容,包括代码、库、环境变量和配置文件。
所有的应用,直接打包镜像,就可以直接跑起来!
如何得到镜像:
1、从远程仓库下载
2、朋友拷贝给你
3、自己制作一个Dockerfile
Docker 镜像加载原理*
联合文件系统(Union File System,Unionfs)
是一种分层的轻量级文件系统,它可以把多个目录内容联合挂载到同一目录下,从而形成一个单一的文件系统,这种特性可以让使用者像是使用一个目录一样使用联合文件系统。
联合文件系统是 Docker 镜像和容器的基础,它让Docker 可以把镜像做成分层的结构,从而使得镜像的每一层可以被共享。
联合文件系统只是一个概念,真正实现联合文件系统才是关键,联合文件系统的实现方案有很多,Docker 中最常用的联合文件系统有三种:AUFS、Devicemapper 和 OverlayFS。
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等等。
对于一个精简的OS,rootfs 可以很小,只需要包含最基本的命令,工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供rootfs就可以了。由此可见对于不同的linux发行版, bootfs基本是一致的, rootfs会有差别, 因此不同的发行版可以公用bootfs。
#查看镜像分层
docker image inspect nginx
所有的 Docker 镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之
上,创建新的镜像层。
Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部!
这一层就是我们通常说的容器层,容器之下的都叫镜像层!
commit 镜像
docker commit 提交容器成为一个新的副本
docker commit -m="提交的描述信息" -a="作者" 容器id 要创建的目标镜像名:[标签名]
# 启动容器
docker run -it -p 8080:8080 tomcat
# 进入容器
[root@iZuf6gomcpmv2fk1vu2w85Z ~]# docker exec -it dfcb5215b888 /bin/bash
# 拷贝webapps.dist的文件到webapps目录下,这样就能显示出tomcat的首页WEB
root@dfcb5215b888:/usr/local/tomcat# cp -r webapps.dist/* webapps
# 新建镜像
docker commit -a=”张三“ -m="add webappps app" dfcb5215b888 tomcat02:1.0
# 可以看到新建的镜像成功了,下次可以直接运行
[root@iZuf6gomcpmv2fk1vu2w85Z ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tomcat02 1.0 7bb5b7e54ace 5 seconds ago 684MB
nginx latest 605c77e624dd 14 months ago 141MB
tomcat latest fb5657adc892 14 months ago 680MB
portainer/portainer-ce latest 0df02179156a 15 months ago 273MB
centos latest 5d0da3dc9764 17 months ago 231MB
elasticsearch 7.6.2 f29a1ee41030 2 years ago 791MB
容器数据卷
问题:如果数据都在容器里面,当容器删除后数据就会丢失。
需求: 数据可以持久化,能永久保存
解决: 容器之间有一个数据共享技术,称之为数据卷技术,docker容器产生的数据,会自动同步到本地服务器上面。
使用数据卷
直接使用命令来挂载
docker run -it -v 主机目录:容器目录
例如: docker run -it -v /home/ceshi:/home centos /bin/bash
创建成功后,通过docker inspect 容器id,能看到详细信息,其中有
"Mounts": [ //挂载 -v
{
"Type": "bind",
"Source": "/home/ceshi", // 主机地址
"Destination": "/home", //docker容器内地址
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],
当在服务器的/home目录进行文件的增删改查,会自动同步到容器的/home/ceshi目录下面。
反过来,在容器内的操作也会自动同步到外面的主机上面。
可以理解为 双向绑定
实战 安装mysql
[root@iZuf6gomcpmv2fk1vu2w85Z ceshi]# docker pull mysql:5.7
#运行容器,需要做数据挂载!
#安装启动Mysql,需要配置密码
#官方测试 : $ docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
#启动我们的
-d 后台运行
--p 端口映射
-v 数据挂载
-e 环境配置
--name 容器名字
[root@iZuf6gomcpmv2fk1vu2w85Z home]# docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d
-v /home/mysql/data:/var/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
或者是
[root@iZuf6gomcpmv2fk1vu2w85Z home]# docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/my.cnf.d
-v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
#启动之后,我们在本地用sql应用程序远程连接,测试一下
#本地的 sql程序连接到服务器的3310 ----3310和容器内部的3306映射,即可连接。
#在本地测试创建一个数据库,查看一下映射的路径是否ok.
注意
在这里由于不同的系统和版本,MySQL的路径可能不一样的。
比如有些mysql的conf路径是/etc/mysql/conf.d ;data路径是/var/mysql 。
而有些mysql的路径conf路径是/etc/mysql/my.cnf.d ;data路径是/var/lib/mysql
我们可以现在服务器登录Mysql的命令后
语法: mysql [-h 主机名] -u用户名 -p密码 [-P端口号] [-D数据库名]
参数分析:
[-h主机名或ip地址]或者[–host=主机名ip地址]:指定登录的主机名;
[-u用户名]或者[–user=用户名]: 指定用户登录的用户名;
[-p密码(p小写)]或者[–password=密码]:输入登录密码;
[-P端口号(P大写)]或者[–port=端口号]:指定登录的MySQL的端口号;
[-D数据库名]或者[–database=数据库名]:指定登录的数据库名称;
1、登录本地数据库
登录本地数据库,只需要指定用户名(-u)和密码(-p)即可,不需要指定主机名(-h),命令如下:
root@8cd4c678c5d2# mysql -uroot -p123456
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 12
Server version: 5.7.36 MySQL Community Server (GPL)
Copyright (c) 2000, 2021, Oracle and/or its affiliates.
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 variables like ‘%dir%’; 可以查看到datadir的路径是/var/lib/mysql,也就是你新建数据库和表的保存路径
mysql> show variables like '%dir%';
+-----------------------------------------+----------------------------+
| Variable_name | Value |
+-----------------------------------------+----------------------------+
| basedir | /usr/ |
| binlog_direct_non_transactional_updates | OFF |
| character_sets_dir | /usr/share/mysql/charsets/ |
| datadir | /var/lib/mysql/ |
| ignore_db_dirs | |
| innodb_data_home_dir | |
| innodb_log_group_home_dir | ./ |
| innodb_max_dirty_pages_pct | 75.000000 |
| innodb_max_dirty_pages_pct_lwm | 0.000000 |
| innodb_tmpdir | |
| innodb_undo_directory | ./ |
| lc_messages_dir | /usr/share/mysql/ |
| plugin_dir | /usr/lib/mysql/plugin/ |
| slave_load_tmpdir | /tmp |
| tmpdir | /tmp |
+-----------------------------------------+----------------------------+
15 rows in set (0.00 sec)
而一般情况下 ,linux安装后的mysql默认配置文件conf是在/etc/my.cnf ,我们可以设置conf文件夹去-v映射到my.conf.d文件夹。
如果我们把容器给删除了,我们挂载到本地的数据卷依然存在,数据持久化。
[root@iZuf6gomcpmv2fk1vu2w85Z data]# docker rm -f mysql01
具名和匿名挂载
#匿名挂载 -v 容器内路径 (-P 是随机映射端口)
docker run -d -P --name nginx01 -v /etc/nginx nginx
[root@iZuf6gomcpmv2fk1vu2w85Z data]# docker run -d -P --name nginx01 -v /etc/nginx nginx
f285a14d36725474dd687f84bdd2fda514f5fd57acb2c88446d45005c77f33ad
[root@iZuf6gomcpmv2fk1vu2w85Z data]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f285a14d3672 nginx "/docker-entrypoint.…" 5 seconds ago Up 5 seconds 0.0.0.0:1024->80/tcp, :::1024->80/tcp nginx01
[root@iZuf6gomcpmv2fk1vu2w85Z data]#
[root@iZuf6gomcpmv2fk1vu2w85Z data]# docker volume ls
DRIVER VOLUME NAME
local 13dca648506507fa68c29423e1433d9c76a6dd44205d52ba58de807e1c34fbb0
local 27679f1518ecddb8686b852dc7e0575aaecabb482f3917b49d51a6d7f1823772
local 330262caceee76a4f510a3157758b63e4a1ef19ffe138fa2280650519ef230f6
local portainer_data
docker volume ls 可以查看你所有的卷,前面三个的volumeName是一串代码,说明都是没有给卷起名。
下面是具名的卷
[root@iZuf6gomcpmv2fk1vu2w85Z data]# docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx
8e72db97684a78d7c66fdb24673c46b4680a5c0877e32e3db0d14202c7567cf5
[root@iZuf6gomcpmv2fk1vu2w85Z data]# docker volume ls
DRIVER VOLUME NAME
local 13dca648506507fa68c29423e1433d9c76a6dd44205d52ba58de807e1c34fbb0
local 27679f1518ecddb8686b852dc7e0575aaecabb482f3917b49d51a6d7f1823772
local 330262caceee76a4f510a3157758b63e4a1ef19ffe138fa2280650519ef230f6
local juming-nginx
local portainer_data
[root@iZuf6gomcpmv2fk1vu2w85Z data]# docker volume inspect juming-nginx
[
{
"CreatedAt": "2023-03-06T16:16:40+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/juming-nginx/_data",
"Name": "juming-nginx",
"Options": null,
"Scope": "local"
}
]
docker 容器中所有的卷,在没有指定目录的情况下,都在var/lib/docker/volumes/juming-nginx/_data",
我们可以通过具名挂载找到卷的位置,大多数情况下,我们使用具名挂载
关于docker的挂载问题,有三个比较容易混淆的概念: (区分的方式)
1.具名挂载:-v 参数 卷名:容器内路径
2.匿名挂载:-v 参数后面 没有写上容器之外的地址, docker 自己会在docker内部给你找个位置
3.指定路径挂载: -v /宿主机路径::容器内路径
rw :可读可写的权限
ro : 可读权限
docker run -d -P --name nginx03 -v juming-nginx:/etc/nginx:rw nginx
docker run -d -P --name nginx03 -v juming-nginx:/etc/nginx:ro nginx
ro 权限说明命令只可以被宿主机操作,容器的内部将无法进行操作