前言
在之前的博客《Docker端口映射及创建镜像演示(二)--技术流ken》,演示了如何使用一个现有容器创建一个镜像,以及镜像在阿里云的上传和下载。
但是这样的镜像有很大的局限性,不能根据我们的生产需要进行个性化定制,所以我们急需学习一种能够满足我们需要的制作镜像的工具。
这个时候Dockerfile就出现了。
使用dockerfile指令可以根据自己的需要,制作满足自己生产需要的镜像。
本篇博客将详细讲解如何使用dockerfile制作自己的专属镜像。
Dockerfile简介
镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么哪些无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile。
Dockerfile 是一个文本文件,其内包含了一条条的指令,每一条指令构建一层,
因此每一条指令的内容,就是描述该层应当如何构建
Dockerfile编写注意项
- # 备注
- 指令参数,指令的大小写不敏感
- 第一个非注释行必须是FROM指令
- 编写Dockerfile必须在一个目录下进行,这个目录称之为 工作目录(WORKSPACE)
- Dockerfile文件命令的首字母必须大写
- 制作镜像所要用的文件必须放在工作目录或者工作目录的子目录之下,不能放在父目录
- 可以通过隐藏文件 .dockeringnore 来指定不要放入到镜像中的文件,一行是一个文件,可以用通配符
- 基于dockerfile做镜像,本质上还是基于一个现有的镜像做新镜像
Dockerfile指令详解
1. FROM
作用:FROM 就是指定基础镜像,因此一个 Dockerfile 中 FROM 是必备的指令,并且必须是第一条指令
格式:
FROM <registry>:[tag]
FROM <registry>@<digest>
FROM 示例:
第一步:创建工作目录及dockerfile
[root@ken ~]# mkdir /ken [root@ken ~]# cd /ken [root@ken ken]# touch Dockerfile
第二步:写入from指令
docker.io:注册表
nginx:仓库
latest:版本号
[root@ken ken]# cat Dockerfile
FROM docker.io/nginx:latest
2. LABEL
作用:设定一些元数据
格式:
LABEL 信息
LABEL示例:
LABEL author "ken"
3. COPY
作用:将工作目录下的文件复制到所做得镜像中的文件系统中
格式:
复制单个文件:COPY <src> <dest>
复制多个文件:COPY [<src> <src> <src>... <dest>]
COPY示例:
COPY passwd /data/
注意:
- 源文件路径用相对路径,目标一般用绝对路径
- 也可以通配符
- 源文件必须在工作目录或者工作目录的子目录中
- 目标路径可以不存在,会自动创建
- 如果源文件是一个目录,会自动递归复制目录下的文件到目标位置,但是目录自身不会复制
- 如果复制多个文件,或者源文件中用了通配符,那么目标路径必须以 / 为结尾
4. ADD
作用:和COPY类似,可以实现将文件和目录加载镜像中,但是区别是可以实现将tar包解压,也可以实现从网络下载文件到镜像
注意:下载的tar无法解压
格式
ADD <src> <dest>
ADD ["<src>" "<src>" "<src>" "<dest>"]
ADD示例:
ADD nginx-1.14.0.tar.gz /data/
5. WORKDIR
作用:相当于执行cd命令。切换目录,为后续的RUN、CMD、ENTRYPOINT 指令配置工作目录。
格式:
WORKDIR 容器目录
WORKDIR示例:
WORKDIR /pack/nginx/
6. VOLUME
作用:指定数据卷的挂载点
格式:
VOLUME 容器目录
VOLUME示例:
VOLUME /data/mysql/mysql3306/data
7. EXPOSE
作用:设置Docker容器内部暴露的端口号,如果需要外部访问,还需要启动容器时增加-p或者-P参数进行分配。
格式:
EXPOSE PORT/[PROTOCOL]
EXPOSE示例:
EXPOSE 80/tcp
9. ENV
作用:设置环境变量
格式:
ENV var value
ENV var1=value1 var2=value2 ...
注意:
通过ENV所定义的变量是可以传递到容器之中,但是,在创建容器的时候,如果手动指定了变量的值,那么这个值会覆盖掉镜像中原有的值
ENV示例:
ENV pkgname=nginx-1.14.0.tar.gz root=/data/mysql/mysql3306/data
10. RUN
作用:基于镜像构建容器时候要执行命令
阶段:第一阶段,也就是构建镜像的时候执行
格式:
RUN 命令
RUN示例:
RUN tar xf $root$pkgname
11. CMD
作用:定义容器启动以后要默认运行的程序,pid为1的程序
阶段:第二阶段,也就是将镜像构成成容器的时候执行
注意:可以在启动容器的时候用指定的命令替换掉镜像所要执行的命令
CMD指定容器启动是执行的命令,每个Dockerfile只能有一条CMD命令,如果指定了多条,只有最后一条会被执行。如果你在启动容器的时候也指定的命令,那么会覆盖Dockerfile构建的镜像里面的CMD命令
格式:
CMD <命令> 相当于执行的是/bin/sh -c 命令,也相当于执行exec来运行命令
CMD ["<命令>", "<参数>", "<参数>"]
CMD ["<参数>", "<参数>"] <<< 需要借助于ENTRYPOINT指令
CMD示例:
CMD mkdir /ken
12. ENTRYPOINT
作用:定义容器启动以后要默认运行的程序,pid为1的程序
注意:
在运行RUN的时候所执行的命令无法覆盖ENTRYPOINT中的命令
RUN 后面的命令会被以参数的方式追加到原本要执行的命令的末尾,而不是替换
基于一个镜像,在创建容器的时候,通过传递不同的参数实现创建不同的容器
每个 Dockerfile 中只能有一个 ENTRYPOINT,当指定多个时,只有最后一个起效
格式:
ENTRYPOINT ["执行命令","参数1","参数2"...]
ENTRYPOINT示例:
ENTRYPOINT [ "curl", "-s", "http://10.220.5.138" ]
13. ARG
作用:定义变量,这个变量是用在第一阶段(构建镜像——build)
格式:
ARG 变量名=变量值
ARG示例:
ARG name=ken
补充:Dockerfile中ENV 和 ARG的区别
在指定docker build 过程中传参数,要用ARG
在执行docker run的过程中传参数,要用ENV
ARG构建参数和 ENV 的效果一样,都是设置环境变量。所不同的是, ARG 所设置的构建环境的
环境变量,在将来容器运行时是不会存在这些环境变量的
14. USER
作用:指定运行容器时的用户名和UID,后续的RUN指令也会使用这里指定的用户
该用户必须存在于容器的用户空间中(容器的文件系统的中的/etc/passwd中)
格式:
USER <UID>|<USERNAME>
USER示例:
user ken
15. HEALTHCHECK
作用:docker daemon检查docker容器是否正常,如果异常会将该容器stop
将容器stop的条件
1)主进程停止了
2)主进程工作在了后台
格式:
HEALTHCHECK [options] CMD
options
--interval=#s|m 指定健康检查的时间间隔(例如:30s,30m)
--timeout=#s|m 指定等待响应的超时时间
--start-period=#s|m 指定容器启动多久以后才可以做监控检查
--retries=# 指定重试次数
返回值
0:success
1:unhealth
HEALTHCHECK示例:
HEALTHCHECK --interval=5m --timeout=1s --retries=3 CMD curl http://10.220.5.138/ken.html || exit 1
16. SHELL
可以用来指定系统中默认的shell类型
格式:
SHELL ["/bin/sh", "-c"] (linux系统中)
SHELL示例:
SHELL ["/bin/sh","-c"]
17. STOPSIGNAL
向容器中pid为1的进程发送一个信号,通过这个信号来关闭这个主进程
默认是15信号
格式:
STOPSIGNAL 数值
STOPSIGNAL示例:
STOPSIGNAL 9
18. ONBULID
作用:定义一个触发器,指定的命令在构建镜像时并不执行,用来实现当基于这个这个镜像做新镜像的时候要执行的命令
格式:
ONBUILD 其他指令
ONBUILD示例:
ONBUILD COPY ken /app/
Dokcerfile完整演示创建nginx镜像
根据上面各个指令的介绍,我就直接用上面写的dockerfile进行演示。整个dockerifle内容如下。
[root@ken ~]# vim /ken/Dockerfile FROM docker.io/nginx:latest LABEL author "ken" COPY ./passwd /data/ WORKDIR /pack/nginx/ ENV pkgname=nginx-1.14.0.tar.gz root=/data/mysql/mysql3306/data/ COPY nginx-1.14.0.tar.gz $root VOLUME $root EXPOSE 80/tcp RUN tar xf $root$pkgname CMD nginx -g "daemon off;"
第一步:构建镜像
build:是指根据dockerfile制作镜像
-t:指定一个tag标签
.:表示上下文。你也可以理解为dockfile所在的目录,但是并不是准确的
如果下方出现successfully就表示镜像已经构建成功了
[root@ken ken]# docker build -t ken:v1-0 . Sending build context to Docker daemon 1.021 MB Step 1/10 : FROM docker.io/nginx:latest ---> 568c4670fa80 Step 2/10 : LABEL author "ken" ---> Using cache ---> 80e4e5846fd9 Step 3/10 : COPY ./passwd /data/ ---> Using cache ---> 685a7ceb74b3 Step 4/10 : WORKDIR /pack/nginx/ ---> Using cache ---> 0fc65f8c36df Step 5/10 : ENV pkgname nginx-1.14.0.tar.gz root /data/mysql/mysql3306/data/ ---> Using cache ---> 3f6038473472 Step 6/10 : COPY nginx-1.14.0.tar.gz $root ---> Using cache ---> 0cbff6223d5b Step 7/10 : VOLUME $root ---> Using cache ---> b74ac1c36c31 Step 8/10 : EXPOSE 80/tcp ---> Using cache ---> 6863a87a61a2 Step 9/10 : RUN tar xf $root$pkgname ---> Using cache ---> b32ac636a389 Step 10/10 : CMD nginx -g "daemon off;" ---> Running in 02308825301d ---> 4a91d70a57eb Removing intermediate container 02308825301d Successfully built 4a91d70a57eb
第二步:查看镜像
可以发现构建的名为ken标签为v1-0的镜像已经存在了
[root@ken ken]# docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE ken v1-0 4a91d70a57eb 21 minutes ago 116 MB
第三步:启动容器
可以发现基于我们刚才的创建的镜像的容器已经顺利跑起来了。
[root@ken ken]# docker run -d --name ken3 -d ken:v1-0 11f492a28b943e619b0ed5d6b19f212f1c9cc47f9bdbe132845e7a7129e5b419 [root@ken ken]# docker container ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 11f492a28b94 ken:v1-0 "/bin/sh -c 'nginx..." 16 seconds ago Up 11 seconds 80/tcp ken3
第四步:登录容器
可以发现我们这个启动的容器里面已经有我们指定的工作目录
复制过来的passwd文件
已经下载并传送到/data下了
[root@ken ken]# docker exec -it ken3 bash root@11f492a28b94:/pack/nginx# ls /data/ mysql/ passwd root@11f492a28b94:/pack/nginx# ls /data/ mysql/ passwd oot@11f492a28b94:/pack/nginx# ls /data/mysql/mysql3306/data/nginx-1.14.0.tar.gz /data/mysql/mysql3306/data/nginx-1.14.0.tar.gz
这样基于dockerfile自主创建镜像的过程就演示完了,快去自己制作一个属于自己的镜像吧。