Dockerfile简介
Dockerfile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本
构建三步骤:
- 编写Dockerfile文件:必须符合file规范
- docker build:
docker build -f /mydocker/Dockerfile -t mrlinxi/centos .
通过docker build获得一个自定义的镜像 - docker run
文件长什么样?下面就是我们使用的centos的Dockerfile
FROM scratch ADD centos-7-x86_64-docker.tar.xz / LABEL \ org.label-schema.schema-version="1.0" \ org.label-schema.name="CentOS Base Image" \ org.label-schema.vendor="CentOS" \ org.label-schema.license="GPLv2" \ org.label-schema.build-date="20201113" \ org.opencontainers.image.title="CentOS Base Image" \ org.opencontainers.image.vendor="CentOS" \ org.opencontainers.image.licenses="GPL-2.0-only" \ org.opencontainers.image.created="2020-11-13 00:00:00+00:00" # default cmd CMD ["/bin/bash"]
6.2 DockerFile构建过程解析
Dockerfile内容基础知识:
- 每条保留字指令都必须为大写字母且后面要跟随至少一个参数
- 指令按照从上到下,顺序执行
- 表示注释
- 每条指令都会创建一个新的镜像层,并对镜像进行提交
Docker执行Dockerfile的大致流程:
- (1)docker从基础镜像运行一个容器
- (2)执行一条指令并对容器作出修改
- (3)执行类似docker commit的操作提交一个新的镜像层
- (4)docker再基于刚提交的镜像运行一个新容器
- (5)执行dockerfile中的下一条指令直到所有指令都执行完成
总结:
从应用软件的角度来看,Dockerfile、Docker镜像与Docker容器分别代表软件的三个不同阶段,
- Dockerfile是软件的原材料
- Docker镜像是软件的交付品
- Docker容器则可以认为是软件的运行态。
Dockerfile面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可,合力充当Docker体系的基石。
- Dockerfile,需要定义一个Dockerfile,Dockerfile定义了进程需要的一切东西。Dockerfile涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道,这时需要考虑如何设计namespace的权限控制)等等;
- Docker镜像,在用Dockerfile定义一个文件之后,docker build时会产生一个Docker镜像,当运行 Docker镜像时,会真正开始提供服务;
- Docker容器,容器是直接提供服务的。
6.3 DockerFile体系结构(保留字指令)
FROM:基础镜像,当前新镜像是基于哪个镜像的。基于什么镜像进行修改;
MAINTAINER:镜像维护者的姓名和邮箱地址;
RUN:容器构建时需要运行的命令;
EXPOSE:当前容器对外暴露出的端口;
WORKDIR:指定在创建容器后,终端默认登陆的进来工作目录,一个落脚点,没写默认根目录/
;
ENV:用来在构建镜像过程中设置环境变量;
例如:ENV MY_PATH /usr/mytest
这个环境变量可以在后续的任何RUN指令中使用,这就如同在命令前面指定了环境变量前缀一样;也可以在其它指令中直接使用这些环境变量。
比如:WORKDIR $MY_PATH
ADD:将宿主机目录下的文件拷贝进镜像且ADD命令会自动处理URL和解压tar压缩包;
COPY:类似ADD,拷贝文件和目录到镜像中。将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置; COPY src dest
COPY ["src", "dest"]
ADD跟COPY的区别在于ADD在复制后会自动解压缩和处理URL,而COPY仅仅进行复制。
VOLUME:容器数据卷,用于数据保存和持久化工作;
CMD:指定一个容器启动时要运行的命令;Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换(后面案例会具体说明);
ENTRYPOINT:指定一个容器启动时要运行的命令;ENTRYPOINT 的目的和 CMD 一样,都是在指定容器启动程序及参数;
CMD与ENTRYPOINT的区别是CMD存在多个时只有最后一个生效以及CMD会被docker run之后的参数替换;而ENTRYPOINT是追加命令。
ONBUILD:当构建一个被继承的Dockerfile时运行命令,父镜像在被子继承后父镜像的onbuild被触发
6.4 案例
1. Base镜像(scratch)
Docker Hub 中 99% 的镜像都是通过在 base 镜像中安装和配置需要的软件构建出来的。
2. 自定义镜像mycentos
Hub默认CentOS镜像什么情况:
自定义mycentos目的使我们自己的镜像具备如下:
登陆后的默认路径、vim编辑器、查看网络配置ifconfig支持
安装Centos镜像之后会默认进入根目录,但是不支持vim也不支持ifconfig,因此利用DockerFile创建的时候安装好相关插件以及修改默认根目录
① 编写自定义镜像的Dockerfile
我们在宿主机的/mydocker
文件夹下,新建一个Dockerfile:vim Dockerfile2
,写入下面的内容
from centos --继承自本地镜像 MAINTAINER ylc<xxx@qq.com> --作者和邮箱 ENV mypath /tmp --环境变量 WORKDIR $mypath --默认登陆的进来目录 RUN yum -y install vim --安装vim RUN yum -y install net-tools EXPOSE 80 --指定端口 CMD echo $MYPATH --打印内容 CMD echo “success-----ok” CMD /bin/bash
② 构建自定义镜像——docker build
docker build -f /root/mydocker/Dockerfile2 -t mycentos:1.3 .
build语句最后面一个**.**
表示当前目录
③ 运行自定义镜像——docker run
docker run -it mycentos:1.3
可以看到默认进入的目录是/tmp
④ 列出镜像的变更历史
docker history 镜像名
每一步都产生了一个镜像,镜像都是层层叠加的,内部像千层饼一样
3. CMD/ENTRYPOINT 镜像案例
CMD/ENTRYPOINT都是指定一个容器启动时要运行的命令
① CMD镜像案例
Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换。
这里以tomcat为例,tomcat的dockerfile最后一句是
正常我们启动tomcat的命令是:docker run -it -p 主机端口:8080 tomcat
现在我们执行这样一句命令:docker run -it -p 8888:8080 tomcat ls -l
这样就相当于在tomcat的dockerfile后面又加了一句CMD ls -l
,因此会覆盖掉之前的语句。
此时tomcat并没有运行,只是查看了默认路径下的文件。
② ENTRYPOINT镜像案例
docker run 之后的参数会被当做参数传递给 ENTRYPOINT,之后形成新的命令组合。
制作CMD版可以查询IP信息的容器:
FROM centos RUN yum install -y curl CMD [ "curl", "-s", "https://ip.cn" ]
crul命令解释:curl命令可以用来执行下载、发送各种HTTP请求,指定HTTP头部等操作。curl是将下载文件输出到stdout。
使用命令:curl http://www.baidu.com,执行后,www.baidu.com的html就会显示在屏幕上了。这是最简单的使用方法。用这个命令获得了http://curl.haxx.se指向的页面,同样,如果这里的URL指向的是一个文件或者一幅图都可以直接下载到本地。如果下载的是HTML文档,那么缺省的将只显示文件头部,即HTML文档的header。要全部显示,请加参数 -i
构建镜像:docker build -f /mydocker/Dockerfile3 -t myip .
创建并启动容器:docker run myip
现在返回的是网页的html文件。
如果我们希望显示 HTTP 头信息,就需要加上 -i
参数:
加上-i
后报错了。我们可以看到可执行文件找不到的报错,executable file not found。
之前我们说过,跟在镜像名后面的是 command,运行时会替换 CMD 的默认值。因此这里的 -i 替换了原来的 CMD,而不是添加在原来的 curl -s https://ip.cn 后面。而 -i 根本不是命令,所以自然找不到。那么如果我们希望加入 -i 这参数,我们就必须重新完整的输入这个命令:
docker run myip curl -s https://ip.cn -i
为了解决上述问题,制作ENTROYPOINT版查询IP信息的容器。
FROM centos RUN yum install -y curl ENTRYPOINT [ "curl", "-s", "http://ip.cn" ] docker build -f /mydocker/Dockerfile4 -t myip2 docker run myip2 -i
现在只用追加一个-i
即可打印请求头跟html文件。
③ ONBUILD案例
直接在Dockerfile4上修改,追加一句ONBUILD RUN echo "father onbuild-----------10086"
然后使用Dockerfile4构建镜像:docker build -f /mydocker/Dockerfile4 -t myip_father .
复制Dockerfile3命名为Dockerfile5,修改Dockerfile5,直接继承自Dockerfile4:
FROM myip_father RUN yum install -y curl CMD [ "curl", "-s", "https://ip.cn" ]
使用Dockerfile5构建镜像:docker build -f /mydocker/Dockerfile5 -t myip_son .