zhaoyu@home:~$

docker-文件系统

从容器的角度看,容器拥有一套由镜像提供的独占的文件系统副本。通过一个叫联合文件系统(UFS)的东西来实现。 UFS是文件系统隔离的重要的一环,其他还包括MNT namespace和chroot系统调用。
linux内核为MNT系统提供了一个namespace。当docker创建一个新的container时,每个新的container都拥有它自己的MNT namespace。 容器会创建一个新的挂载点。
最后,chroot会让镜像的文件系统的root成为容器的root。用于阻止容器内运行的程序引用主机文件系统的其他部分。

挂载点

每个容器拥有一个MNT namespace和一个文件树root。每个容器的文件树的root就是镜像的挂载点。每个容器都有一组不同的挂载点。 容器挂载的存储有三种类型:

  • 绑定挂载点
  • 内存存储。
  • docker 卷

如下:

所有这三种类型的存储都可使用--mount选项创建。

绑定挂载点

绑定挂载点主要用于容器需要使用主机上的文件或者路径,或者容器程序产生了需要外部容器或者用户处理的日志或者文件。如nginx配置或者容器产生log文件。

CONF_SRC=~/example.conf; \
CONF_DST=/etc/nginx/conf.d/default.conf; \
LOG_SRC=~/example.log; \
LOG_DST=/var/log/nginx/custom.host.access.log; \
docker run -d --name diaweb \
--mount type=bind,src=${CONF_SRC},dst=${CONF_DST},readonly=true \
--mount type=bind,src=${LOG_SRC},dst=${LOG_DST} \
-p 80:80 \
nginx:latest

当你在容器上挂载一个docker卷时,容器生产的内容将会替换主机的内容。而创建绑定挂载点后,镜像提供的内容会被主机上的内容覆盖。

内存存储

大多数软件和应用有私钥文件,数据库密码,或其他敏感文件。对于这种情况,需要使用内存存储,通过type=tmpfs设置。

docker run --rm \
--mount type=tmpfs,dst=/tmp \
--entrypoint mount \
alpine:latest -v

该命令创建了一个空的tmpfs设备,并挂载到容器的/tmp文件树下。任何在该文件树下创建的文件都会被写入内存。 命令执行完成后,会输出一系列挂载点信息

tmpfs on /dev type tmpfs (rw,nosuid,size=65536k,mode=755)
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=666)

第一行表示:

  • 一个tmpfs设备挂载到/dev目录下。
  • 设备拥有一个tmpfs文件系统。
  • rw表示读写权限。

默认的,tmpfs没有大小限制,且拥有所有文件权限,(1777)。如果需要修改,可以在挂载的时候设置参数如下:

docker run --rm --mount type=tmpfs,dst=/tmp,tmpfs-size=16k,tmpfs-mode=1770 \
--entrypoint mount alpine:latest -v

docker卷

docker卷是有docker管理的文件系统树,可以被主机系统的磁盘存储或者云存储实现。共享数据就是卷的重要特性。 所有的命令都可以使用docker column子命令实现。
创建一个名为location-example的卷: ```shell script docker volume create –driver local –label example=location location-example

命令执行完成后,主机文件系统的一部分会被Docker管理。`--driver`指定创建卷的插件,默认为local插件。`--label`设置卷的标签。

查看卷的详情:
```shell script
docker volume inspect location-example

结果如下:

[
    {
        "CreatedAt": "2020-07-23T19:14:03+08:00",
        "Driver": "local",
        "Labels": {
            "example": "location"
        },
        "Mountpoint": "/var/lib/docker/volumes/location-example/_data",
        "Name": "location-example",
        "Options": {},
        "Scope": "local"
    }
]

在创建卷后,可以挂在卷到某个容器,如cassandra。当cass1容器删除后,docker卷还会保留。 ```shell script docker run -d –volume location-example:/var/lib/cassandra/data –name cass1 cassandra:2.2

其他命令:
```shell script
docker volume ls # 查看所有卷:
docker volume prune # 删除所有无用的卷
docker volume rm #删除一个或多个卷

docker run命令提供了--volumes-from选项,用于拷贝已有容器的挂载信息到新的容器中。如下, 第一步,创建容器fowler ```shell script docker run –name fowler
–mount type=volume,dst=/library/PoEAA
–mount type=bind,src=/tmp,dst=/library/DSL
alpine:latest
echo “Fowler collection created.”

第二步,创建容器knuth
```shell script
docker run --name knuth \
--mount type=volume,dst=/library/TAoCP.vol1 \
--mount type=volume,dst=/library/TAoCP.vol2 \
alpine:latest \
echo "Knuth collection created"

第三步,使用--volumes-from选项创建容器reader。 ```shell script docker run –name reader
–volumes-from fowler
–volumes-from knuth
alpine:latest ls -l /library/

第四步,查看容器reader的挂载信息。可以看到已经包括了fowler,和knuth的挂载信息。
```shell script
docker inspect --format "" reader

查看文件系统的变化。

容器可以查看文件系统的变化。 ```shell script docker container diff container-name

其结果类似如下:
```shell script
A /hello/world   # A 为添加的目录
C /bin           # C 为修改的目录
D /bin/vi        # D 为删除的目录