0911_docker学习(7)

195 阅读4分钟

数据共享

docker 可以用来隔离环境,让容器内和容器外的环境互不干扰(其实还是会有影响的),那么运行在容器内的程序,可能会产生数据,那么这些数据默认也是在这个容器内的,那么如何从容器外获取这些数据呢?要是我想销毁这个容器,那容器里面的数据,会不会也被销毁嘛?要是我想升级容器,数据是不是得进行迁移呀?

Linux 的文件系统是一棵树,上面可以通过创建挂载点的方式,将存储介质挂载到文件系统上,从而能够访问磁盘里的数据。

同样的,每一个容器都有 MNT namespace 和 文件树,那么同样能够创建挂载点,将主机上面的存储介质挂载到容器的挂载点上面,当容器内部向特定的挂载点写入数据,等同于在主机上面写入数据。这样数据就能够保存在主机上面。

docker 里面有三种常用的存储方式:

  • Bind mounts
  • In-memory storage
  • Docker volumes

image.png

Bind mounts

Bind mounts 是将主机上某个路径挂载到容器内部的某个路径上,从而达到数据共享的效果。不仅可以挂载目录,也能够挂载文件。它也存在一些问题,它依赖与主机上的路径,如果主机上面没有相应的路径,那么它将不能挂载成功。另外一个问题是,它会增加与其他容器冲突的可能性,容器之间可能会抢占文件的使用权。 因此,最好在通用平台或硬件池中避免这些类型的特定绑定。

# 我当前的绝对路径是 /home/zhui/playground/
cat > ./example.html << EOF

Hello Docker, How are you ?

EOF

touch ./example.log
cat > ./example.conf <<EOF
server {
 listen 80;
 server_name localhost;
 access_log /var/log/nginx/custom.host.access.log main;
 location / {
   root /usr/share/nginx/html;
   index index.html index.htm;
 }
}
EOF

LOG_SRC=/home/zhui/playground/example.log
LOG_DST=/var/log/nginx/custom.host.access.log
CONF_DST=/etc/nginx/conf.d/default.conf
CONF_SRC=/home/zhui/playground/example.conf
HELLO_SRC=/home/zhui/playground/example.html
DEFAULT_DST=/usr/share/nginx/html/index.html

docker run -d --name nginx-web \
--mount type=bind,src=${CONF_SRC},dst=${CONF_DST},readonly=true  \
--mount type=bind,src=${LOG_SRC},dst=${LOG_DST} \
--mount type=bind,src=${HELLO_SRC},dst=${DEFAULT_DST} \
-p 80:80 nginx:latest

image.png

In-memory storage

大多数的服务软件,比如 web 应用程序,里面可能会使用私钥、数据库密码、API key、或者一些敏感的配置文件,需要一些空间临时进行缓冲。

这种情况下,把这些数据写到主机文件里面就不太合适了,那么可以将这些缓存数据,写到内存里面。


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

# 例子

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

上面的命令,能够创建一个 tmpfs 的空设备(docker 自己定义并创建),并将其挂载到容器的 /tmp 目录下,容器内对 /tmp 目录下的操作,都将放入主机的内存中,从而保护敏感文件。

Docker volumes

volume(卷) 跟 bind mounts 是有区别的,最大的一点区别是容器实例能够在不知道主机的文件系统的情况来,通过卷来共享数据。

卷的其中一个特性是能够共享对数据的访问,而且卷的生命周期是独立于容器的,也就是说,即使某个容器使用了某个卷,当这个容器被销毁,使用的卷依然存在,而且能够被其他容器所使用。


# 创建卷
docker volume create --driver local --label example=location location-example


# 查看所有卷
docker volume ls

# 查看卷的信息
docker volume inspect  location-example

# 查看 Mountpoint 发现他是由 docker 自动生成的
ocker volume inspect --format "{{json .Mountpoint}}" location-example

# 删除所有未被使用的卷
docker volume prune


# 删除卷
docker volume rm location-example


# 先创建一个卷
docker volume create --driver local --label example=cassandra cass-shared

# 容器上使用卷
docker run -d --volume cass-shared:/var/lib/cassandra/data --name cass cassandra:2.2


# 删除容器后,volume 依然存在
docker container rm -f cass
docker volume ls


卷可以有名字(对人类友好),也可以是匿名的,当它是匿名卷时,它的名字,就是一大串的哈希字符。 通常生成匿名卷的方式是直接使用了 docker volume create(不带其他参数),或者是 docker rundocker create 时不指定卷名。

docker 还提供 volumees-from 参数,能够直接从其他容器(被称为数据卷容器)那里获取数据,实现数据共享。


# 生成一个匿名卷
docker volume create

# 直接在创建容器实例时,同时创建匿名卷
docker run --name fowler \
--mount type=volume,dst=/library \
\alpine:latest touch /library/{1..4}.txt



#  通过 --volumes-from 参数关联卷
docker run --name reader \
--volumes-from fowler \
alpine:latest ls -l /library/

其他参考

Docker 基础知识 - 使用绑定挂载(bind mounts)管理应用程序数据

## 数据卷容器