Docker Data Volume (存储卷)
Docker镜像由多个只读层叠加而成,启动容器时,Docker会加 载只读镜像层并在镜像栈顶部添加一个读写层
如果运行中的容器修改了现有的一个已经存在的文件,那该文 件将会从读写层下面的只读层复制到读写层,该文件的只读版 本仍然存在,只是已经被读写层中该文件的副本所隐藏,此即 “写时复制(COW)”机制
“卷”是容器上的一个或多个“目录”,此类目录可绕过联合文件 系统,与宿主机上的某目录“绑定(关联)”
即使将容器删除,同步到宿主机上的数据也不会消失,保证数据的持久化。
Docker管理卷:
Docker有两种类型的卷,每种类型都在容器中存在一个挂载点 ,但其在宿主机上的位置有所不同;
1 . Bind mount volume (将卷绑定到宿主机)
指定容器 上的路径目录和宿主机上的目录:
docker run –name dd1 -it –rm -v /data/b2:/data busybox (创建一个容器,前面的路径为宿主机的路径,后面为容器的路径;两个位置的路径都不需要创建会自动生成的)
docker inspect dd1 :用此命令可以查看容器的详细信息:(关连路径的详细信息)
此时在容器路径下/data/创建数据,会自动同步到指定的宿主机/data/b2/路径下的。
如果将原来的容器删除,再下次创建容器时指定上一次宿主机的路径,就可以将原来的数据同步到新建的容器上了。容器的路径可以和原来不同,但宿主机的路径必须要和你要同步的数据路径相同
docker run –name dd1 -it –rm -v /data/b2:/app busybox
2 . Docker-managed volume (docker管理卷)
只需要指定容器里的目录,docker引擎会自动关连到宿主机上对应的路径位置,可以通过探测容器的详细信息来查询。
docker run –name dd1 -it -v /data busybox (只指定容器的路径)
docker inspect dd1 (查看具体关连到本地的路径的信息)
此时在容器里/data/下创建数据,会自动同步到宿主机上的路径下的。
有了脱离容器的持久状态。
两个docker容器共享一个卷:也可以多个容器共享。
在同一个宿主机上:
docker run –name dd1 -it –rm -v /data/b2:/data busybox
docker run –name dd2 -it –rm -v /data/b2:/app busybox
创建两个容器,指定相同的宿主机目录.本容器的目录可以各不相同。此时如果在一个容器的/data目录下创建一个文件,会将数据同步到本地的/data/b2目录下,也会同步到另一个容器的/app/目录下。
也可以有另一种思路:
新建一个容器,设置卷关连到宿主机。然后再设定网络环境。这样其他容器再启动时可以使用此容器的卷设置和网络设置。
做一个基础的容器,再创建其他容器时,复制此容器的配置。
docker run –name base -it –rm -v /data/b2:/data busybox (创建基础容器)
docker run –name nginx –network container:base -it –rm –volumes-from base busybox (创建一个新的容器,网路是基于base容器的;卷的关连设置也是基于base容器的)
此时查看新创建的nginx容器的网络设置和卷的设置都是和此前基础容器base的设置是相同的。
删除容器之时删除相关的卷
为docker rm命令使用-v选项 v
删除指定的卷 docker volume rm
Dockerfile (制作容器镜像)
大多数从dockerhub上下载下来的容器镜像大多都不符合实际需求,许多配置参数都需要修改,比较麻烦,所以需要我们自己来制作符合自己需求的容器镜像。
上文介绍了以原有容器镜像为基础,来修改之后再制作成镜像的方式,此处采用另一种的制作容器镜像的方式。
dockerfile的方式是将应用的配置文件做成模板,每次运行一个镜像容器是,加载设定好的模板配置文件,就可以实现对不同镜像容器的不同需求了。
工作原理:在开启一个容器镜像时,不启动容器的主进程而是先开启另一个进程,读取模板配置文件里的参数,设定好容器主进程的各项环境变量的参数,然后再开启容器的主进程。不在通过去修改应用程序的配置文件,而是在启动程序时,给容器的应用传递环境变量。(环境变量就存放在dockerfile文件里)
FROM 指令:(指定制作镜像的基础镜像)
FROM指令是最重的一个且必须为Dockerfile文件开篇的第一个非 注释行,用于为映像文件构建过程指定基准镜像,后续的指令运 行于此基准镜像所提供的运行环境。
实践中,基准镜像可以是任何可用镜像文件,默认情况下, docker build会在docker主机上查找指定的镜像文件,在其不存在 时,则会从Docker Hub Registry上拉取所需的镜像文件
如果找不到指定的镜像文件,docker build会返回一个错误信息
form 指定镜像的格式:
FROM <image>[:<tag>] :直接指定镜像名称
FROM <image>@<digest> :指定镜像的哈希值;(防止在使用镜像时, 被人在镜像里添加危害系统的代码)
MAINTANIER 指令:(已被废弃了)新版已经换成了LABEL
用于让镜像制作者提供本人的详细信息
Dockerfile并不限制MAINTAINER指令可在出现的位置,但推荐将 其放置于FROM指令之后
MAINTAINER <authtor’s detail> l <author’s detail>可是任何文本信息,但约定俗成地使用作者名称及邮件地址 :例如:MAINTAINER “tom <lv@qq.com>” (作者名和邮箱地址)
LABEL:格式是键值数据对: LABEL maintainer= “magedu <mage@magedu.com>”
COPY 指令
用于从Docker宿主机复制文件至创建的新映像文件
Syntax 格式
COPY <src> … <dest>
COPY [“<src>”,… “<dest>”] 列表格式:前面多个源文件,后面一个目标文件夹
<src>:要复制的源文件或目录,支持使用通配符
<dest>:目标路径,即正在创建的image的文件系统路径;建议为<dest>使用绝对路 径,否则,COPY指定则以WORKDIR为其起始路径;
注意:在路径中有空白字符时,通常使用第二种格式用引号。
文件复制的规则:
<src>必须是build上下文中的路径,不能是其父目录中的文件
如果<src>是目录,则其内部文件或子目录会被递归复制,但<src>目录自身 不会被复制。不复制目录,只是将目录下的文件复制过去。
如果指定了多个<src>,或在<src>中使用了通配符,则<dest>必须是一个目录 ,且必须以/结尾
如果<dest>事先不存在,它将会被自动创建,这包括其父目录路径
例如:copy index.html /data/web/html/ (仅复制一个文件到要启动容器的目录下,容器的目录如果不存在,系统会默认创建的,index.html文件的路径在当前目录下及和dockerfile文件在同一目录下)
ADD 指令
ADD指令类似于COPY指令,ADD支持使用TAR文件和URL路径
Syntax 格式
ADD <src> … <dest>
ADD [“<src>”,… “<dest>”]
操作规则:
同COPY指令
如果<src>为URL且<dest>不以/结尾,则<src>指定的文件将被下载并直接被 创建为<dest>;如果<dest>以/结尾,则文件名URL指定的文件将被直接下载 并保存为<dest>/<filename>
如果<src>是一个本地系统上的压缩格式的tar文件,它将被自动展开为一个目录 ,其行为类似于“tar -x”命令;然而通过URL网络上获取到的tar文件将不会自动 展开;
如果<src>有多个,或其间接或直接使用了通配符,则<dest>必须是一个以/结 尾的目录路径;如果<dest>不以/结尾,则其被视作一个普通文件,<src>的内 容将被直接写入到<dest>;
WORKDIR 指令 (指定容器的路径)
在使用copy和add命令时,用于指定容器的路径。
用于为Dockerfile中所有的RUN、CMD、ENTRYPOINT、COPY和 ADD指定设定工作目录
Syntax ɰ WORKDIR <dirpath> l 在Dockerfile文件中,WORKDIR指令可出现多次,其路径也可以为相对路径,不过 ,其是相对此前一个WORKDIR指令指定的路径 l 另外,WORKDIR也可调用由ENV指定定义的变量 ɰ 例如 l WORKDIR /var/log l WORKDIR $STATEPATH
例如:
WORKDIR /usr/local/src (先指定好容器的路径)
ADD nginx-1.15.2.tar.gz ./ (引用时只写当前路径就可以了)
VOLUME指令 (卷的挂载)
用于在image中创建一个挂载点目录,以挂载Docker host上的卷或 其它容器上的卷
Syntax 格式
VOLUME <mountpoint>
VOLUME [“<mountpoint>”]
如果挂载点目录路径下此前在文件存在,docker run命令会在卷挂 载完成后将此前的所有文件复制到新挂载的卷中
例如:VOLUME /data/mysql (前面路径为容器里的路径,后面宿主机的目录路径不指定会自动创建的,也可以自定义的指定)
这样就实现了将容器里的/data/mysql/ 目录直接就挂载到了宿主机上了。
EXPOSE 指令 (暴露端口)
用于为容器打开指定要监听的端口以实现与外部通信;只能指定自己暴露的端口,不能指定自己的IP地址。需要动态绑定到宿主机上的所有地址和随机端口,因为本机到底是运行在哪个主机上不确定,且宿主机的哪个端口空闲也是不确定的,所以是随机指定的。
Syntax
EXPOSE <port>[/<protocol>] [<port>[/<protocol>] …]
<protocol>用于指定传输层协议,可为tcp或udp二者之一,默认为TCP协议
EXPOSE指令可一次指定多个端口,例如
EXPOSE 11211/udp 11211/tcp
只写在此文件里,是不会暴露的,只有在docker run 运行时添加-P选项就会读取此文件里的暴露的配置内容,为了防止安全才这样做。
ENV指令(定义容器的环境变量)
用于为镜像定义所需的环境变量,并可被Dockerfile文件中位于其 后的其它指令(如ENV、ADD、COPY等)所调用
调用格式为$variable_name或${variable_name}
dockerfile里的变量:
${variable:-word} 当变量有值时,使用原变量的值,如果没有给与变量赋值,则使用-号后面的值。
${variable:+word} 和上述变量相反,当变量有值时,使用+后面的值,变量没有值时,就没有值了
Syntax 格式
1 . ENV <key> <value>
2 . ENV <key>=<value> …
第一种格式中,<key>之后的所有内容均会被视作其<value>的组成部分 ,因此,一次只能设置一个变量;
第二种格式可用一次设置多个变量,每个变量为一个”<key>=<value>”的 键值对,如果<value>中包含空格,可以以反斜线(\)进行转义,也可通过 对<value>加引号进行标识;另外,反斜线也可用于续行
定义多个变量时,建议使用第二种方式,以便在同一层中完成所有功能
例如:
第一种格式的写法,一次定义单个变量值
ENV dock_root /data/web/html/
copy index.html $dock-root
copy index.html ${dock-root :-/data/web/html/} 这种写法就是当变量值没有设定的时候,使用后面的字符串作为变量的值。
第二种格式的写法,一次定义多个变量值。
ENV dock_root=/data/web/html/ \ (反斜线用于换行再写,如果变量值中间有空白字符需要添加“”)
web=/data/http/dd
RUN指令
用于指定docker build过程中运行的程序,其可以是任何命令,但在基础镜像里需要有相对应的命令,否则也无法运行。
Syntax 格式
1 . RUN <command>
2 . RUN [“<executable>”, “<param1>”, “<param2>”]
第一种格式中,<command>通常是一个shell命令,且以“/bin/sh -c”来运行它, 这意味着此进程在容器中的PID不为1,不能接收Unix信号,因此,当使用 docker stop <container>命令停止容器时,此进程接收不到SIGTERM信号;
第二种语法格式中的参数是一个JSON格式的数组,其中<executable>为要运行的 命令,后面的<paramN>为传递给命令的选项或参数;然而,此种格式指定的命 令不会以“/bin/sh -c”来发起,因此常见的shell操作如变量替换以及通配符(?,* 等)替换将不会进行;不过,如果要运行的命令依赖于此shell特性的话,可以将 其替换为类似下面的格式。
RUN [“/bin/bash”, “-c”, “<executable>”, “<param1>”]
例如:
RUN :mkdir /data/hhhhhh (就会在容器的/data目录下新建一个hhhhhh的目录)
也可以写多个命令&&+另一条命令&&+另一条命令,尽量写在一行,因为写了多行会造成容器封层数的增加。
格式:
RUN :command1&&\
command 2 && \ (反斜线为续行在写)
command 3
CMD指令(定义镜像文件启动为容器时, 将定义的程序运行为容器的主程序;如果此程序结束容器也会跟随者结束)
类似于RUN指令,CMD指令也可用于运行任何命令或应用程序, 不过,二者的运行时间点不同
RUN指令运行于映像文件构建过程中,而CMD指令运行于基于Dockerfile 构建出的新映像文件启动一个容器时
CMD指令的首要目的在于为启动的容器指定默认要运行的程序,且其运 行结束后,容器也将终止;不过,CMD指定的命令其可以被docker run创建容器时后面添加的命令所覆盖掉,而不去运行dockerfile文件里定义的命令,至运行docker run 后面的命令+/bin/sh/ls /etc/ 等命令。
在Dockerfile中可以存在多个CMD指令,但仅最后一个会生效
Syntax
CMD <command>
CMD [“<executable>”, “<param1>”, “<param2>”]
CMD [“<param1>”,”<param2>”]
前两种语法格式的意义同RUN
第三种则用于为ENTRYPOINT指令提供默认参数
CMD httpd -h /data/web/html (在dockerfile文件里添加的)如果将此命令添加到以busybox的镜像里,运行时,原来默认是运行的主程序/bin/sh的,添加CMD后主程序变为httpd程序了。
第三种格式的写法:将自己定义的内容当参数传递给ENTRYPOINT的:例如:
CMD [“/bin/httpd”,”-f”,”-h /data/web/html”]
ENTROPIONT /bin/sh -c (添加-c则指定从字符串获取参数,及允许获得CMD传送过来的参数)
ENTRYPOINT指令:
类似CMD指令的功能,用于为容器指定默认运行程序,从而使得 容器像是一个单独的可执行程序
与CMD不同的是,由ENTRYPOINT启动的程序不会被docker run命 令行指定的参数所覆盖,而且,这些命令行参数会被当作参数传 递给ENTRYPOINT指定指定的程序
不过,docker run命令的–entrypoint选项的参数可覆盖ENTRYPOINT指令 指定的程序
Syntax 格式
ENTRYPOINT <command>
ENTRYPOINT [“<executable>”, “<param1>”, “<param2>”]
docker run命令传入的命令参数会覆盖CMD指令的内容并且附加到 ENTRYPOINT命令最后做为其参数使用
Dockerfile文件中也可以存在多个ENTRYPOINT指令,但仅有最后 一个会生效
例如:
ENTRYPOINT /bin/httpd -f -h /data/web/html/ 在dockerfile文件里指定要运行的命令,且默认为主进程,在运行dockerfile容器时,docker run –name kkk -it –rm httpd:2.1 ls /data/web/html/ 其他的功能和CMD指令相同,会把其指令后面的程序运行为主程序,但和CMD不同的时在命令行运行容器时添加的命令不会运行的。而CMD会运行并将其自己指定的命令覆盖掉。
USER 指令:
用于指定运行image时的或运行Dockerfile中任何RUN、CMD或 ENTRYPOINT指令指定的程序时的用户名或UID
默认情况下,container的运行身份为root用户
Syntax 格式
USER <UID>|<UserName>
需要注意的是,<UID>可以为任意数字,但实践中其必须为/etc/passwd中 某用户的有效UID,否则,docker run命令将运行失败
ONBUILD 指令:
用于在Dockerfile中定义一个触发器
Dockerfile用于build映像文件,此映像文件亦可作为base image被 另一个Dockerfile用作FROM指令的参数,并以之构建新的映像文 件
在后面的这个Dockerfile中的FROM指令在build过程中被执行时, 将会“触发”创建其base image的Dockerfile文件中的ONBUILD指令 定义的触发器
Syntax 格式:
ONBUILD <INSTRUCTION>
尽管任何指令都可注册成为触发器指令,但ONBUILD不能自我嵌套,且不会触 发FROM和MAINTAINER指令
使用包含ONBUILD指令的Dockerfile构建的镜像应该使用特殊的标签,例如 ruby:2.0-onbuild
在ONBUILD指令中使用ADD或COPY指令应该格外小心,因为新构建过程的上 下文在缺少指定的源文件时会失败
创建镜像的示例1:(copy命令复制单个文件到容器目录下)
mkdir imge1 (创建一个文件夹)
cd imge1/ (进入到此文件夹下)
vim Dockerfile (创建一个dockerfie文件,注意创建的文件开头字母要大写)
#Description test image (描述信息)
FROM busybox:latest (基于什么镜像来制作)
MAINTAINER “magedu <mage@magedu.com>” (指定镜像制作的人的信息)
#LABEL maintainer= “magedu <mage@magedu.com>” (新的指令用法)
copy index.html /data/web/html/ (需要在imge1目录下创建一个index.html文件)
vim index.html
hello
保存退出。
docker build -t httpd:1.1 imge1/ (制作镜像)
(httpd为自定义的仓库名;1.1为标签版本号;imge1/:为dockerfile文件的父目录。)
docker image ls (查看本地镜像已经生成新的镜像文件了)
基于上面制作的镜像文件来开启一个容器:
docker run –name hhh -it –rm httpd:1.1 (交互式的方式登陆进去查看dockerfile里复制到容器里的文件是否复制过去了)。
创建镜像示例2:(copy命令复制目录下的多个文件到容器目录里)
首先复制一个目录到img1下:
cp -r /etc/yum.repos.d /img1/
修改dockerfile文件:
其中yum.repos.d为目录。复制过去不复制目录,只复制目录下的文件,另外dockerfile文件里命令如果能写一行不要分两行来写,因为每一行都在运行容器时都是一层封装。
docker build -t httpd:1.2 /root/imge1/ (再次制作镜像)
docker run –name hhh -it –rm httpd:1.2 (以第二版本的镜像开启一个容器,查看是否将目录下的文件复制过去)
创建镜像示例3:(add命令下载网络上tar格式的文件。和下载本地的tar格式的文件)
首先找一个网络上的tar格式的包,复制其url的路径。
http://nginx.org/download/nginx-1.12.2.tar.gz
编辑dockerfile文件:/roo/imge1/
docker build -t httpd:1.3 /root/imge1/ (再次制作镜像文件)
docker run –name kkk -it –rm httpd:1.3 (以此次的镜像文件运行一个docker容器,来验证是否将文件下载下来)
网络上的url路径下载的tar格式的包不会自动将其解压所。
但如果将tar格式的包下载到宿主机上的目录下,使用add命令,会将其自动的解压缩。
wget http://nginx.org/download/nginx-1.15.2.tar.gz 先将文件下载到本地/root/imge1/下
编辑dockerfile文件:
docker build -t httpd:1.4 /root/imge1/ (创建一个新的镜像文件)
docker run –name kkk -it –rm httpd:1.4 (以此镜像运行一个容器)
进入到容器后发现,此包已经下载下来并解压缩了。
创建镜像示例4:(workdir指令的用法)
dockerfile文件的内容:
创建镜像和运行此镜象的容器来验证参考上面的操作就可以了。
当有多个workdir路径时,从下向上找,离自己最近的workdir为自己引用的路径。
创建镜像示例5:(volume的挂载)
不指定宿主机的路径只指定容器的路径的挂载
编辑/root/imge1/下的dockerfile文件:
docker build -t httpd:1.5 /root/imge1/(制作镜像)
docker run –name kkk -it –rm httpd:1.5 (启动容器)
docker inspect kkk (查看容器的详细信息,容器里的目录是否挂载到宿主机上了)
创建镜像示例6:(expose暴露端口号)
编辑/root/imge1/下的dockerfile文件:
docker build -t httpd:1.6 /root/imge1/ (再次制作镜像)
docker run –name kkk -it -P –rm httpd:1.6 (以此镜像运行一个容器)
在容器里操作
httpd -h /data/web/html (启动http程序并指定主页面的路径)
netstat -nlt (查看端口号是否打开)
ifconfig (查看容器的IP地址)
最后在宿主机上curl 容器的IP地址应该可以访问容器提供的http的web服务。
docker port kkk (查看端口号是否暴露了,和查看关连到宿主机的哪个端口)
在浏览器上打开L: 宿主机IP:端口号
创建镜像示例7:(ENV环境变量)
编辑/root/imge1/下的dockerfile文件:
docker build -t httpd:1.7 /root/imge1/ (再次制作镜像)
docker run –name kkk -it -P –rm httpd:1.7 (以此镜像运行一个容器)
进入容器后查看是否完成。
docker run –name kkk -it -P –rm httpd:1.7 printenv (查看环境变量信息)
docker run –name kkk -it -P -e web=”nginx-1.15.1.tar.gz” –rm httpd:1.7 (也可以在build时重新来定义其变量的值)
创建镜像示例8: (run指令;前提是基础容器里有此命令)
编辑/root/imge1/下的dockerfile文件:
docker build -t httpd:1.8 /root/imge1/ (再次制作镜像)
docker run –name kkk -it -P –rm httpd:1.8 (基于此镜像开启容器)
查看容器验证run命令是否执行成功。
创建镜像示例8:( ENTRYPOINT指令)
编辑/root/imge1/下的dockerfile文件:
docker build -t httpd:2.1 /root/imge1/ (再次制作新的镜像)
docker run –name kkk -it –rm httpd:2.1 (以此镜像为基础开启一个新的容器;默认就会运行httpd的程序,而不是原本busybox的/bin/sh的程序了)
docker run –name kkk -it –rm httpd:2.1 ls /data/web/html/ (但是和CMD不同的是 ,命令行后面的 命令与不会运行,而CMD定义的主程序,如果命令行也有命令,则运行命令行上的命令)
如果一定要想运行自己的命令:需要指定专门的选项:
docker run –name kkk -it –rm –entrypoint “ls /data/web/html” httpd:2.1 (这样写就能将定义的entrypoint的命令覆盖掉)。
CMD [“/usr/sbin/nginx”,”-g”,”daemon off;”] (daemon off:运行为前端,在dockerfile文件里)
/usr/sbin/nginx -g “daemon off;” 在命令行里
创建镜像示例8:(使用entrypoint来传递变量的参数)
mkdir /root/img3 (创建一个文件夹)
vim /root/img3/Dockerfile (创建dockerfile的配置文件)
vim entrypoint.sh (编写一个脚本)
添加脚本的执行权限。
docker build -t nginx:2.3 /root/img3/ (创建新的镜像)
docker run –name kk –rm nginx:2.3 (以此镜像为基础开启一个容器)
本文来自投稿,不代表Linux运维部落立场,如若转载,请注明出处:http://www.178linux.com/104466