08.Docker Storage
Docker 镜像层
在使用 Dockerfile 构建镜像时,每一个 Dockerfile 指令都会创建一个新的 Docker 镜像层,每一层都是基于上一层的构建,只会包含和上一层的新的更改,因此大小不会迅速增加。
如以下两个 Dockerfile 文件:
dockerfile :
FROM ubuntu
# 更换 Ubuntu 软件源为阿里云源
RUN sed -i 's|http://archive.ubuntu.com/ubuntu/|http://mirrors.aliyun.com/ubuntu/|g' /etc/apt/sources.list && \
sed -i 's|http://security.ubuntu.com/ubuntu/|http://mirrors.aliyun.com/ubuntu/|g' /etc/apt/sources.list && \
apt-get update && \
apt-get -y install python3 python3-pip
# 配置 pip 使用阿里云镜像
RUN mkdir -p ~/.pip && \
echo "[global]\nindex-url = https://mirrors.aliyun.com/pypi/simple/\n[install]\ntrusted-host = mirrors.aliyun.com" > ~/.pip/pip.conf
# 安装 Flask
RUN pip install flask --break-system-packages
# 复制源代码到容器中
COPY . /opt/source-code/
# 设置工作目录
WORKDIR /opt/source-code
# 使用 Flask 运行应用
ENTRYPOINT ["flask", "run"]dockerfile2 :
FROM ubuntu
# 更换 Ubuntu 软件源为阿里云源
RUN sed -i 's|http://archive.ubuntu.com/ubuntu/|http://mirrors.aliyun.com/ubuntu/|g' /etc/apt/sources.list && \
sed -i 's|http://security.ubuntu.com/ubuntu/|http://mirrors.aliyun.com/ubuntu/|g' /etc/apt/sources.list && \
apt-get update && \
apt-get -y install python3 python3-pip
# 配置 pip 使用阿里云镜像
RUN mkdir -p ~/.pip && \
echo "[global]\nindex-url = https://mirrors.aliyun.com/pypi/simple/\n[install]\ntrusted-host = mirrors.aliyun.com" > ~/.pip/pip.conf
# 安装 Flask
RUN pip install flask --break-system-packages
# 复制源代码到容器中
COPY file.txt /opt/source-code/
# 设置工作目录
WORKDIR /opt/source-code
# 使用 Flask 运行应用
ENTRYPOINT ["flask", "run"]观察文件,两个 Dockerfile 文件中只有 COPY 指令不同,第一个为 COPY . /opt/source-code/ ,第二个为 COPY file.txt /opt/source-code/ 。
可以在当前目录创建文件,以便保持复制的文件确实不同
先构建 dockerfile 的镜像:
docker build -f .\dockerfile -t flask-app .使用 docker images 查看当前镜像的大小,为 549MB :
PS X:> docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
flask-app latest 12dd24c0bcd1 2 minutes ago 549MB然后构建 dockerfile2 的镜像:
docker build -f .\dockerfile2 -t flask-app2 .再次查看镜像大小:
PS X:> docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
flask-app2 latest 447a485a4d4f 6 seconds ago 549MB
flask-app latest 12dd24c0bcd1 3 minutes ago 549MB发现两个镜像大小相同,但实际上两个镜像一共占用宿主机约为 549MB 大小,而不是两个镜像大小之和 549 + 549 = 1098MB 。原因是两个 Dockerfile 文件除了 COPY 指令前的所有指令全部相同,因此之前的每个所有指令都会创建一个新层,而这些层会被创建第二个镜像时复用,而不是创建新的层,因此他们共享同一个镜像文件(共享的是底层的文件)。
只有当所有共享的镜像文件都被删除时,原本的层才会被删除。当删除第一个构建的镜像 flask-app 时,镜像 flask-app2 仍可使用。
容器层
容器层是可读可写的,镜像层是只读的:

所以镜像中的文件不可被修改。
使用镜像创建容器后,容器内的文件会拷贝一份到容器内,可在容器内修改这些文件,如上图中的 app.py 文件;可在容器内创建新文件,如上图中的 temp.txt 文件。
卷映射
容器内创建的数据不会被持久化保存,若想要持久化保存,则将数据保存到宿主机上,建立容器内和宿主机目录(或卷)之间的映射,使得容器内产生的文件到容器内的目标目录后,相当于保存到了宿主机上的指定目录(卷)。
在 Linux 系统上,卷的默认保存位置在 /var/lib/docker/volumes 中,但也可以显式指定映射的目标目录。使用 -v 选项指定映射:
docker run -v data_volumes:/var/lib/mysql mysql
这里给出了宿主机上的相对路径,使用了 volume 模式。
相当于将宿主机上 /var/lib/docker/volumes/data_volumes 目录和容器内 /var/lib/mysql 目录建立映射,此后在容器内产生到 /var/lib/mysql 目录下的文件都将被保存到宿主机的 /var/lib/docker/volumes/data_volumes 卷内,实现持久化。
data_volumes是 Docker 内部管理的卷名称,而不是宿主机上的目录,默认存储在/var/lib/docker/volumes/目录下。在
volumes目录下会存在一个名为data_volumes的文件夹,下面会有一个_data的文件夹,产生的文件将存放此文件夹内,data_volumes理解为一个卷,如果没有该卷,Docker 会自动创建它。
也可以显式指定宿主机上的其他目录,使用绝对路径,此时使用的是 bind 模式:
docker run -v /dara/mysql:/var/lb/mysql mysql如果使用
bind模式,则映射到宿主机上的为目录而不是卷。
IMPORTANT
注意, -v 选项是一个过时的选项,现在要建立卷映射,一般使用 –mount 选项。
--mount 选项:
使用 --mount 选项建立映射的指令格式如下:
docker run --mount type=bind,source=/data/mysql,target=/var/lib/mysql mysql- 指定使用
bind模式,后面给出绝对路径(mount强制要求给出绑定的模式,bind或者volume) source给出宿主机绝对路径target给出容器内路径
NOTE
--mount 的语法更严格,比如 source 必须显式为绝对路径。
- 使用
-v选项时,Docker 会自动根据路径判断是创建一个 卷(volume) 还是 绑定挂载(bind mount)。- 卷(Volume) 存储在 Docker 管理的
/var/lib/docker/volumes/目录下,并且在卷内部有一个_data子目录来存储实际数据。- 绑定挂载(Bind Mount) 使用宿主机上的路径作为挂载点,数据直接存储在宿主机的目录中。
- 推荐使用
--mount选项,它提供了更清晰和严格的语法。