六、数据管理
用户在使用docker的过程中,往往需要查看容器内应用产生的数据,或者需要把容器内的数据进行备份,甚至多个容器之间进行数据的共享,这必然涉及容器的数据管理操作。
容器中管理数据主要有两种方式:
1)数据卷(Data Volumes)
2)数据卷容器(Data Volume Dontainers)
本章介绍在容器内创建数据卷,并且把本地的目录或文件挂载到容器内的数据卷中,使用数据卷容器在容器和主机、容器和容器之间共享数据,并实现数据的备份和恢复。
6.1 数据卷
数据卷是一个可供容器使用的特殊目录,它绕过文件系统,可以提供很多有用的特性:
1)数据卷可以在容器之间共享和重用。
2)对数据卷的修改会立马生效。
3)对数据卷的更新,不会影响镜像。
4)卷会一直存在,直到没有容器使用。
数据卷的使用,类似于Linux下对目录或文件进行mount操作。
在容器内创建一个数据卷:
在用docker run命令的时候,使用-v标记可以在容器内创建一个数据卷。多次使用-v标记可以创建多个数据卷。
下面使用training/webapp镜像创建一个Web容器,并创建一个数据卷挂载到容器的/webapp目录下:
sudo docker run -d -P --name web -v /webapp training/webapp python app.py
-P是允许外部访问容器需要暴露的端口。
挂载一个主机目录作为数据卷:
使用-v标记也可以指定挂载一个本地的已有目录到容器中去作为数据卷:
sudo docker run -d -P --name web -v /src/webapp:/opt/webapp training/webapp python app.py
上面的命令加载主机的/src/webapp目录到容器的/opt/webapp目录。
用户可以放置一些程序或数据到本地目录中,然后在容器内运行和使用。另外,本地目录必须是绝对路径,如果目录不存在,docker会自动创建。
docker挂在数据卷的默认权限是读写(rw),用户也可以通过 :ro 指定为只读:
sudo docker run -d -P --name web -v /src/webapp:/opt/webapp:ro training/webapp python app.py
加了 :ro 后,容器内挂载的数据卷的数据就无法修改了。
挂载一个本地主机文件作为数据卷:
-v标记也可以从主机挂载单个文件到容器中作为数据卷:
sudo docker run --rm -it -v ~/.bash_history:/bash_history ubuntu /bin/bash
这样就可以记录在容器输入过的命令历史了。
一般不推荐这种直接挂载本地主机文件的方式,它可能导致在修改文件时变更其inode节点。
6.2 数据卷容器
如果用户需要在容器之间共享一些持续更新的数据,最简单的方式是使用数据卷容器。数据卷容器其实就是一个普通的容器,专门用它提供数据卷供其他容器挂载。
首先,创建一个数据卷容器dbdata,并在其中创建一个数据卷挂载到/dbdata:
sudo docker run -it -v /dbdata --name dbdata ubuntu
可以查看到/dbdata目录。
然后可以在其他容器中使用--volumes-from来挂载dbdata容器中的数据卷,例如创建db1和db2两个容器,并从dbdata容器挂载数据卷:
sudo docker run -it --volumes-from dbdata --name db1 ubuntu
sudo docker run -it --volumes-from dbdata --name db2 ubuntu
此时三个容器都挂载同一个数据卷到相同的/dbdata目录。三个容器任何一方在该目录下的写入,其它容器都可以看到。
数据卷即先创建一个挂载数据卷的容器,然后在其它容器中使用--volumes-from来挂载那个容器中的数据卷。这样使得多个容器共享数据卷。
可以多次使用--volumes-from参数来从多个容器挂载多个数据卷。还可以从其它已经挂载了容器卷的容器来挂载数据卷:
sudo docker run -it --name db3 --volumes-from db1 training/postgres
使用--volumes-from挂载的数据卷的挂载位置是相同的。
6.3 利用数据卷容器迁移数据
可以利用数据卷容器对其中的数据卷进行备份、恢复,以实现数据的迁移。
备份:
备份dbdata数据卷容器内的数据卷:
sudo docker run --volumes-from dbdata -v $(pwd):/backup --name work ubuntu
tar cvf /backup/backup.tar /dbdata
首先利用ubuntu镜像创建了一个容器worker。使用--volumes-from dbdata参数来让worker容器挂载dbdata容器的数据卷(即dbdata数据卷);使用-v $(pwd):/backup参数来挂载本地的当前目录到worker容器的/backup目录。
worker容器启动后,使用tar cvf /backup/backup.tar /dbdata命令来将 /dbdata下内容备份为容器内的 /backup/backup.tar,即宿主主机当前目录下的backup.tar。
即对于数据卷容器的数据备份:新建一个容器,--volumes-from挂载数据卷容器的数据卷,载用-v xxx:yyy挂载本地主机的某个目录为数据卷,再进入新建容器中将数据卷容器的数据卷tar打包放到本地目录挂载点。退出之后可在本地看到打包后的数据卷数据。
恢复:
恢复数据到一个容器。首先创建一个带有数据卷的容器dbdata2:
sudo docker run -v /dbdata --name dbdata2 ubuntu /bin/bash
然后创建另一个新的容器,挂载dbdata2的容器,并使用tar解压备份文件到所挂载的容器卷中即可:
sudo docker run --volumes-from dbdata2 -v $(pwd):/backup busybox tar xvf /backup/backup.tar
七、网络基础配置
大量的互联网应用服务包括多个服务组件,这往往需要多个容器之间通过网络通信进行相互配合。
docker目前提供了映射容器端口到宿主主机和容器互联机制来为容器提供网络服务。
本章介绍:如何使用docker的网络功能,使用端口映射机制来将容器内应用服务提供给外部服务,以及通过容器互联系统让多个容器之间进行快捷的网络通信。
7.1 端口映射实现访问容器
从外部访问容器应用:
在启动容器时,如果不指定对应参数,在容器外部是无法通过网络来访问容器内的网络应用和服务的。
当容器中运行一些网络应用,要让外部访问这些应用时,可以通过-P或-p参数来指定端口映射。当使用-P标记时,docker会随机映射一个49000~49900的端口至容器内部开放的网络端口:
sudo docker run -d -P training/webapp python app.py
sudo docker ps -l
-p(小写的)则可以指定要映射的端口,并且,在一个指定端口上只可以绑定一个容器。支持的格式有 ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort
映射所有接口地址:
使用hostPort:containerPort格式将本地的5000端口映射到容器的5000端口,可以执行如下命令:
sudo docker run -d -p 5000:500 training/webapp python app.py
此时默认会绑定本地所有接口上的所有地址。多次使用-p标记可以绑定多个端口。例如:
sudo docker run -d -p 5000:5000 -p 3000:80 training/webapp python app.py
映射到指定地址的指定端口:
可以使用ip:hostPort:containerPort格式指定映射使用一个特定地址,比如localhost地址127.0.0.1:
sudo docker run -d -p 127.0.0.1:5000:5000 training/webapp python app.py
映射到指定地址的任意端口:
使用ip::containerPort绑定localhost的任意端口到容器的5000端口,本地主机会自动分配一个端口:
sudo docker run -d -p 127.0.0.1::5000 training/webapp python app.py
还可以使用udp标记来指定udp端口:
sudo docker run -d -p 127.0.0.1:5000:5000/udp training/wenapp python app.py
查看映射端口配置:
使用docker port来查看当前映射的端口配置,也可以查看到绑定的地址:
sudo docker port nostalgic_morse 5000
7.2 容器互联实现容器间通信
容器的连接(linking)系统是除了端口映射外另一种可以与容器中应用进行交互的方式。它会在源和接受容器之间创建一个隧道,接受容器可以看到源容器指定的信息。
自定义容器命名:
连接系统依据容器的名称来执行。因此,首先需要自定义一个好记的容器命名。
自定义的命名,比较好记;当要连接其它容器时,可以作为一个有用的参考点,比如连接web容器到db容器。
--name标记。
在执行docker run的时候如果添加了--rm标记,则容器在终止后会立刻删除。注意--rm和-d不能同时使用。
容器互联:
使用--link参数可以让容器之间安全地进行交互。
先创建一个数据库容器:
sudo docker run -d --name db training/postgres
然后创建一个新的web容器,并将它连接到db容器:
sudo docker run -d -P --name web --link db:db training/webapp python app.py
此时,db容器和web容器建立互联关系。
--link参数的格式为--link name:alias,其中name是要链接的容器的名称,alias是这个连接的别名。
web容器链接了db,web容器可以访问db容器的信息。
docker在两个互联的容器之间创建了一个安全隧道,而且不用映射它们的端口到宿主主机上。在启动db容器的时候并没有使用-p和-P标记,从而避免了暴露数据库端口到外部网络上。
docker通过两种方式为容器公开连接信息:
1)环境变量;
2)更新/etc/hosts文件。
使用env命令查看web容器的环境变量:
sudo docker run --rm --name web2 --link db:db training/webapp env
八、使用dockfile创建镜像
dockfile是一个文本格式的配置文件,用户可以使用dockfile快速创建自定义的镜像。
本章介绍dockfile典型的基本结构及其支持的众多指令,如何编写dockfile,并介绍使用dockfile创建镜像的过程。
8.1 基本结构
dockfile由一行行命令语句组成,并且支持以#开头的注释行。
一般而言,dockfile分为四部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令。
一开始必须指明所基于的镜像名称。如:
FROM ubuntu
然后是维护者信息,如:
MAINTAINER docker_user dock_user@eamil.com
然后是镜像操作指令,如:
RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe" >> /etc/
apt/sources.list
RUN apt-get update && apt-get install -y nginx
RUN echo " daemon off;">> /etc/nginx/nginx.conf
然后是容器启动时执行指令,如:
CMD /usr/sbin/nginx
8.2 指令
指令的一般格式为INSTRUCTION arguments,指令包括FROM,MAINTAINER,RUN等。
1)FROM
FORM <image>或FROM <image>:<tag>
如果在同一个dockerfile中创建多个镜像时,可以使用多个FROM指令,每个镜像一次。
2)MAINTAINER
MAINTAINER <name>指定维护者信息。
3)RUN
RUN <command>或RUN ["executable","param1","param2"]。
前者将在shell终端中运行命令,即/bin/sh -c;后者则使用exec执行。指定使用其它终端可以通过第二种方式实现,例如:RUN ["/bin/bash","-c","echo hello"]。
每条RUN指令将在当前镜像基础上执行指定命令,并提交为新的镜像。当命令较长时可以使用来换行。
4)CMD
支持三种格式:
CMD [“executable","param1,"param2"]使用exec执行,推荐方式。
CMD command param1 param2在/bin/sh中执行,提供给需要交互的应用。
CMD [”param1","param2"]提供给ENTRYPOINT的默认参数。
指定启动容器时执行的命令,每个dockerfile只能有一条CMD命令,如果指定了多条命令,只有最后一条会被执行。
如果用户启动容器时候指定了运行的命令,则会覆盖掉CMD指定的命令。
5)EXPOSE
格式为:EXPOSE <port> [<port>...]。
例如:EXPOSE 22 80 8443
告诉docker服务端容器暴露的端口号,供互联系统使用。在启动容器时需要通过-P,docker主机会自动分配一个端口转发到指定的端口;使用-p,则可以具体指定哪个本地端口映射过来。
6)ENV
格式为:ENV <key> <value>。指定一个环境变量,会被后续RUN指令使用,并在容器运行时保持。例如:
ENV PG_MAJOR 9.3
ENV PG_VERSION 9.3.4
RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgres && ...
ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH
7)ADD
ADD <src> <dest>
该命令将复制指定的<src>到容器中的<dest>。其中<src>可以是dockerfile所在目录的一个相对路径(文件或目录);也可以是一个URL;还可以是一个tar文件(自动解压为目录)。
8)COPY
COPY <src> <dest>
复制本地主机的<src>(为dockerfile所在目录的相对路径,文件或目录)为容器中的<dest>。目录路径不存在时,会自动创建。
当使用本地目录为源目录时,推荐使用COPY。
9)ENTRYPOINT
有两种格式:
ENTRYPOINT ["executable","param1","param2"]
ENTRYPOINT command param1 param2(shell中执行)。
配置容器启动后执行的命令,并且不可被docker run提供的参数覆盖。
每个dockerfile中只能有一个ENTRYPOINT,当指定多个ENTRYPOINT时,只有最后一个生效。
10)VOLUME
格式为VOLUME ["/data"]
创建一个可以从本地主机或其它容器挂载的挂载点,一般用来存放数据库和需要保持的数据等。
11)USER
USER daemon
指定运行容器时的用户名或UID,后续的RUN也会使用指定用户。
当容器不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户。
12)WORKDIR
格式为:WORKDIR /path/to/workdir
为后续的RUN、CMD、ENTRYPOINT指令配置工作目录。
可以使用多个WORKDIR指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径
13)ONBUILD
ONBUILD [INSTRUCTION]
配置当所创建的镜像作为其它新创建镜像的基础镜像时,所执行的操作指令。
8.3 创建镜像
编写完dockerfile之后,可以通过docker build命令来创建镜像。
docker build [选项] 路径,该命令将读取指定路径下(包括子目录)的dockerfile,并将该路径下所有内容发送给docker服务端,由服务端来创建镜像。因此一般建议放置dockerfile的目录为空目录。
另外可以通过.dockerignore文件(每一行添加一条匹配模式)来让docker忽略路径下的目录和文件。
要指定镜像的标签信息,可以通过-t选项。
sudo docker build -t buidl_repo/first_image /tmp/docker_builder/
从/tmp/docker_builder路径生成镜像标签build_repo/first_image