Docker的鏡像是隻讀的,可是容器是可寫的,咱們能夠將數據寫入到容器,不過一旦容器刪除數據將會丟失,那麼有什麼辦法能將數據進行持久化存儲呢?html
在執行docker run 時,經過-v參數將主機目錄做爲容器的數據卷,這就是基於本地文件系統Volumn管理。node
以mysql鏡像爲例說明,進入到https://hub.docker.com/_/mysql查看詳情。mysql
[root@docker-node1 ~]# systemctl start docker
[root@docker-node1 ~]# docker pull mysql Using default tag: latest latest: Pulling from library/mysql 619014d83c02: Pulling fs layer 9ced578c3a5f: Pulling fs layer
注意:若是出現Get https://registry-1.docker.io/v2/library/mysql/manifests/latest: dial tcp: lookup registry-1.docker.io on 8.8.8.8:53: read udp 192.168.0.109:41429->8.8.8.8:53: i/o timeout這種問題,能夠嘗試修改/etc/resolv.conf文件,加入nameserver 8.8.4.4linux
[root@docker-node1 ~]# cat /etc/resolv.conf # Generated by NetworkManager nameserver 8.8.8.8 nameserver 8.8.4.4
[root@docker-node1 ~]# docker run -d --name mysql1 -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql 9dd537e48f16fd924f19f95aa38d15e08bdfa254d65ee66f1e19331ed6e79ce3 [root@docker-node1 ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9dd537e48f16 mysql "docker-entrypoint.s…" 20 seconds ago Up 11 seconds 3306/tcp, 33060/tcp mysql1
這樣就啓動了一個mysql的容器mysql1,可是顯然咱們並無指定數據庫中表指定放到什麼地方,那麼它給咱們自動放到什麼地方了呢?nginx
咱們能夠看看mysql的Dockerfile:git
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目錄中了。github
另外能夠看到主機上有一條volume的記錄:web
[root@docker-node1 ~]# docker volume ls DRIVER VOLUME NAME local 5c4fbbc613e046baf9e148a301ef94ef09e4fc57312edd907885336e9ecd5bc1
能夠看看這個存儲卷記錄的具體信息:sql
[root@docker-node1 ~]# docker volume inspect 5c4fbbc613e046baf9e148a301ef94ef09e4fc57312edd907885336e9ecd5bc1 [ { "CreatedAt": "2020-02-03T13:24:30+08:00", "Driver": "local", "Labels": null, "Mountpoint": "/var/lib/docker/volumes/5c4fbbc613e046baf9e148a301ef94ef09e4fc57312edd907885336e9ecd5bc1/_data", "Name": "5c4fbbc613e046baf9e148a301ef94ef09e4fc57312edd907885336e9ecd5bc1", "Options": null, "Scope": "local" } ]
持久化存儲docker
若是咱們講這個容器刪掉,這個存儲卷還存在嗎?能夠嘗試一下:
[root@docker-node1 ~]# docker rm -f mysql1 #刪掉mysql1容器 mysql1 [root@docker-node1 ~]# docker volume ls #存儲卷仍舊存在 DRIVER VOLUME NAME local 5c4fbbc613e046baf9e148a301ef94ef09e4fc57312edd907885336e9ecd5bc1
能夠看到雖然mysql的容器不在了,可是它的存儲卷依舊存在。
上面你也許已經看到了一些須要自定義的地方:其一,volume name的名字太長了,須要本身指定;其二,volume持久化的目錄須要本身指定。
[root@docker-node1 ~]# docker run -d -v /home/mysql:/var/lib/mysql --name mysql1 -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql 0e560c5c9caf902c0d9647ef1d7995803d9dfde8e0db2c529d97f913f943bdf5
上面經過-v參數指定mysql的掛載位置(主機文件位置:容器文件位置[Dockerfile中已經指定]),經過--name指定容器的名稱,以下所示:
[root@docker-node1 ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0e560c5c9caf mysql "docker-entrypoint.s…" 9 seconds ago Up 7 seconds 3306/tcp, 33060/tcp mysql1
如今,能夠先進入到這個容器中,對mysql的數據庫中作一些改變,而後刪掉容器:
(1)進入容器
[root@docker-node1 ~]# docker exec -it mysql1 /bin/sh
(2)進入mysql
# mysql -uroot Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 8 Server version: 8.0.19 MySQL Community Server - GPL Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
(3)建立test數據庫
mysql> create database test; Query OK, 1 row affected (0.36 sec) mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | | test | +--------------------+ 5 rows in set (0.00 sec)
(4)刪掉mysql1容器
[root@docker-node1 ~]# docker rm -f mysql1 mysql1
(5)新建mysql2容器
新建mysql2容器,而且指向mysql1容器的存儲卷:
[root@docker-node1 ~]# docker run -d -v /home/mysql:/var/lib/mysql --name mysql2 -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql 9fc1aff1e798b0b6b4c01b26160877253c655f137a542734eb81b2b8984af66c
而後能夠進入到mysql2容器中查看mysql中是否有mysql1容器建立的test數據庫:
[root@docker-node1 ~]# docker exec -it mysql2 /bin/sh #進入mysql2容器 # mysql -uroot Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 8 Server version: 8.0.19 MySQL Community Server - GPL Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | | test | +--------------------+ 5 rows in set (0.16 sec)
能夠看到倒是存在test數據庫,這樣也就實現了volume持久化。
[root@docker-node1 bindmounting-test]# ls Dockerfile index.html
FROM nginx #基礎鏡像 WORKDIR /usr/share/nginx/html #工做目錄,容器內的目錄 COPY index.html . #將本機當前目錄下的index.html文件拷貝到上述工做目錄下
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>hello</title> </head> <body> <h1>Hello Docker! </h1> </body> </html>
[root@docker-node1 bindmounting-test]# docker build -t docker-nginx . Sending build context to Docker daemon 3.072kB Step 1/3 : FROM nginx ---> f68d6e55e065 Step 2/3 : WORKDIR /usr/share/nginx/html ---> Running in 3b784d71c4dc Removing intermediate container 3b784d71c4dc ---> 10cef7e9bbb9 Step 3/3 : COPY index.html . ---> f43b1a1b7bef Successfully built f43b1a1b7bef Successfully tagged docker-nginx:latest
[root@docker-node1 bindmounting-test]# docker run -d -p 80:80 --name web docker-nginx 22c28d4887d222785a3c60ca28c2fe79ff82ff9e630af0cdbb48232171732c90
上面經過-p進行了端口暴露,可經過外網訪問:
可是難道每次修改index.html文件都須要從新生成鏡像,而後運行嗎?咱們能夠經過bing mounting進行映射,若是本地文件變了,容器內的就會改變。這樣就不會從新生成鏡像了。
[root@docker-node1 bindmounting-test]# ls Dockerfile index.html [root@docker-node1 bindmounting-test]# docker run -d -v $(pwd):/usr/share/nginx/html -p 80:80 --name web docker-nginx f4661067be3fdead6c627bc00a054244b92207d42baebafdc37b8c8a8fe6f3cb
能夠看到上面我將$(pwd)這個當前路勁的文件,也就是bindmounting-test文件夾中內容映射到容器/usr/share/nginx/html目錄下,若是本地bindmounting-test文件夾下有文件更改了,容器中天然會變化。
例如,修改本地index.html文件中的內容:
[root@docker-node1 bindmounting-test]# vim index.html
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>hello</title> </head> <body> <h1>Hello </h1> </body> </html>
此時,再刷新頁面:
這樣當在容器內或者容器外更改 映射文件夾內的內容時 兩邊都會改變,很利於開發者在linux進行應用的迭代更新部署。
docker run -v /home/mysql:/var/lib/mysql
上面的映射關係都是 主機:容器