一 DockerFile 内容基础知识
Dockerfile 是用来构建 Docker 镜像的构建文件,是由一系列命令和参数构成的脚本。
编写 dockerFile 的步骤
- 编写 DockerFile 文件
- 执行 docker build 命令,获得一个自定义的镜像
- 执行 docker run ,运行生成的镜像
centos 官方 dockerFile 文件内容如下:
1 | FROM scratch |
1.1 Docker 执行 Dockerfile 的大致流程
- docker 从基础镜像运行一个容器
- 执行一条指令并对容器作出修改
- 执行类似 docker commit 的操作提交一个新的镜像层
- docker 再基于刚提交的镜像运行一个新容器
- 执行 dockerfile 中的下一条指令直到所有指令都执行完成
从应用软件的角度来看,Dockerfile、Docker 镜像与 Docker 容器分别代表软件的三个不同阶段,
Dockerfile 是软件的原材料
Docker 镜像是软件的交付品
Docker 容器则可以认为是软件的运行态。
Dockerfile 面向开发,Docker 镜像成为交付标准,Docker 容器则涉及部署与运维,三者缺一不可,合力充当 Docker 体系的基石。
- Dockerfile,需要定义一个 Dockerfile,Dockerfile 定义了进程需要的一切东西。Dockerfile 涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道,这时需要考虑如何设计 namespace 的权限控制)等等;
- Docker 镜像,在用 Dockerfile 定义一个文件之后,docker build 时会产生一个 Docker 镜像,当运行 Docker 镜像时,会真正开始提供服务;
- Docker 容器,容器是直接提供服务的。
1.2 docker 的体系结构
- ADD: 将宿主机目录下的文件拷贝进镜像且ADD命令会自动处理URL和解压tar压缩包
- CMD: 指定一个容器启动时要运行的命令,Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换
- COPY: 类似ADD,拷贝文件和目录到镜像中。将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置(COPY src dest 或者 COPY [“src”,”dest”])
- ENTRYPOINT: 指定一个容器启动时要运行的命令,ENTRYPOINT的目的和 CMD 一样,都是在指定容器启动程序及参数
- ENV: 用来在构建镜像过程中设置环境变量
- EXPOSE: 当前容器对外暴露出的端口
- FROM : 基础镜像,当前新镜像是基于哪个镜像的
- HEALTHCHECH- 健康检测指令
- MAINTAINER : 镜像维护者的姓名和邮箱地址
- ONBUILD: 当构建一个被继承的Dockerfile时运行命令,父镜像在被子继承后父镜像的onbuild被触发
- RUN: 容器构建时需要运行的命令
- USER: 指定后续执行的用户组和用户
- VOLUME: 容器数据卷,用于数据保存和持久化工作
- WORKDIR: 指定在创建容器后,终端默认登陆的进来工作目录,一个落脚点。为 RUN、CMD、ENTRYPOINT、COPY 和 ADD 设置工作目录,就是切换目录
注意
1 | ENV MY_PATH /usr/mytest |
这个环境变量可以在后续的任何 RUN 指令中使用,这就如同在命令前面指定了环境变量前缀一样;也可以在其它指令中直接使用这些环境变量,
比如:WORKDIR \$MY_PATH
二 DockerFile 命令详解
Base 镜像(scratch) : Docker Hub 中 99% 的镜像都是通过在 base 镜像中安装和配置需要的软件构建出来的
2.1 CMD 命令
CMD类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:
CMD 在docker run 时运行。
RUN 是在 docker build。
Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换
1 | CMD <shell 命令> |
例如我们在启动 tomcat 镜像时,执行一下命令
1 | docker run -it -p 8888:8080 tomcat ls -l |
上述命令会覆盖 tomcat 的 dockerFile 文件最后的启动定义命令
1 | CMD ["catalina.sh", "run"] |
因此会导致 tomcat 的 Docker 镜像无法启动里面的 tomcat
2.2 ENTRYPOINT 命令
类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。
但是 如果运行 docker run 时使用了 —entrypoint 选项,将覆盖 ENTRYPOINT 指令指定的程序。
语法格式:
1 | ENTRYPOINT ["<executeable>","<param1>","<param2>",...] |
ENTRYPOINT 可以搭配 CMD 命令使用:一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参
docker run 之后的参数会被当做参数传递给 ENTRYPOINT,之后形成新的命令组合
2.2.1 示例一
例如假设已通过 Dockerfile 构建了 nginx:test 镜像:
1 | FROM nginx |
1、不传参运行
1 | $ docker run nginx:test |
容器内会默认运行以下命令,启动主进程。
1 | nginx -c /etc/nginx/nginx.conf |
2、传参运行
1 | $ docker run nginx:test -c /etc/nginx/new.conf |
容器内会默认运行以下命令,启动主进程(/etc/nginx/new.conf:假设容器内已有此文件)
1 | nginx -c /etc/nginx/new.conf |
2.2.2 示例二
制作一个查询 IP 的镜像
DockerFile 文件的定义如下:
1 | FROM centos |
如果我们希望显示 HTTP 头信息,就需要运行改容器镜像时加上-i
参数,我们可以看到可执行文件找不到的报错,executable file not found。之前说过,跟在镜像名后面的是 command,运行时会替换 CMD 的默认值。因此这里的-i
替换了原来的 CMD,而不是添加在原来的curl -s http://ip.cn
后面。而-i
根本不是命令,所以自然找不到。那么如果我们希望加入-i
这参数,可以将 CMD 替换为
新的 DockerFIle 文件的定义如下:
1 | FROM centos |
此时,重新完整的输入这个命令:
1 | docker run myip curl -s http://ip.cn -i |
可以看到,输出了想要的结果信息
2.3 ONBUILD 命令
用于延迟构建命令的执行。简单的说,就是 Dockerfile 里用 ONBUILD 指定的命令,在本次构建镜像的过程中不会执行(假设镜像为 test-build)。当有新的 Dockerfile 使用了之前构建的镜像 FROM test-build ,这时执行新镜像的 Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令。
语法格式:
1 | ONBUILD <其它指令> |
制作一个包含 onbuild 的镜像,其 DockerFIle 文件内容如下:
1 | FROM centos |
2.4 RUN命令
CMD类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:
- CMD 在docker run 时运行。
- RUN 是在 docker build。
RUN:用于执行后面跟着的命令行命令。有以下俩种格式:
shell 格式:
1 | RUN <命令行命令> |
exec 格式:
1 | RUN ["可执行文件", "参数1", "参数2"] |
注意:Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大。例如:
1 | FROM centos |
以上执行会创建 3 层镜像。可简化为以下格式:
1 | FROM centos |
如上,以 && 符号连接命令,这样执行后,只会创建 1 层镜像。
2.5 COPY命令
复制指令,从上下文目录中复制文件或者目录到容器里指定路径。
语法格式:
1 | COPY [--chown=<user>:<group>] <源路径1>... <目标路径> |
[--chown=<user>:<group>]
:可选参数,用户改变复制到容器内文件的拥有者和属组。
<源路径>
:源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则。例如:
1 | COPY hom* /mydir/ |
<目标路径>
:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。
2.6 ADD命令
ADD 指令和 COPY 的使用格类似(同样需求下,官方推荐使用 COPY)。功能也类似,不同之处如下:
- ADD 的优点:在执行
<源文件>
为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到<目标路径>
。 - ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定
2.7 ENV命令
设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。
语法格式:
1 | ENV <key> <value> |
以下示例设置 NODE_VERSION = 7.2.0 , 在后续的指令中可以通过 $NODE_VERSION 引用:
1 | ENV NODE_VERSION 7.2.0 |
2.8 ARG命令
构建参数,与 ENV 作用一致。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。
构建命令 docker build 中可以用 —build-arg <参数名>=<值> 来覆盖。
语法格式:
1 | ARG <参数名>[=<默认值>] |
2.9 VOLUME命令
定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。
作用:
- 避免重要的数据,因容器重启而丢失,这是非常致命的。
- 避免容器不断变大。
语法格式:
1 | VOLUME ["<路径1>", "<路径2>"...] |
在启动容器 docker run 的时候,我们可以通过 -v 参数修改挂载点。
2.10 EXPOSE
仅仅只是声明端口。
作用:
- 帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射。
- 在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。
格式:
1 | EXPOSE <端口1> [<端口2>...] |
2.11 WORKDIR
指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会帮你建立目录。
docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。
格式:
1 | WORKDIR <工作目录路径> |
2.12 USER
用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。
格式:
1 | USER <用户名>[:<用户组>] |
2.13 HEALTHCHECK
用于指定某个程序或者指令来监控 docker 容器服务的运行状态。
格式:
1 | HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令 |
三 构建自定义tomcat镜像
这里演示自定义 tomcat的docker镜像
- 在/docker_images 目录下创建一个名为 c.txt 的文本文件
- 将 tomcat 和 jdk 的安装包拷贝到上述目录
在该目录下创建一个 DockerFIle 文件
DockerFIle 文件内容如下:
1 | FROM centos |
此时,文件的目录内容如下:
1 | yishui@yishui:~/桌面/docker_images$ pwd |
3.1 构建命令
1 | docker build -t yishui_tomcat . |
或者
1 | docker build -f Dockerfile -t yishui_tomcat . |
注意: 因为这里 DockerFile 文件的名字为 Dockerfile,所以可以的省略-f 命令
执行命令,得到的结果如下:
yishui@yishui:~/桌面/docker_images$ docker build -t yishui_tomcat "docker build" requires exactly 1 argument. See 'docker build --help'. Usage: docker build [OPTIONS] PATH | URL | - Build an image from a Dockerfile yishui@yishui:~/桌面/docker_images$ docker build -t yishui_tomcat . Sending build context to Docker daemon 573.8MB Step 1/15 : FROM centos ---> 1e1148e4cc2c Step 2/15 : MAINTAINER yishui<zhiyubujian@163.com>
注意 命令的最后一个点,一定要加,否则会出问题
3.2 查看是否有镜像生成
yishui@yishui:~/桌面/docker_images$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE yishui_tomcat latest b359862a31e7 2 minutes ago 726MB yishui/tomcat-demo 1.0 1323b27a2652 2 days ago 463MB <none> <none> 7cfe70fc34b0 2 days ago 463MB tomcat latest 168588387c68 3 weeks ago 463MB centos latest 1e1148e4cc2c 2 months ago 202MB
3.3 运行构建的镜像
yishui@yishui:~/桌面/docker_images$ docker run -it -p 8000:8080 b359862a31e7 Using CATALINA_BASE: /usr/local/apache-tomcat-9.0.16 Using CATALINA_HOME: /usr/local/apache-tomcat-9.0.16 Using CATALINA_TMPDIR: /usr/local/apache-tomcat-9.0.16/temp Using JRE_HOME: /usr/local/jdk1.8.0_144 Using CLASSPATH: /usr/local/apache-tomcat-9.0.16/bin/bootstrap.jar:/usr/local/apache-tomcat-9.0.16/bin/tomcat-juli.jar Tomcat started. tail: cannot open '/usr/local/apache-tomcat-9.0.8/bin/logs/catalina.out' for reading: No such file or directory tail: cannot watch parent directory of '/usr/local/apache-tomcat-9.0.8/bin/logs/catalina.out': No such file or directory tail: inotify cannot be used, reverting to polling
通过http://localhost:8000/ 访问,发现可以看到 tomcat 管理界面,镜像构建成功
或者运行以下命令
docker run -d -p 9080:8080 —name myt9 -v /demo/tomcat9/test:/usr/local/apache-tomcat-9.0.16/webapps/test -v /demo/tomcat9/tomcat9logs/:/usr/local/apache-tomcat-9.0.16/logs —privileged=true b359862a31e7
注意 -v 该命令表示挂载容器卷
Docker 挂载主机目录 Docker 访问出现 cannot open directory .: Permission denied
解决办法:在挂载目录后多加一个—privileged=true 参数即可
四 自定义 centos
4.1. 编写 DockerFile 文件
先查看官方文件,得知,自定义镜像具备以下情况
- 登陆后的默认路径
- vim编辑器
- 查看网络配置ifconfig支持
编写好自定义的 DockerFile 文件,内容如下
1 | FROM centos |
4.2. 构建 Docker 镜像
1 | docker build -t 新镜像的名字:TAG . |
注意 上述命令最后的 .
表示的是当前路径
具体的命令如下:
1 | docker build -f /demo/myDockerFile -t mycentos/centos:1.0 . |
4.3. 查询是否构建成功
使用 docker images 命令查询是否构建成功
1 | docker images |
4.4. 运行构建的镜像
1 | docker run -it mycentos/centos:1.0 |
4.5. 列出镜像的变更历史
1 | docker history 镜像名 |