一、Data Volume
在执行docker run 时,通过-v参数将主机目录作为容器的数据卷,这就是基于本地文件系统Volumn管理。

1、Volume类型
受管理的Volume,由docker后台自动创建
绑定挂载的Volume,具体挂载位置由用户指定

2、docker后台自动创建
(1)启动docker服务

# systemctl start docker

(2)拉取mysql镜像

# docker pull mysql

(3)运行mysql镜像

# docker run -d --name mysql1 -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql
# docker ps -a

这样就启动了一个mysql的容器mysql1,但是显然我们并没有指定数据库中表指定放到什么地方,那么它给我们自动放到什么地方了呢?
我们可以看看mysql的Dockerfile:

FROM debian:stretch-slim

# add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added
RUN groupadd -r mysql && useradd -r -g mysql mysql

RUN apt-get update && apt-get install -y --no-install-recommends gnupg dirmngr && rm -rf /var/lib/apt/lists/*

# add gosu for easy step-down from root
ENV GOSU_VERSION 1.7
RUN set -x \
    && apt-get update && apt-get install -y --no-install-recommends ca-certificates wget && rm -rf /var/lib/apt/lists/* \
    && wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$(dpkg --print-architecture)" \
    && wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$(dpkg --print-architecture).asc" \
    && export GNUPGHOME="$(mktemp -d)" \
    && gpg --batch --keyserver ha.pool.sks-keyservers.net --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4 \
    && gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu \
    && gpgconf --kill all \
    && rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc \
    && chmod +x /usr/local/bin/gosu \
    && gosu nobody true \
    && apt-get purge -y --auto-remove ca-certificates wget

RUN mkdir /docker-entrypoint-initdb.d

RUN apt-get update && apt-get install -y --no-install-recommends \
# for MYSQL_RANDOM_ROOT_PASSWORD
        pwgen \
# for mysql_ssl_rsa_setup
        openssl \
# FATAL ERROR: please install the following Perl modules before executing /usr/local/mysql/scripts/mysql_install_db:
# File::Basename
# File::Copy
# Sys::Hostname
# Data::Dumper
        perl \
    && rm -rf /var/lib/apt/lists/*

RUN set -ex; \
# gpg: key 5072E1F5: public key "MySQL Release Engineering <mysql-build@oss.oracle.com>" imported
    key='A4A9406876FCBD3C456770C88C718D3B5072E1F5'; \
    export GNUPGHOME="$(mktemp -d)"; \
    gpg --batch --keyserver ha.pool.sks-keyservers.net --recv-keys "$key"; \
    gpg --batch --export "$key" > /etc/apt/trusted.gpg.d/mysql.gpg; \
    gpgconf --kill all; \
    rm -rf "$GNUPGHOME"; \
    apt-key list > /dev/null

ENV MYSQL_MAJOR 8.0
ENV MYSQL_VERSION 8.0.19-1debian9

RUN echo "deb http://repo.mysql.com/apt/debian/ stretch mysql-${MYSQL_MAJOR}" > /etc/apt/sources.list.d/mysql.list

# the "/var/lib/mysql" stuff here is because the mysql-server postinst doesn't have an explicit way to disable the mysql_install_db codepath besides having a database already "configured" (ie, stuff in /var/lib/mysql/mysql)
# also, we set debconf keys to make APT a little quieter
RUN { \
        echo mysql-community-server mysql-community-server/data-dir select ''; \
        echo mysql-community-server mysql-community-server/root-pass password ''; \
        echo mysql-community-server mysql-community-server/re-root-pass password ''; \
        echo mysql-community-server mysql-community-server/remove-test-db select false; \
    } | debconf-set-selections \
    && apt-get update && apt-get install -y mysql-community-client="${MYSQL_VERSION}" mysql-community-server-core="${MYSQL_VERSION}" && rm -rf /var/lib/apt/lists/* \
    && rm -rf /var/lib/mysql && mkdir -p /var/lib/mysql /var/run/mysqld \
    && chown -R mysql:mysql /var/lib/mysql /var/run/mysqld \
# ensure that /var/run/mysqld (used for socket and lock files) is writable regardless of the UID our mysqld instance ends up having at runtime
    && chmod 777 /var/run/mysqld

VOLUME /var/lib/mysql  #持久化存储
# Config files
COPY config/ /etc/mysql/
COPY docker-entrypoint.sh /usr/local/bin/
RUN ln -s usr/local/bin/docker-entrypoint.sh /entrypoint.sh # backwards compat
ENTRYPOINT ["docker-entrypoint.sh"]

EXPOSE 3306 33060
CMD ["mysqld"]

实际上已经帮我们持久化存储到主机的/var/lib/mysql目录中了。
(4)查看这个存储卷记录的具体信息:

# docker volume ls
# docker volume inspect 209d1d84e44dd05db4b2b298ccb315461b7d546c855be32cd98842f57939fd45
[
    {
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/209d1d84e44dd05db4b2b298ccb315461b7d546c855be32cd98842f57939fd45/_data",
        "Name": "209d1d84e44dd05db4b2b298ccb315461b7d546c855be32cd98842f57939fd45",
        "Options": {},
        "Scope": "local"
    }
]

(5)持久化存储

# docker rm -f mysql1 #删掉mysql1容器
mysql1
# docker volume ls #存储卷仍旧存在
DRIVER              VOLUME NAME
local               209d1d84e44dd05db4b2b298ccb315461b7d546c855be32cd98842f57939fd45

可以看到虽然mysql的容器不在了,但是它的存储卷依旧存在

3、用户指定挂载位置
(1)容器重命名以及指定挂载位置

# docker run -d -v /home/mysql:/var/lib/mysql --name mysql1 -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql

上面通过-v参数指定mysql的挂载位置(主机文件位置:容器文件位置[Dockerfile中已经指定]),通过–name指定容器的名称
(2)测试持久化
现在,可以先进入到这个容器中,对mysql的数据库中做一些改变,然后删掉容器:

进入容器

# docker exec -it mysql1 /bin/sh

进入mysql

# mysql -uroot

创建test数据库

mysql> create database test;

删掉mysql1容器

# docker rm -f mysql1

新建mysql2容器
新建mysql2容器,并且指向mysql1容器的存储卷:

# docker run -d -v /home/mysql:/var/lib/mysql --name mysql2 -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql

然后可以进入到mysql2容器中查看mysql中是否有mysql1容器创建的test数据库:

# docker exec -it mysql2 /bin/sh #进入mysql2容器
# mysql -uroot
mysql> show databases; 
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| test               |
+--------------------+

存在test数据库,实现了volume持久化

二、Bind Mounting
1、bing mounting和data volume的区别
data volume 需要在 Dockerfile文件中 定义 volume,这种方式较多的是将容器映射到本地,实现容器与外部程序共享数据。
bind mounting 只需要 -v 指明 容器外部文件夹和容器映射文件夹的对应关系,将本地的文件映射到容器内。

2、bind mounting的应用
(1)在bindmounting-test文件夹中新建两个文件

# pwd
/bindmounting-test
# ls
Dockerfile  index.html

(2)编写Dockerfile文件

FROM nginx     #基础镜像
WORKDIR /usr/share/nginx/html  #工作目录,容器内的目录
COPY index.html .  #将本机当前目录下的index.html文件拷贝到上述工作目录下

(3)编写index.html

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>hello</title>
</head>
<body>
  <h1>Hello Docker! </h1>
</body>
</html>

(4)生成镜像

# docker build -t docker-nginx .

(5)运行docker-nginx镜像

# docker run -d -p 80:80 --name web docker-nginx

上面通过-p进行了端口暴露,可通过外网访问

docker rabbitmq没有持久化 docker持久化存储_html


但是难道每次修改index.html文件都需要重新生成镜像,然后运行吗?我们可以通过bing mounting进行映射,如果本地文件变了,容器内的就会改变。这样就不会重新生成镜像了。

(6)使用bind mounting

# ls
Dockerfile  index.html
# docker run -d -v $(pwd):/usr/share/nginx/html -p 80:80 --name web docker-nginx

可以看到上面我将$(pwd)这个当前路劲的文件,也就是bindmounting-test文件夹中内容映射到容器/usr/share/nginx/html目录下,如果本地bindmounting-test文件夹下有文件更改了,容器中自然会变化。

例如,修改本地index.html文件中的内容:

# vim index.html
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">

  <title>hello</title>

</head>

<body>
  <h1>Hello </h1>
</body>
</html>

此时,再刷新页面

docker rabbitmq没有持久化 docker持久化存储_html_02

三、使用数据卷
还可以使用docker volume命令来创建卷

# docker volume create my-data
# docker volume ls
# docker volume inspect my-data