docker

1.1Docker的数据管理

  数据卷和目录映射
  数据卷
  本质: 就是本地宿文件系统的一个目录
docker  volume create container-vl1
[ ~]# docker volume ls
DRIVER              VOLUME NAME
local               container-vl1
[ _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 镜像的生成途径

  1.  基于容器制作 docker commit
  2.  dockerfiledocker 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 

介绍

  1.  用于让dockerfile制作者提供本人的详细信息
  2. 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

介绍

  1. 用于从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 制作镜像

  docker build -t busyboxhttpd:v0.1 ./    创建在当前目录(改目录下一般放置创建镜像所需的文件,如要copy的文件等)
  -f /tmp/Dockerfile 指定dockerfile绝对路径
基于此新建镜像运行容器,进行验证
  [ ~]# docker run --name web1 --rm busyboxhttpd:v0.1 cat /data/web/html/index.html
  <h1>Busybox httpd server</h1>
注:
  --rm:在容器关闭时,直接删除容器,方便实验。

 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>
  1.    add 本地文件是压缩文件  复制到容器内之后自动解压。
  2.    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

介绍

  用于为容器打开指定要监听的端口以实现与外部通信

注:

  1. <protocol>用于指定传输层协议,可为tcp或udp二者之一,默认为TCP协议
  2. 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}

注:

  1. 第一种格式中,<key>之后的所有内容均会被视作其<value>的组成部分,因此,一次只能设置一个变量;
  2. 第二种格式可用一次设置多个变量,每个变量为一个”<key>=<value>"的键值对,如果<value>中包含空格,可以以反斜线(\)进行转义,也可通过对<value>加引号进行标识;另外,反斜线也可用于续行;
  3. 定义多个变量时,建议使用第二种方式,以便在同一层中完成所有功能
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>"]

一般用第一种写法

注:

  1.  第一种格式中,<command>通常是一个shell命令, 且“/bin/sh -c”来运行它,这意味着此进程在容器中的PID不为1,不能接收Unix信号,因此,当使用docker stop <container>命令停止容器时,此进程接收不到SIGTERM信号
  2.  第二种语法格式中的参数是一个JSON格式的数组,其中<executable>为要运行的命令,后面的 <paramN>为传递给命令的选项或参数;然而,此种格式指定的命令不会以“/bin/sh -c”来发起,因此常见的shell操作变量替换以及通配符(?,*等)替换将不会进行;不过,如果要运行的命令依赖于此shell特性的话,可以将其替换为类似下面的格式。
  3.  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>"]

注:

  1.  前两种语法格式的意义同RUN
  2.  第三种则用于为ENTRYPOINT指令提供默认参数
  3.  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>"]

  1.  docker run命令传入的命令参数会覆盖CMD指令的内容并且附加到ENTRYPOINT命令最后做为其参数使用
  2.  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"]

相关推荐