docker网络和存储
问题:
-
容器: 某个软件完整的运行环境;包含了一个小型的linux系统
-
宿主机里面同时4个nginx; 一个nginx运行时完整环境有20MB?
- 4个nginx 合起来占用多少的磁盘空间
- 80?一定会很大…
-
docker装的和宿主机的优缺点:
-
优点:docker的移植性、便捷性高于在宿主机部署、进程隔离、很方便的资源限制
-
缺点:docker虚拟化技术,损失不到3%的性能。
-
-
docker?原生物理机自己造docker这种东西。
-
镜像(Image):固定不变的。一个镜像可以启动很多容器
-
容器(Container):文件系统可能logs经常变化的,一个镜像可以启动很多容器。
-
docker在底层使用自己的存储驱动。来组件文件内容 storage drivers。docker 基于 AUFS(联合文件系统)
1、Docker存储
1、镜像如何存储
0、自己探索
FROM busybox
CMD ping baidu.com
截取的nginx的分层
nginx这个镜像怎么存的
使用:docker image inspect nginx
指示了镜像怎么存的
-
LowerDir :底层目录; diff(只是存储不同);包含小型linux和装好的软件
/var/lib/docker/overlay2/67b3802c6bdb5bcdbcccbbe7aed20faa7227d584ab37668a03ff6952e 631f7f2/diff:用户文件; /var/lib/docker/overlay2/f56920fac9c356227079df41c8f4b056118c210bf4c50bd9bb077bdb4 c7524b4/diff: nginx的启动命令放在这里 /var/lib/docker/overlay2/0e569a134838b8c2040339c4fdb1f3868a7118dd7f4907b40468f5fe6 0f055e5/diff: nginx的配置文件在这里 /var/lib/docker/overlay2/2b51c82933078e19d78b74c248dec38164b90d80c1b42f0fdb1424953 207166e/diff: 小linux系统
-
倒着看
-
小linux系统(FROM apline) + Dockerfile的每一个命令可能都引起了系统的修改,所以和git 一样,只记录变化
-
我们进入到这个镜像启动的容器,容器的文件系统就是镜像的;
-
docker ps -s;可以看到这个容器真正用到的文件大小
-
容器会自己建立层;如果想要改东西,把改的内容复制到容器层即可 docker inspect container
"LowerDir": "/var/lib/docker/overlay2/41e4fa41a2ad1dca9616d4c8254a04c4d9d6a3d462 c862f1e9a0562de2384dbcinit/diff:/var/lib/docker/overlay2/e3b8bdbb0cfbe5450696c470994b3f99e 8a7942078e2639a788027529c6278f7/diff:/var/lib/docker/overlay2/67b380 2c6bdb5bcdbcccbbe7aed20faa7227d584ab37668a03ff6952e631f7f2/diff:/var /lib/docker/overlay2/f56920fac9c356227079df41c8f4b056118c210bf4c50bd 9bb077bdb4c7524b4/diff:/var/lib/docker/overlay2/0e569a134838b8c20403 39c4fdb1f3868a7118dd7f4907b40468f5fe60f055e5/diff:/var/lib/docker/ov erlay2/2b51c82933078e19d78b74c248dec38164b90d80c1b42f0fdb14249532071 66e/diff", "MergedDir": "/var/lib/docker/overlay2/41e4fa41a2ad1dca9616d4c8254a04c4d9d6a3d462 c862f1e9a0562de2384dbc/merged", "UpperDir": (镜像的上层可以感知变 化)"/var/lib/docker/overlay2/41e4fa41a2ad1dca9616d4c8254a04c4d9d6a3d 462c862f1e9a0562de2384dbc/diff",【容器的修改后的文件,保存再宿主机哪里呀。 容器删除后,那些容器目录还存在吗?一定不再】 "WorkDir": "/var/lib/docker/overlay2/41e4fa41a2ad1dca9616d4c8254a04c4d9d6a3d462 c862f1e9a0562de2384dbc/work"
-
-
MergedDir :合并目录;容器最终的完整工作目录全内容都在合并层;数据卷在容器层产生;所 有的增删改都在容器层;
-
UpperDir :上层目录;
-
WorkDir :工作目录(临时层),pid;
LowerDir(底层)\UpperDir()\MergedDir\WorkDir(临时东西)
-
docker底层的 storage driver完成了以上的目录组织结果;
1、images and layers
Docker映像由一系列层组成。 每层代表图像的Dockerfile中的一条指令。 除最后一层外的每一层都是只 读的。 如以下Dockerfile:
-
Dockerfile文件里面几句话,镜像就有几层
FROM ubuntu:15.04 COPY . /app RUN make /app CMD python /app/app.py # 每一个指令都可能会引起镜像改变,这些改变类似git的方式逐层叠加。
该Dockerfile包含四个命令,每个命令创建一个层。 FROM语句从ubuntu:15.04映像创建一个图层开始。 COPY命令从Docker客户端的当前目录添加一些文件。 RUN命令使用make命令构建您的应用程序。 最后,最后一层指定要在容器中运行的命令。 每一层只是与上一层不同的一组。 这些层彼此堆叠。 创建新容器时,可以在基础层之上添加一个新的可写层。 该层通常称为“容器层”。 对运行中 的容器所做的所有更改(例如写入新文件,修改现有文件和删除文件)都将写入此薄可写容 器层。
2、Container and layers
容器和镜像之间的主要区别是可写顶层。
在容器中添加新数据或修改现有数据的所有写操作都存储在此可写层中。
删除容器后,可写层也会被删除。 基础图像保持不变。 因为每个容器都有其自己的可写容器层,并且所有更改都存储在该容器层中,所以多个容器可以共享对同一基础映像的访问,但具有自己的数据状态。
3、磁盘容量预估
docker ps -s
size:用于每个容器的可写层的数据量(在磁盘上)。
virtual size:容器使用的用于只读图像数据的数据量加上容器的可写图层大小。 多个容器可以共享部分或全部只读图像数据。 从同一图像开始的两个容器共享100%的只读数据,而具有不同图像的两个容器(具有相同的层)共享这些公共 层。 因此,不能只对虚拟大小进行总计。这高估了总磁盘使用量,可能是一笔不小的数目。
4、镜像如何挑选
busybox:是一个集成了一百多个最常用Linux命令和工具的软件。linux工具里的瑞士军刀
alpine:Alpine操作系统是一个面向安全的轻型Linux发行版经典最小镜像,基于busybox,功能比
Busybox完善。
slim:docker hub中有些镜像有slim标识,都是瘦身了的镜像。也要优先选择
无论是制作镜像还是下载镜像,优先选择alpine类型.
5、Copy On Write
写时复制是一种共享和复制文件的策略,可最大程度地提高效率。
如果文件或目录位于映像的较低层中,而另一层(包括可写层)需要对其进行读取访问,则它仅使用现有文件。
另一层第一次需要修改文件时(在构建映像或运行容器时),将文件复制到该层并进行修改。 这 样可以将I / O和每个后续层的大小最小化。
2、容器如何挂载
每一个容器里面的内容,支持三种挂载方式:
1)、docker自动在外部创建文件夹自动挂载容器内部指定的文件夹内容【Dockerfile VOLUME指令的作
用】
2)、自己在外部创建文件夹,手动挂载
3)、可以把数据挂载到内存中。
--mount 挂载到 linux宿主机,手动挂载(不用了)
-v 可以自动挂载,到linux主机或者docker自动管理的这一部分区域
命令 | 作用 |
---|---|
Volumes(卷) | 存储在主机文件系统的一部分中,该文件系统由Docker管理(在Linux上是“ / var / lib / docker / volumes /”)。 非Docker进程不应修改文件系统的这一部分。 卷是在Docker中持久存 储数据的最佳方法。 |
Bind mounts(绑定挂载) | 可以在任何地方 存储在主机系统上。 它们甚至可能是重要的系统文件或 目录。 Docker主机或Docker容器上的非Docker进程可以随时对其进行修改。 |
tmpfs mounts(临时挂载) | 仅存储在主机系统的内存中,并且永远不会写入主机系统的文件系统 |
1、volume(卷)
-
匿名卷使用
docker run -dP -v :/etc/nginx nginx #docker将创建出匿名卷,并保存容器/etc/nginx下面的内容 # -v 宿主机:容器里的目录
-
具名卷使用
docker run -dP -v nginx:/etc/nginx nginx #docker将创建出名为nginx的卷,并保存容器/etc/nginx下面的内容
如果将空卷装入存在文件或目录的容器中的目录中,则容器中的内容(复制)到该卷中。
如果启动一个容器并指定一个尚不存在的卷,则会创建一个空卷。
-v 宿主机绝对路径:Docker容器内部绝对路径:叫挂载;这个有空挂载问题 -v 不以/开头的路径:Docker容器内部绝对路径:叫绑定(docker会自动管理,docker不会把他当前目 录,而把它当前卷) 以上用哪个比较好?????? 如果自己开发测试,用 -v 绝对路径的方式 如果是生产环境建议用卷 除非特殊 /bin/docker 需要挂载主机路径的则操作 绝对路径挂载
nginx–Docker /usr/share/nginx/html
nginx测试html挂载几种不同情况:
- 不挂载 效果:访问默认欢迎页 - -v /root/html:/usr/share/nginx/html 效果:访问forbidden - -v html:/usr/share/nginx/html:ro 效果:访问默认欢迎页 - -v /usr/share/nginx/html 效果:匿名卷 (什么都不写也不要加冒号,直接写容器内的目录)
-
原因:
- -v html:/usr/share/nginx/html; docker inspect 容器的时候; docker自动管理的方式
# -v不以绝对路径方式; ### 1、先在docker底层创建一个你指定名字的卷(具名卷) html ### 2、把这个卷和容器内部目录绑定 ### 3、容器启动以后,目录里面的内容就在卷里面存着; #####-v nginxhtml:/usr/share/nginx/html 也可以以下操作 ## 1、docker run -d -P -v nginxhtml:/usr/share/nginx/html -- name=nginx777 nginx ## 1、 docker create volume nginxhtml 如果给卷里面就行修改,容器内部的也就改 了。 ## 2、 docker ps [root@localhost _data]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 23eafedea375 nginx "/docker-entrypoint.…" 5 minutes ago Up 5 minutes 0.0.0.0:49153->80/tcp, :::49153->80/tcp nginx777 ## 3、 docker inspect 23eafedea375 可以看到 "Mounts": [ { "Type": "volume", //这是个卷 "Name": "nginxhtml", //名字是html "Source": "/var/lib/docker/volumes/nginxhtml/_data", //宿主 机的目录。容器里面的哪两个文件都在 "Destination": "/usr/share/nginx/html", //容器内部 "Driver": "local", "Mode": "z", "RW": true, //读写模式 "Propagation": "" } ] ## 4、如果给卷里面就行修改,容器内部的也就改 了 #卷:就是为了保存数据 docker volume #可以对docker自己管理的卷目录进行操作; /var/lib/docker/volumes(卷的根目录)
-
2、bind mount
如果将绑定安装或非空卷安装到存在某些文件或目录的容器中的目录中,则这些文件或目录会被 安装遮盖,就像您将文件保存到Linux主机上的/ mnt中一样,然后 将USB驱动器安装到/ mnt中。 在卸载USB驱动器之前,/ mnt的内容将被USB驱动器的内容遮盖。 被遮盖的文件不会被删除或更 改,但是在安装绑定安装或卷时将无法访问。 总结:外部目录覆盖内部容器目录内容,但不是修改。所以谨慎,外部空文件夹挂载方式也会导 致容器内部是空文件夹
-
bind mount和 volumes 的方式写法区别在于:
- 所有以/开始的都认为是 bind mount ,不以/开始的都认为是 volumes.
docker run -dP -v /my/nginx:/etc/nginx:ro nginx
警惕bind mount 方式,文件挂载没有在外部准备好内容而导致的容器启动失败问题
# 一行命令启动nginx,并且配置文件和html页面。需要知道卷的位置才能改
docker run -d -P -v nginxconf:/etc/nginx/ -v nginxpage:/usr/share/nginx/html nginx
# 想要实现 docker run -d -P -v /root/nginxconf:/etc/nginx/ -v
/root/nginxhtml:/usr/share/nginx/html --name=nginx999 nginx
### 1、提前准备好东西 目录nginxconf,目录里面的配置we年都放里面,,再调用命令
### 2、docker cp nginxdemo:/etc/nginx /root/nginxconf #注意/的使用
### 3、docker run -d -P -v /root/nginxconf:/etc/nginx/ -v
/root/nginxhtml:/usr/share/nginx/html --name=nginx999 nginx
3、管理docker卷
1. 使用Docker卷和主机目录绑定的优缺点对比
特性 | Docker卷 | 主机目录映射 |
---|---|---|
数据持久化 | ✅ 独立于容器生命周期 | ❌ 依赖主机目录存在 |
性能 | ✅ 通常有更好的I/O性能(Linux) | ⚠️ 直接依赖主机文件系统性能 |
权限管理 | ✅ 自动处理文件权限(UID匹配) | ⚠️ 需手动配置权限 |
可移植性 | ✅ 与Docker环境深度集成 | ❌ 路径绑定导致环境依赖 |
备份/迁移 | ✅ 原生支持卷导出/导入 | ⚠️ 需手动操作主机文件系统 |
开发调试 | ⚠️ 需要额外操作查看数据 | ✅ 直接访问主机文件 |
安全隔离 | ✅ 默认存储在Docker管理区域 | ❌ 直接暴露主机文件系统 |
2. 如何使用Docker卷
基础操作命令
# 创建命名卷
docker volume create my_volume
# 启动容器并挂载卷
docker run -d --name myapp \
--mount source=my_volume,target=/app/data \
nginx:latest
# 查看卷信息
docker volume inspect my_volume
# 删除未使用卷
docker volume prune
匿名卷使用(Docker自动管理)
docker run -d -v /container/path nginx:latest
docker-compose.yml:
services:
my_service:
image: my_image
volumes:
- my_volume:/app/data
volumes:
my_volume:
driver: local # 默认值,也可指定其他驱动(如nfs、flocker等)
driver_opts:
type: none # 使用"none"表示直接挂载
o: bind # 使用"bind"选项进行绑定挂载
device: ./data # 宿主机路径(相对于compose文件)
labels:
- "app=my_app" #为卷添加元数据标签,用于管理或过滤。
external: false # 默认值,设为true则使用已存在的卷"data"
3. 如何配置Docker卷权限
权限配置方法
-
运行时指定用户:
docker run -d --user 1000:1000 \
-v my_volume:/data \
nginx:latest
Dockerfile预设:
FROM nginx:latest
RUN chown -R 1000:1000 /app/data
USER 1000
-
docker run:
docker run -v my_volume:/container/path:ro my_image # 只读挂载
docker run -v my_volume:/container/path:rw my_image # 可读写挂载
-
docker-compose.yml:
services:
my_service:
image: my_image
volumes:
- my_volume:/container/path:ro
修改权限
-
docker run:
# 在容器启动时自动修改权限
docker run -d -v my_volume:/data \
-e TARGET_UID=1000 \
--entrypoint /bin/sh \
nginx:latest -c "chown -R \$TARGET_UID:\$TARGET_UID /data && exec nginx"
-
docker-compose.yml:
services:
my_service:
image: my_image
volumes:
- my_volume:/container/path
entrypoint: ["sh", "-c", "chmod 755 /container/path && exec my_app"]
运行中修改:
docker exec -it my_container chmod 777 /container/path
4. 如何导入主机文件到Docker卷
三种常用方法
方法1:临时容器挂载
docker run --rm -v /host/path:/source -v my_volume:/target alpine:latest sh -c "cp -r /source/* /target/"
方法2:使用docker cp
# 先启动临时容器
docker run --name temp_container -v my_volume:/data -d nginx tail -f /dev/null
# 复制文件
docker cp host_file.txt temp_container:/data/
# 清理容器
docker rm -f temp_container
方法3:备份恢复模式导入数据到卷
tar -cvf - ./host_files | docker run --rm -i -v my_volume:/backup alpine:latest tar -xvf - -C /backup
5. 如何导出Docker卷并迁移到其他主机
完整迁移流程
1.在原主机打包数据:
docker run --rm -v my_volume:/data -v $(pwd):/backup alpine:latest tar -czvf /backup/volume_backup.tar.gz -C /data .
2.传输备份文件:
scp volume_backup.tar.gz user@newhost:/path/to/restore
3.在新主机恢复数据:
# 创建新卷
docker volume create new_volume
# 解压数据
docker run --rm -v new_volume:/data -v $(pwd):/backup \
alpine:latest tar -xzvf /backup/volume_backup.tar.gz -C /data
高级技巧:直接主机间传输
# 使用SSH管道直接传输
docker run --rm -v my_volume:/data alpine:latest tar -czf - -C /data . \
| ssh user@newhost "docker volume create new_volume && \
docker run --rm -i -v new_volume:/data alpine:latest tar -xzf - -C /data"
6.生产环境迁移docker卷数据
使用--volumes-from
配合专用备份容器,或采用Portainer等管理工具进行可视化操作
步骤 1:创建专用备份容器
首先,你需要创建一个专用的备份容器,该容器的作用是负责对需要迁移的 Docker 卷进行备份操作。可以使用一个包含基本工具(如 tar
用于打包文件)的基础镜像来创建这个容器。
docker create --name backup_container -v source_volume:/data_to_backup busybox true
-
--name backup_container
:为备份容器指定一个名称,方便后续引用。 -
-v source_volume:/data_to_backup
:将需要迁移的源卷source_volume
挂载到备份容器内的/data_to_backup
路径。 -
busybox true
:使用busybox
镜像,true
是一个简单的命令,用于启动容器但不执行其他操作。
步骤 2:备份源卷数据
接下来,运行一个临时容器,通过 --volumes-from
选项挂载备份容器的卷,然后将卷中的数据打包成一个压缩文件。
docker run --rm --volumes-from backup_container -v $(pwd):/backup busybox tar -czvf /backup/backup.tar.gz /data_to_backup
-
--rm
:容器运行结束后自动删除,避免留下无用的容器。 -
--volumes-from backup_container
:从backup_container
继承卷挂载,这样临时容器就可以访问source_volume
中的数据。 -
-v $(pwd):/backup
:将当前主机目录挂载到临时容器的/backup
路径,用于存放备份文件。 -
busybox tar -czvf /backup/backup.tar.gz /data_to_backup
:使用busybox
镜像中的tar
命令将/data_to_backup
目录下的数据打包成backup.tar.gz
文件,并保存到/backup
路径,即主机的当前目录。
步骤 3:将备份文件传输到目标主机
使用 scp
或其他文件传输工具将生成的备份文件 backup.tar.gz
传输到目标主机。
scp backup.tar.gz user@destination_host:/path/on/destination
步骤 4:在目标主机创建新卷和目标备份容器
在目标主机上创建一个新的 Docker 卷,用于接收迁移过来的数据,并创建一个目标备份容器。
docker volume create destination_volume
docker create --name destination_backup_container -v destination_volume:/data_to_restore busybox true
步骤 5:恢复数据到目标卷
在目标主机上运行一个临时容器,同样使用 --volumes-from
选项挂载目标备份容器的卷,然后将备份文件解压到目标卷中。
docker run --rm --volumes-from destination_backup_container -v /path/on/destination:/backup busybox tar -xzvf /backup/backup.tar.gz -C /data_to_restore
-
-xzvf
:tar
命令的选项,用于解压tar.gz
文件。 -
-C /data_to_restore
:指定解压文件的目标路径为/data_to_restore
,即目标卷挂载的路径。
步骤 6:使用目标卷
现在,你可以在目标主机上启动容器,并使用 -v选项挂载 destination_volume卷,从而使用迁移过来的数据。
docker run -d -v destination_volume:/path/in/container your_image
通过以上步骤,你就可以使用 --volumes-from
配合专用备份容器完成 Docker 卷的迁移。
4、docker cp
cp的细节
docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|- :把容器里面的复制出来
docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH:把外部的复制进去
-
SRC_PATH 指定为一个文件
- DEST_PATH 不存在:文件名为 DEST_PATH ,内容为SRC的内容
- DEST_PATH 不存在并且以 / 结尾:报错
- DEST_PATH 存在并且是文件:目标文件内容被替换为SRC_PATH的文件内容。
- DEST_PATH 存在并且是目录:文件复制到目录内,文件名为SRC_PATH指定的名字
-
SRC_PATH 指定为一个目录
-
DEST_PATH 不存在: DEST_PATH 创建文件夹,复制源文件夹内的所有内容
-
DEST_PATH 存在是文件:报错
-
DEST_PATH 存在是目录
-
SRC_PATH 不以 /. 结束:源文件夹复制到目标里面
-
SRC_PATH 以 /. 结束:源文件夹里面的内容复制到目标里面 自动创建文件夹不会做递归。把父文件夹做好
-
-
[root@hzh ~]# docker cp index.html mynginx4:/usr/share/nginx/html
[root@hzh ~]# docker cp mynginx4:/etc/nginx/nginx.conf nginx.conf
2、Docker网络
1、端口映射
docker create -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 --name=hello-mysql mysql:5.7
2、容器互联
–link name:alias ,name连接容器的名称,alias连接的别名
场景:我们无需暴露mysql的情况下,让web应用使用mysql;
docker run -d -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
docker run -d --link mysql01:mysql --name tomcat tomcat:7
docker exec -it tomcat bash
cat /etc/hosts
ping mysql
3、自定义网络
1、默认网络原理
Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据 Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。 因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。
Docker容器网络就很好的利用了Linux虚拟网络技术,在本地主机和容器内分别创建一个虚拟接口,并让 他们彼此联通(这样一对接口叫veth pair);
Docker中的网络接口默认都是虚拟的接口。虚拟接口的优势就是转发效率极高(因为Linux是在内核中进行数据的复制来实现虚拟接口之间的数据转发,无需通过外部的网络设备交换),对于本地系统和容器 系统来说,虚拟接口跟一个正常的以太网卡相比并没有区别,只是他的速度快很多。
-
原理:
- 1、每一个安装了Docker的linux主机都有一个docker0的虚拟网卡。桥接网卡
- 2、每启动一个容器linux主机多了一个虚拟网卡。
- 3、docker run -d -P --name tomcat --net bridge tomcat:8
2、网络模式
网络模式 | 配置 | 说明 |
---|---|---|
bridge模式 | –net=bridge | 默认值,在Docker网桥docker0上为容器创建新的网络 栈 |
none模式 | –net=none | 不配置网络,用户可以稍后进入容器,自行配置 |
container模式 | –net=container:name/id | 容器和另外一个容器共享Network namespace。 kubernetes中的pod就是多个容器共享一个Network namespace。 |
host模式 | –net=host | 容器和宿主机共享Network namespace |
用户自定义 | –net=mynet | 用户自己使用network相关命令定义网络,创建容器的时候可以指定为自己定义的网络 |
3、自建网络测试
#1、docker0网络的特点。,
默认、域名访问不通、--link 域名通了,但是删了又不行
#2、可以让容器创建的时候使用自定义网络,用自定义
1、自定义创建的默认default "bridge"
2、自定义创建一个自定义网络
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway
192.168.0.1 mynet
所有东西实时维护好,直接域名ping通
docker network connect [OPTIONS] NETWORK CONTAINER
#3、跨网络连接别人就用。把tomcat加入到mynet网络
docker network connect mynet tomcat
效果:
1、自定义网络,默认都可以用主机名访问通
2、跨网络连接别人就用 docker network connect mynet tomcat
#4、命令
1、容器启动,指定容器ip。 docker run --ip 192.168.0.3 --net 自定义网络
2、创建子网。docker network create --subnet 指定子网范围 --driver bridge 所有东西实时
维护好,直接域名ping通
3、docker compose 中的网络默认就是自定义网络方式。
docker run -d -P --network 自定义网络名(提前创建)