docker
1.1Docker的数据管理
[ _data]# docker volume inspect container-vl1 [ { "CreatedAt": "2020-03-05T13:13:24+08:00", "Driver": "local", "Labels": {}, "Mountpoint": "/var/lib/docker/volumes/container-vl1/_data", "Name": "container-vl1", "Options": {}, "Scope": "local" } ]
1.1.1启动一个挂载数据卷的容器
在用 <span lang="en-us" xml:lang="en-us">docker run</span>
命令的时候,使用 <span lang="en-us" xml:lang="en-us">--mount</span>
标记来将 数据卷
挂载到容器里。在一次 <span lang="en-us" xml:lang="en-us">docker run</span>
中可以挂载多个 数据卷
。
下面创建一个名为 <span lang="en-us" xml:lang="en-us">web</span>
的容器,并加载一个 数据卷
到容器的 <span lang="en-us" xml:lang="en-us">/webapp</span>
目录。
docker run -d --name web --mount source=container-vl1,target=/webapp training/webapp python app.py
[ ~]# docker run -d --name web --mount source=container-vl1,target=/webapp training/webapp python app.py [ ~]# docker exec -it -u root 6f8cd71ff589 /bin/bash :/opt/webapp# cd /webapp/ :/webapp# ls :/webapp# mkdir test :/webapp# la test [ ~]# cd /var/lib/docker/volumes/container-vl1/_data/ [ _data]# ls test
数据卷在OpenStack中可做日志目录,,删除容器,对数据卷中的依然存在。
1.1.2删除数据卷
$ docker volume rm my-vol
数据卷
是被设计用来持久化数据的,它的生命周期独立于容器,Docker 不会在容器被删除后自动删除 数据卷
,并且也不存在垃圾回收这样的机制来处理没有任何容器引用的 数据卷
。如果需要在删除容器的同时移除数据卷。可以在删除容器的时候使用 <span lang="en-us" xml:lang="en-us">docker rm -v</span>
这个命令。
无主的数据卷可能会占据很多空间,要清理请使用以下命令
$ docker volume prune
1.2挂载主机目录
1.2.1挂载一个主机目录作为数据卷(目录映射)
使用 <span lang="en-us" xml:lang="en-us">--mount</span>
标记可以指定挂载一个本地主机的目录到容器中去。
$ docker run -d -P \
--name web \
--mount type=bind,source=/src/webapp,target=/opt/webapp \
training/webapp \
python app.py
上面的命令加载主机的 <span lang="en-us" xml:lang="en-us">/src/webapp</span>
目录到容器的 <span lang="en-us" xml:lang="en-us">/opt/webapp</span>
目录。这个功能在进行测试的时候十分方便,比如用户可以放置一些程序到本地目录中,来查看容器是否正常工作。本地目录的路径必须是绝对路径,以前使用 <span lang="en-us" xml:lang="en-us">-v</span>
参数时如果本地目录不存在 Docker 会自动为你创建一个文件夹,现在使用 <span lang="en-us" xml:lang="en-us">--mount</span>
参数时如果本地目录不存在,Docker 会报错。
Docker 挂载主机目录的默认权限是 读写
,用户也可以通过增加 <span lang="en-us" xml:lang="en-us">readonly</span>
指定为 只读
。
$ docker run -d –p \
--name web \
--mount type=bind,source=/src/webapp,target=/opt/webapp,readonly \
training/webapp \
python app.py
加了 <span lang="en-us" xml:lang="en-us">readonly</span>
之后,就挂载为 只读
了。如果你在容器内 <span lang="en-us" xml:lang="en-us">/opt/webapp</span>
目录新建文件,会显示如下错误
/opt/webapp # touch new.txt
touch:new.txt:Read-only file system
使用-v 挂载
docker run -d –p \
--name web2 \
-v /src/webapp:/opt/webapp,readonly \
training/webapp \
python app.py
1.2.2 挂载一个本地主机文件作为数据卷
<span lang="en-us" xml:lang="en-us">--mount</span>
标记也可以从主机挂载单个文件到容器中
$ docker run --rm -it \
--mount type=bind,source=$HOME/.bash_history,target=/root/.bash_history \
ubuntu:18.04 \
bash
:/# history
1 ls
2 diskutil list
这样就可以记录在容器输入过的命令了
2.DockerFile详解
2.1 认识Dockerfile
2.1.1 镜像的生成途径
- 基于容器制作 docker commit
- dockerfile,docker build
2.1.2 Dockerfile 介绍
Docker中有个非常重要的概念叫做——镜像(Image)。Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。
镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么之前提及的无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile。
Dockerfile 是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
dockerfile编译一个镜像
docker build -t name:tag -f dockerfile的绝对路径 ./
2.1.3 Dockerfile 的使用
(1)Dockerfile 编写的基本结构
Dockerfile 一般分为四部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令,’#’ 为 Dockerfile 中的注释。
(2)一台主机可以有多个Dockerfile
要使用多个Dockerfile 创建镜像,可以在不同目录编写Dockerfile,然后在Dockerfile 所在的目录下构建新的镜像;
注意:Dockerfile 中所包含的需要的内容;如COPY的文件、目录等,都需要在Dockerfile 同级目录下存在;
(3)docker build 基于dockerfile制作镜像的命令
① 格式:
docker build [OPTIONS] PATH | URL | -
② 选项:
- -t:打标签
- -c,- cpu-shares int :CPU份额(相对权重)
- -m,- memory bytes:内存限制
- --build-arg:设置构建时变量,就是构建的时候修改ARG指令的参数
2.1.4 Dockerfile 指令
· FROM
· MAINTAINER
· COPY
· ADD
· WORKDIR
· VOLUME
· EXPOSE
· ENV
· RUN
· CMD
· ENTRYPOINT
· HEALTHCHECK
· ONBUILD
· USER
· ARG
· SHELL
· STOPSIGNAL
FROM
格式
<span lang="en-us" xml:lang="en-us">FROM <repository>[:<tag>] </span>
或
<span lang="en-us" xml:lang="en-us">FROM <repository>@<digest></span>
注:
- <repository>:指定作为base image的名称;
- <tag>:base image的标签,省略时默认latest;
- <digest>:是镜像的哈希码;使用哈希码会更安全一点;
如:
FROM busybox:latest
MAINTAINER
介绍
- 用于让dockerfile制作者提供本人的详细信息
- dockerfile 并不限制MAINTAINER 指令可在出现的位置,但推荐将其放置于FROM指令之后
如:
MAINTAINER <authtor‘s detail>
<span lang="en-us" xml:lang="en-us"> # Description: test image</span>
<span lang="en-us" xml:lang="en-us"> FROM busybox:latest</span>
<span lang="en-us" xml:lang="en-us"> MAINTAINER "Along <>"</span>
COPY
介绍
- 用于从docker 主机复制新文件或者目录至创建的新镜像指定路径中
格式
COPY <src>... <dest>
或
COPY ["<src>",... "<dest>"]
注:
- <src>:要复制的源文件或目录,支持使用通配符;
- <dest>:目标路径,即正在创建的image的文件系统路径;建议<dest>使用绝对路径,否则,COPY指定以WORKDIR为其实路径
- 在路径中有空白字符时,通常使用第2中格式;
文件复制准则
- <src>必须是build上下文中的路径,不能是其父目录中的文件;(也就是必须在dockerfile同级目录)
- 如果<src>是目录,则其内部文件或子目录会被递归复制,但<src>目录自身不会被复制;
- 如果指定了多个<src>,或在<src>中使用了通配符,则<dest>必须是一个目录,且必须以 / 结尾;
- 如果<dest>事先不存在,他将会被自动创建,这包括父目录路径。
如:
COPY index.html /data/web/html/ <span lang="en-us" xml:lang="en-us">#</span>
要确保
<span lang="en-us" xml:lang="en-us">dockerfile </span>
同级路径下有
<span lang="en-us" xml:lang="en-us">index.html</span>
文件
使用build 制作镜像
ADD 和 COPY 类似
格式
<span lang="en-us" xml:lang="en-us">ADD <src> ..<dest> </span>
或
<span lang="en-us" xml:lang="en-us">ADD ["<src>".. "<dest>"]</span>
- add 本地文件是压缩文件 复制到容器内之后自动解压。
- add url文件获取。 拉去网上tar包到容器时不解压
<span lang="en-us" xml:lang="en-us"> ADD http://nginx.org/download/nginx-1.15.8.tar.gz /usr/local/src/</span>
<span lang="en-us" xml:lang="en-us"> ADD nginx-1.15.8.tar.gz /usr/local/src/</span>
操作准则
- 同COPY指令
- 如果<src>为URL且<dest>不以 / 结尾,则<src>指定的文件将被下载并直接被创建为<dest>;如果<dest>以/结尾,则文件名URL指定的文件将被直接下载并保存为<dest>/ <filename>
- 如果<src>是一个本地系统上的压缩格式的tar文件,它将被展开为一个目录,其行为类似于"tar-x"命令;然而,通过URL获取到的tar文件将不会自动展开;
- 如果<src>有多个,或其间接或直接使用了通配符,则<dest>必须是一个以/结尾的目录路径 ;如果<dest>不以/结尾,则其被视作一个普通文件,<src>的内容将被直接写入到<dest>;
WORKDIR
介绍
为指令RUN、CMD、ENTRYPOINT、COPY和ADD指定设定工作目录。类似于cd的意思
如:
<span lang="en-us" xml:lang="en-us"> WORKDIR /usr/local/</span>
<span lang="en-us" xml:lang="en-us"> ADD nginx-1.15.8.tar.gz ./src/</span>
运行容器后tar包解压到容器的/usr/local/src/目录下
VOLUME
介绍
- 用于在image中创建一个挂载点目录,以挂载Docker host.上的卷或其它容器上的卷(用于临时数据卷,容器删除后数据卷跟着删除)
- 一般用 --mount 和 -v 很少用volume
在dockerfile中写入:
VOLUME /data/mysql
docker build -t busyboxhttpd:v0.5 ./
docker inspect -f {{.Mounts}} web1 [{volume b788b8a50d69953e2b086b3b54ba683154647319a481246cb7ab2ff927b21372/var/lib/docker/volumes/b788b8a50d69953e2b086b3b54ba683154647319a481246cb7ab2ff927b21372/_data /data/mysql local true }]
b788b8a50d69953e2b086b3b54ba683154647319a481246cb7ab2ff927b21372这个卷就是运行容器后在本地新建的卷,映射到容器的/data/mysql目录。
VOLUME 删除容器的时候,所创建的volume一并删除。
EXPOSE
介绍
用于为容器打开指定要监听的端口以实现与外部通信
注:
- <protocol>用于指定传输层协议,可为tcp或udp二者之一,默认为TCP协议
- EXPOSE指令可一次指定多个端口,例如:EXPOSE 11211/udp 11211/tcp
如:
EXPOSE 80/tcp
注:就算dockerfile 中有EXPOSE 指令暴露端口,但是不是真正的暴露;需要在启动容器时,使用-P 选项真正的暴露端口。
docker build -t busyboxhttpd:v0.6 ./
<span lang="en-us" xml:lang="en-us">docker run --name web1 -P --rm -it busyboxhttpd:v0.6 /bin/httpd -f -h /data/web/html</span>
<span lang="en-us" xml:lang="en-us">docker inspect -f {{.NetworkSettings.IPAddress}} web1 #</span>
查询容器的
<span lang="en-us" xml:lang="en-us">IP</span>
另打开一个终端,验证<span lang="en-us" xml:lang="en-us">httpd </span>
服务的
<span lang="en-us" xml:lang="en-us">80</span>
端口
<span lang="en-us" xml:lang="en-us">[ ~]# curl 172.17.0.2:80</span>
<span lang="en-us" xml:lang="en-us"><h1>Busybox httpd server</h1></span>
<span lang="en-us" xml:lang="en-us">--- </span>
在宿主机通过暴露的端口访问
<span lang="en-us" xml:lang="en-us">httpd </span>
服务
<span lang="en-us" xml:lang="en-us">[ ~]# docker port web1</span>
<span lang="en-us" xml:lang="en-us">80/tcp</span>
<span lang="en-us" xml:lang="en-us">-> 0.0.0.0:32768</span>
<span lang="en-us" xml:lang="en-us">[ ~]# curl 127.0.0.1:32768</span>
<span lang="en-us" xml:lang="en-us"><h1>Busybox httpd server</h1></span>
ENV
介绍
- 用于为镜像定义所需的环境变量,并可被Dockerfile文件中位于其后的其它指令(如ENV、ADD、COPY等)所调用
- 调用格式为$variable_ name 或 ${variable_ name}
注:
- 第一种格式中,<key>之后的所有内容均会被视作其<value>的组成部分,因此,一次只能设置一个变量;
- 第二种格式可用一次设置多个变量,每个变量为一个”<key>=<value>"的键值对,如果<value>中包含空格,可以以反斜线(\)进行转义,也可通过对<value>加引号进行标识;另外,反斜线也可用于续行;
- 定义多个变量时,建议使用第二种方式,以便在同一层中完成所有功能
ENV DOC_ROOT=/data/web/html/ \ WEB_SERVER_PACKAGE="nginx-1.15.8"COPY index.html ${DOC_ROOT}
RUN
介绍
- 用于指定docker build过程中运行的程序,其可以是任何命令
语法
RUN <command>
或
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>"]
如:
<span lang="en-us" xml:lang="en-us"> RUN cd</span>
<span lang="en-us" xml:lang="en-us">./src</span>
<span lang="en-us" xml:lang="en-us">&& \</span>
<span lang="en-us" xml:lang="en-us"> tar</span>
<span lang="en-us" xml:lang="en-us">-xf ${WEB_SERVER_PACKAGE}</span>
此次有变量替换推荐用第一种语法
CMD
介绍
- 类似于RUN指令,CMD指令也可用于运行任何命令或应用程序,不过,二者的运行时间点不同
- RUN指令构建镜像过程中执行 CMD指令容器启动时执行
- CMD指令的首要目的在于为启动的容器指定默认要运行的程序,且其运行结束后,容器也将终止;不过,CMD指定的命令其可以被docker run的命令行选项所覆盖
- 在Dockerfile中可以存在多个CMD指令,但仅最后一个会生效
语法
CMD <command>
或
CMD [“<executable>",“<param1>","<param2>"]
或
CMD ["<param1>","<param2>"]
注:
- 前两种语法格式的意义同RUN
- 第三种则用于为ENTRYPOINT指令提供默认参数
- json数组中,要使用双引号,单引号会出错
示例编写dockerfile文件
FROM busybox LABEL maintainer="Along <>" app="httpd" ENV WEB_DOC_ROOT="/data/web/html" RUN mkdir -p ${WEB_DOC_ROOT} && echo "<h1>Busybox httpd server</h1>" > ${WEB_DOC_ROOT}/index.html CMD /bin/httpd -f -h ${WEB_DOC_ROOT}
使用build 制作镜像
docker build -t busyboxhttpd:v1.1 ./
基于此新建镜像运行容器,进行验证,httpd正常运行
docker run --name web2 --rm -d busyboxhttpd:v1.1
curl 容器IP
ENTRYPOINT
介绍
- 类似CMD指令的功能,用于为容器指定默认运行程序,从而使得容器像是一个单独的可执行程序
- 与CMD不同的是,由ENTRYPOINT启动的程序不会被docker run命令行指定的参数所覆盖,而且,这些命令行参数会被当作参数传递给ENTRYPOINT指定指定的程序
- 不过,docker run命令的 --entrypoint选项的参数可覆盖ENTRYPOINT指令指定的程序
语法
ENTRYPOINT <command>
ENTRYPOINT ["<executable>", "<param1>", "<param2>"]
注:
- docker run命令传入的命令参数会覆盖CMD指令的内容并且附加到ENTRYPOINT命令最后做为其参数使用
- Dockerfile文件中也可以存在多个ENTRYPOINT指令,但仅有最后一个会生效
如:
CMD ["curl","-s","https://ip.cn"]
ENTRYPOINT ["curl","-s","https://ip.cn"]
当我们启动容器 docker run http:v1 -i 时 -i 参数会覆盖CMD指令后的["curl","-s","https://ip.cn"]
而对于ENTRYPOINT指令 -i就是新的 CMD
,因此会作为参数传给 curl
,["curl","-s","https://ip.cn","-i"]