Docker持久化处理
生产环境中使用Docker的过程中,往往需要对数据进行持久化,或者需要在多个容器之间进行数据共享,这必然涉及容器的数据管理操作,容器管理中主要有两种方式,数据卷(Data Volumes)
,数据卷容器(Data Volume Containers)
,本小结将首先介绍如何在容器内创建数据卷,并且把本地的目录或文件挂载到容器内的数据卷中.接下来,会介绍如何使用数据卷容器在容器和主机、容器和容器之间共享数据,并实现数据的备份和恢复.
◆数据卷◆
数据卷是一个可供容器使用的特殊目录,它将主机操作系统目录直接映射进容器,类似于Linux中的mount操作.
数据卷可以提供很多有用的特性,如下所示: ● 数据卷可以在容器之间共享和重用,容器间传递数据将变得高效方便. ● 对数据卷内数据的修改会立马生效,无论是容器内操作还是本地操作. ● 对数据卷的更新不会影响镜像,解耦了应用和数据. ● 卷会一直存在,直到没有容器使用,可以安全地卸载它.
挂载一个本地目录作为数据卷:
1.在本地主机创建一个目录,并写入一些数据,来模拟本地数据.
代码语言:javascript复制[root@localhost ~]# mkdir /data
[root@localhost ~]# echo "hello mkdirs.com" > /data/index.html
2.开启容器,并让容器读取本地的/data
目录.
[root@localhost ~]# docker run -d -p 8080:80 --name MyWeb -v /data:/usr/local/apache2/htdocs httpd:latest
2882b3edda42fe153a897d3dc21f73835eb57c14019b5e810066c34e0eda4c0c
[参数解释]
-d #以守护进程运行
-p #将容器中的80口,映射到本地主机的8080
--name #指定一个容器名称
-v #上面指的是,将本地/data目录挂载得到容器中的/usr/local目录中.
-P #是将容器服务暴露的端口,是自动映射到本地主机的临时端口.
[root@localhost ~]# curl 127.0.0.1:8080
hello mkdirs.com
◆数据卷容器◆
如果用户需要在多个容器之间共享一些持续更新的数据,最简单的方式是使用数据卷容器.数据卷容器也是一个容器,但是它的目的是专门用来提供数据卷供其他容器挂载.
1.首先,创建一个数据卷容器dbdata,并在容器中创建一个数据卷/dbdata的目录.
代码语言:javascript复制[root@localhost ~]# docker run -itd -v /usr/local/apache2/htdocs --name dbdata centos:latest
1bc16a7978db7db83a4a107bf2fe1c4c42c4c7fffa7dd92372a6aacb68ccfdd0
[root@localhost ~]# docker exec -it dbdata /bin/bash
[root@1bc16a7978db /]# echo "hello mkdirs.com" > /usr/local/apache2/htdocs/index.html
[root@1bc16a7978db /]# ls -lh /usr/local/apache2/htdocs/index.html
total 4.0K
-rw-r--r-- 1 root root 17 Dec 15 11:37 index.html
[root@1bc16a7978db /]# exit
2.然后,可以在其他容器中使用--volumes-from
来挂载dbdata容器中的数据卷,例如创建db1和db2两个容器,并从dbdata容器挂载数据卷.
[root@localhost ~]# docker run -d -p 801:80 --volumes-from dbdata --name db1 httpd:latest
123e75f38947f3294ac77a08bf4380f311d09cc176b576c61499139d75b35db3
[root@localhost ~]# docker run -d -p 802:80 --volumes-from dbdata --name db2 httpd:latest
a4e0f8016af6b89e31a637b1482b0849dcea26e4004298def4abce44c84d6dd6
3.分别访问两个不同的端口,会发现网页展现效果是一样的,也就是说,db1和db2共享了dbdata容器里指定文件的内容.
代码语言:javascript复制[root@localhost ~]# netstat -antp |grep 801
tcp6 0 0 :::801 :::* LISTEN 3998/docker-proxy
[root@localhost ~]# netstat -antp |grep 802
tcp6 0 0 :::802 :::* LISTEN 4157/docker-proxy
[root@localhost ~]# curl 127.0.0.1:801
hello mkdirs.com
[root@localhost ~]# curl 127.0.0.1:802
hello mkdirs.com
使用--volumes-from
参数所挂载数据卷的容器自身并不需要保持在运行状态,如果删除了挂载的容器(包括dbdata、db1和db2),数据卷并不会被自动删除.如果要删除一个数据卷,必须在删除最后一个还挂载着它的容器时显式使用docker rm -v
命令来指定同时删除关联的容器.
◆容器备份恢复◆
数据备份: 使用下面的命令来备份dbdata数据卷容器内的数据卷,并把它备份到当前目录下.
代码语言:javascript复制[root@localhost ~]# docker run --volumes-from dbdata -v $(pwd):/backup --name workers centos:latest tar -czvf /backup/backup.tar /usr/local/apache2/htdocs
tar: Removing leading `/' from member names
/usr/local/apache2/htdocs/
/usr/local/apache2/htdocs/index.html
[root@localhost ~]# ls
backup.tar
这个命令稍微有点复杂,具体分析一下,首先利用centos镜像创建了一个容器workers.使用--volumes-from dbdata
参数来让workers容器挂载dbdata容器的数据卷(即dbdata数据卷),使用-v $(pwd):/backup
参数来挂载本地的当前目录到workers容器的/backup目录.workers容器启动后,使用了tar -czvf/backup/backup.tar /usr/local/apache2/htdocs
命令来将/usr/local/apache2/htdocs
下内容备份为容器内的/backup/backup.tar
,即宿主主机当前目录下的backup.tar.
数据恢复: 如果要将数据恢复到一个容器,可以按照下面的步骤操作.
1.首先创建一个带有数据卷的容器dbdata_backup.
代码语言:javascript复制[root@localhost ~]# docker run -itd -v /usr/local/apache2/htdocs --name dbdata_backup centos:latest /bin/bash
a207d887bfa07cc0e1737efb197950cac3b2c5647391348b1b8fa8b873c58667
2.然后创建另一个新的容器,挂载dbdata2的容器,并使用untar解压备份文件到所挂载的容器卷中.
代码语言:javascript复制[root@localhost ~]# docker run --volumes-from dbdata_backup -v $(pwd):/backup busybox tar -xzvf /backup/backup.tar
usr/local/apache2/htdocs/
usr/local/apache2/htdocs/index.html
本小结介绍了通过数据卷和数据卷容器对容器内数据进行共享、备份和恢复等操作,通过这些机制,即使容器在运行中出现故障,用户也不必担心数据发生丢失,只需要快速地重新创建容器即可.
Docker端口映射
在实践中,经常会碰到需要多个服务组件容器共同协作的情况,这往往需要多个容器之间有能够互相访问到对方的服务,Docker提供了两个很方便的功能来满足服务访问的基本需求:一个是允许映射容器内应用的服务端口到本地宿主主机,另一个是互联机制实现多个容器间通过容器名来快速访问,下面我们来分别介绍一下吧.
◆从外部访问容器应用◆
随机分配端口: 当容器中运行一些网络应用,要让外部访问这些应用时,可以通过-P
或-p
参数来指定端口映射.当使用-P(大写的)标记时,Docker会随机映射一个49000~49900
的端口到内部容器开放的网络端口.
[root@localhost ~]# docker run -d -P --name myweb httpd:latest
afb211e832c16c80822632fe0864838781cee2132993f93cde8c915e242f9df5
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
afb211e832c1 httpd:latest "httpd-foreground" 3 seconds ago Up 2 seconds 0.0.0.0:32768->80/tcp myweb
指定分配端口: 当我们使用-p(小写的)
可以指定要映射的端口,并且,在一个指定端口上只可以绑定一个容器.
[root@localhost ~]# docker run -d -p 8080:80 --name myweb1 httpd:latest
b47f6131dea02c8cd22a75049e97c28cc4bb25bc6bf5cd36645c1ccb4210554e
#上面说明,将容器的80端口,映射到本地的8080
[root@localhost ~]# curl 127.0.0.1.8080
<html><body><h1>It works!</h1></body></html>
◆映射所有接口地址◆
映射指定端口: 格式将容器的80端口映射到本机的80端口.
代码语言:javascript复制[root@localhost ~]# docker run -d -p 80:80 --name myweb2 httpd:latest
9c3d0f8ad0bbfa75cc6534f93f959192316125a2776a2c909c71dc9dfb5a8b79
[root@localhost ~]# curl 127.0.0.1
<html><body><h1>It works!</h1></body></html>
映射多个端口: 多次使用-p
标记可以绑定多个端口.
[root@localhost ~]# docker run -d -p 8080:80 -p 1000:21 --name myweb3 httpd:latest
097ceb68128b58195c990dff720e39ca1717809cc2019d3f31466dee6fd32aec
[root@localhost ~]# netstat -antp |grep "8080"
tcp6 0 0 :::8080 :::* LISTEN 2306/docker-proxy
[root@localhost ~]# netstat -antp |grep "1000"
tcp6 0 0 :::1000 :::* LISTEN 2317/docker-proxy
◆映射到指定地址◆
映射到指定地址的指定端口: 将容器中的80端口映射到本地指定IP地址上去.
代码语言:javascript复制[root@localhost ~]# ifconfig ens32:0 192.168.1.10 netmask 255.255.255.0
[root@localhost ~]# ifconfig ens32:0
ens32:0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.1.10 netmask 255.255.255.0 broadcast 192.168.1.255
ether 00:0c:29:1e:14:e2 txqueuelen 1000 (Ethernet)
[root@localhost ~]# docker run -d -p 192.168.1.10:8080:80 --name myweb_port httpd:latest
7385faa5d476cb37dd7d201cd0ec939501c9bdb23ec1c8239245c30d2be9abe7
[root@localhost ~]# netstat -antp |grep "8080"
tcp 0 0 192.168.1.10:8080 0.0.0.0:* LISTEN 2585/docker-proxy
[root@localhost ~]# curl 192.168.1.10:8080
<html><body><h1>It works!</h1></body></html>
映射到指定地址的任意端口: :本地主机会自动分配一个端口,绑定到容器的80口.
代码语言:javascript复制[root@localhost ~]# docker run -d -p 192.168.1.10::80 --name myweb_port1 httpd:latest
7a5a105ae0827aaff68864a28b5f9b8a9592af3551f7deca564ea2d6d5a249b3
[root@localhost ~]# netstat -antp |grep "80"
tcp 0 0 192.168.1.10:8080 0.0.0.0:* LISTEN 2585/docker-proxy
#还可以使用udp标记来指定udp端口
[root@localhost ~]# docker run -d -p 192.168.1.10:5000:5000/udp --name myweb_udp httpd:latest
b9cc6333a63109a70a1d2e645b1ff5046988b472dea3bb4f4d010f1478951adf
[root@localhost ~]# netstat -an |grep "5000"
udp 0 0 192.168.1.10:5000 0.0.0.0:*
## Docker容器互联
容器的互联(linking)是一种让多个容器中应用进行快速交互的方式,它会在源和接收容器之间创建连接关系,接收容器可以通过容器名快速访问到源容器,而不用指定具体的IP地址.
1.使用--link
参数可以让容器之间安全地进行交互,下面先创建一个新的MySQL数据库容器.
[root@localhost ~]# docker run -d --name mysqldb mysql:latest
c1770a69ed29944466ce013c42ac2a0391651c88381e41be05308eab80458390
2.然后创建一个新的web容器,并将它连接到MySQL容器,使之能够通信.
代码语言:javascript复制[root@localhost ~]# docker run -d -P --name web --link mysqldb:mysqldb httpd:latest
8b2bfcbbe00f6966c511fdbbbc16e40736ab8d6aa89d229e224f38d12c4643df
此时,mysqldb容器和web容器建立互联关系,--link
参数的格式为--link name:alias
,其中name是要连接的容器名称,alias是这个连接的别名.
Docker相当于在两个互联的容器之间创建了一个虚机通道,而且不用映射它们的端口到宿主主机上.在启动mysqldb容器的时候并没有使用-p和-P标记,从而避免了暴露数据库服务端口到外部网络上.
拓展与实战例子
◆Apache◆
Apache是世界使用排名第一的Web服务器软件,它可以运行在几乎所有广泛使用的计算机平台上,由于其跨平台和安全性被广泛使用,是最流行的Web服务器端软件之一.它快速、可靠并且可通过简单的API扩充,将Perl/Python等解释器编译到服务器中.
1.拉取镜像,并在本地创建一个测试页.
代码语言:javascript复制[root@localhost ~]# docker pull httpd:latest
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
httpd latest 2a51bb06dc8b 4 weeks ago 132MB
[root@localhost ~]# mkdir /web
[root@localhost ~]# echo "hello world" > /web/index.html
2.运行http容器,并访问测试.
代码语言:javascript复制[root@localhost ~]# docker run -d -p 8080:80 --name MyWeb -v /web:/usr/local/apache2/htdocs httpd:latest
[root@localhost ~]# curl 127.0.0.1:8080
hello world
◆GitLab◆
Gitlab是一款非常强大的开源源码管理系统.它支持基于Git的源码管理、代码评审、issue跟踪、活动管理、wiki页面,持续集成和测试等功能.基于Gitlab,用户可以自己搭建一套类似Github的开发协同平台.
1.安装并启动postgresql.
代码语言:javascript复制[root@localhost ~]# docker pull sameersbn/postgresql:latest
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
sameersbn/postgresql latest 3c0142eb3992 5 months ago 204MB
[root@localhost ~]# docker run --name gitlab_postgresql -d
--env 'DB_NAME=gitlab'
--env 'DB_USER=gitlab' --env 'DB_PASS=gitlab'
sameersbn/postgresql:latest
2.安装redis.
代码语言:javascript复制[root@localhost ~]# docker pull sameersbn/redis:latest
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
sameersbn/redis latest ad607f019b8c 4 months ago 84.8MB
sameersbn/postgresql latest 3c0142eb3992 5 months ago 204MB
[root@localhost ~]# docker run --name gitlab_redis -itd sameersbn/redis:latest
3.安装GitLab.
代码语言:javascript复制[root@localhost ~]# docker pull sameersbn/gitlab:latest
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
sameersbn/gitlab latest 336fe9c19d92 6 days ago 1.96GB
sameersbn/redis latest ad607f019b8c 4 months ago 84.8MB
sameersbn/postgresql latest 3c0142eb3992 5 months ago 204MB
[root@localhost ~]# docker run --name gitlab -d sameersbn/gitlab
--link gitlab_postgresql:postgresql --link gitlab_redis:redis
--publish 10022:22 --publish 10080:80
--env 'GITLAB_PORT=10080' --env 'GITLAB_SSH_PORT=10022'
--env 'GITLAB_SECRETS_DB_KEY_BASE=long-and-random-alpha-numeric-string'
sameersbn/gitlab:latest
◆WordPress◆
WordPress是使用PHP语言开发的博客平台,用户可以在支持PHP和MySQL数据库的服务器上架设属于自己的网站.也可以把WordPress当作一个内容管理系统(CMS)来使用,WordPress逐步演化成一款内容管理系统软件,它是使用PHP语言和MySQL数据库开发的.用户可以在支持PHP和MySQL数据库的服务器上使用自己的博客.
1.首先安装一个MariaDB数据库,并配置好初始密码.
代码语言:javascript复制[root@localhost ~]# docker pull mariadb:latest
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mariadb latest b468922dbbd7 3 weeks ago 366MB
[root@localhost ~]# docker run --name MyDataBase --env MYSQL_ROOT_PASSWORD=example -d mariadb:latest
2.拉取WordPress镜像,并运行,将容器内的80口映射到宿主机的8080口上.
代码语言:javascript复制[root@localhost ~]# docker pull wordpress:latest
[root@localhost ~]# docker run --name MyWordPress --link MyDataBase:MariaDB -p 8080:80 -d wordpress:latest