云原生(四) | Docker 篇之网络和存储原理
网络和存储原理
前言
博主语录:一文精讲一个知识点,多了你记不住,一句废话都没有
经典语录:勇者愤怒,抽刃向更强者;怯者愤怒,却抽刃向更弱者
一、Docker 存储
1、镜像如何存
1.0、自己探索
截取的 nginx 的分层
nginx 这个镜像怎么存的
使用:docker image inspect nginx
如图指示了镜像怎么存的
LowerDir :底层目录; diw (只是存储不同);包含小型 linux 和装好的软件
/var/lib/docker/overlay2/67b3802c6bdb5bcdbcccbbe7aed20faa7227d584ab37668a03ff6952e631f7f2/diff:用户文件;
/var/lib/docker/overlay2/f56920fac9c356227079df41c8f4b056118c210bf4c50bd9bb077bdb4c7524b4/diff: nginx 的启动命令放在这里
/var/lib/docker/overlay2/0e569a134838b8c2040339c4fdb1f3868a7118dd7f4907b40468f5fe60f055e5/diff: nginx 的配置文件在这里
/var/lib/docker/overlay2/2b51c82933078e19d78b74c248dec38164b90d80c1b42f0fdb1424953207166e/diff: 小 linux 系统
倒着看
"LowerDir":
"/var/lib/docker/overlay2/41e4fa41a2ad1dca9616d4c8254a04c4d9d6a3d462c862f1e9a0562de2384dbc-
init/diff:/var/lib/docker/overlay2/e3b8bdbb0cfbe5450696c470994b3f99e8a7942078e2639a788027529c6278f7/diff:/var/lib/docker/overlay2/67b3802c6bdb5bcdbcccbbe7aed20faa7227d584ab37668a03ff6952e631f7f2/diff:/var/lib/docker/overlay2/f56920fac9c356227079df41c8f4b056118c210bf4c50bd
9bb077bdb4c7524b4/diff:/var/lib/docker/overlay2/0e569a134838b8c2040339c4fdb1f3868a7118dd7f4907b40468f5fe60f055e5/diff:/var/lib/docker/overlay2/2b51c82933078e19d78b74c248dec38164b90d80c1b42f0fdb142495320766e/diff",
"MergedDir":
"/var/lib/docker/overlay2/41e4fa41a2ad1dca9616d4c8254a04c4d9d6a3d462c862f1e9a0562de2384dbc/merged",
"UpperDir": (镜像的上层可以感知变化)"/var/lib/docker/overlay2/41e4fa41a2ad1dca9616d4c8254a04c4d9d6a3d462c862f1e9a0562de2384dbc/diff",【容器的修改后的文件,保存在宿主机哪里呀。容器删除后,那些容器目录还存在吗?一定不再】
"WorkDir":
"/var/lib/docker/overlay2/41e4fa41a2ad1dca9616d4c8254a04c4d9d6a3d462c862f1e9a0562de2384dbc/work"
MergedDir :合并目录;容器最终的完整工作目录全内容都在合并层;数据卷在容器层产生;所有的增删改都在容器层;
UpperDir :上层目录;
WorkDir :工作目录(临时层),PID;
LowerDir(底层)\UpperDir(上层)\MergedDir\WorkDir(临时东西)
docker 底层的 storage driver 完成了以上的目录组织结果;
1.1、Images and layers
Docker 映像由一系列层组成。 每层代表图像的 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 命令构建您的应用程序。
最后,最后一层指定要在容器中运行的命令。
每一层只是与上一层不同的一组。 这些层彼此堆叠。
创建新容器时,可以在基础层之上添加一个新的可写层。 该层通常称为“容器层”。 对运行中的容器所做的所有更改(例如写入新文件,修改现有文件和删除文件)都将写入此薄可写容器层。
1.2、Container and layers
容器和镜像之间的主要区别是可写顶层。
在容器中添加新数据或修改现有数据的所有写操作都存储在此可写层中。
删除容器后,可写层也会被删除。 基础图像保持不变。 因为每个容器都有其自己的可写容器层,并且所有更改都存储在该容器层中,所以多个容器可以共享对同一基础映像的访问,但具有自己的数据状态。
下图显示了共享同一 Ubuntu 15.04 映像的多个容器。
1.3、磁盘容量预估
docker ps -s
size:用于每个容器的可写层的数据量(在磁盘上)。
virtual size:容器使用的用于只读图像数据的数据量加上容器的可写图层大小。
多个容器可以共享部分或全部只读图像数据。
从同一图像开始的两个容器共享 100%的只读数据,而具有不同图像的两个容器(具有相同的层)共享这些公共层。 因此,不能只对虚拟大小进行总计。这高估了总磁盘使用量,可能是一笔不小的数目。
1.4、镜像如何挑选
Busybox:是一个集成了一百多个最常用 Linux 命令和工具的软件。Linux 工具里的瑞士军刀
Alpine:Alpine 操作系统是一个面向安全的轻型 Linux 发行版经典最小镜像,基于 busybox,功能比 Busybox 完善。
Slim:docker hub 中有些镜像有 slim 标识,都是瘦身了的镜像。也要优先选择
无论是制作镜像还是下载镜像,优先选择 Alpine 类型.
1.5、Copy On Write
写时复制是一种共享和复制文件的策略,可最大程度地提高效率。
如果文件或目录位于映像的较低层中,而另一层(包括可写层)需要对其进行读取访问,则它仅使用现有文件。
另一层第一次需要修改文件时(在构建映像或运行容器时),将文件复制到该层并进行修改。 这样可以将 I / O 和每个后续层的大小最小化。
2、容器如何挂载
每一个容器里面的内容,支持三种挂载方式:
docker 自动在外部创建文件夹自动挂载容器内部指定的文件夹内容【Dockerfile VOLUME 指令的作用】
自己在外部创建文件夹,手动挂载
可以把数据挂载到内存中
--mount 挂载到 linux 宿主机,手动挂载(不用了)
-v 可以自动挂载,到 linux'主机或者 docker 自动管理的这一部分区域
Volumes(卷) :存储在主机文件系统的一部分中,该文件系统由 Docker 管理(在 Linux 上是“ / var / lib / docker / volumes /”)。 非 Docker 进程不应修改文件系统的这一部分。 卷是在 Docker 中持久存储数据的最佳方法。
Bind mounts(绑定挂载) :可以在任何地方 存储在主机系统上。 它们甚至可能是重要的系统文件或目录。 Docker 主机或 Docker 容器上的非 Docker 进程可以随时对其进行修改。
tmpfs mounts(临时挂载) :仅存储在主机系统的内存中,并且永远不会写入主机系统的文件系统
上面三种挂载方法可以参照官网
2.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 测试 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 自动管理的方式
docker inspect 容器的时候
# -v 不以绝对路径方式;
# 1、先在 docker 底层创建一个你指定名字的卷(具名卷) html
# 2、把这个卷和容器内部目录绑定
# 3、容器启动以后,目录里面的内容就在卷里面存着;
# -v nginxhtml:/usr/share/nginx/html 也可以以下操作
# 1、 docker create volume nginxhtml 如果给卷里面就行修改,容器内部的也就改了。
# 2、 docker volume inspect nginxhtml
# 3、docker run -d -P -v nginxhtml:/usr/share/nginx/html --name=nginx777 nginx
# 可以看到
"Mounts": [
{
"Type": "volume", //这是个卷
"Name": "html", //名字是 html
"Source": "/var/lib/docker/volumes/html/_data", //宿主机的目录。容器里面的哪两个文件都在
"Destination": "/usr/share/nginx/html", //容器内部
"Driver": "local",
"Mode": "z",
"RW": true, //读写模式
"Propagation": ""
}
]
# 卷:就是为了保存数据
docker volume # 可以对 docker 自己管理的卷目录进行操作; /var/lib/docker/volumes(卷的根目录)
# 一行命令启动 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
2.2、bind mount
如果将绑定安装或非空卷安装到存在某些文件或目录的容器中的目录中,则这些文件或目录会被安装遮盖,就像您将文件保存到 Linux 主机上的/ mnt 中一样,然后 将 USB 驱动器安装到/ mnt 中。在卸载 USB 驱动器之前,/ mnt 的内容将被 USB 驱动器的内容遮盖。 被遮盖的文件不会被删除或更改,但是在安装绑定安装或卷时将无法访问。
总结:外部目录覆盖内部容器目录内容,但不是修改。所以谨慎,外部空文件夹挂载方式也会导致容器内部是空文件夹
docker run -dP -v /my/nginx:/etc/nginx:ro nginx
# bind mount 和 volumes 的方式写法区别在于
# 所有以/开始的都认为是 bind mount ,不以/开始的都认为是 volumes.
警惕 bind mount 方式,文件挂载没有在外部准备好内容而导致的容器启动失败问题
3、管理卷
docker volume create xxx:创建卷名
docker volume inspect xxx:查询卷详情
docker volume ls: 列出所有卷
docker volume prune: 移除无用卷
4、docker cp
cp 的细节
docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|- :把容器里面的复制出来
docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH:把外部的复制进去
案例:
二、Docker 网络
1、端口映射
2、容器互联
--link name:alias ,name 连接容器的名称,alias 连接的别名
场景:我们无需暴露 mysql 的情况下,让 web 应用使用 mysql;
3、自定义网络
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
3.2、网络模式
3.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 中的网络默认就是自定义网络方式。
版权声明: 本文为 InfoQ 作者【Lansonli】的原创文章。
原文链接:【http://xie.infoq.cn/article/f0edf566cbe61f2f60a2b84b8】。文章转载请联系作者。
评论