Dockerfile 可以用来创建一个镜像,允许在该文件中调用一些命令行中的命令,这样可以利用一个基础镜像,然后附加一些基础操作,最后直接自动生成新镜像。
简介
用于表示 docker 镜像生成过程的文件,如果在某个目录下有名为 Dockfile 的文件,那么通过 docker build --tag name:tag .
命令生成镜像,其中 name
是镜像名称,而 tag
就是镜像的版本或者是标签号,默认是 lastest
。
当在某个目录下运行 docker build
命令时,当前目录就是 build context
,也可以在最后一个参数指定 context
目录,正常应该存在一个 Dockerfile
文件,当然,也可以通过 -f
参数指定。
从 Docker 1.10 起,在执行 COPY
、ADD
和 RUN
语句时,会在镜像中添加新层。
基本指令
基本指令有十三个。
FROM <image>
指定构建镜像的基础源镜像
FROM centos:latest # 指定基础镜像
MAINTAINER <name> <email>
镜像的创建者和邮箱
ENV <key>=<value>
设置环境变量
WORKDIR <dir>
配置容器中后续的工作目录
RUN <command> <param1> ... <paramN>
执行命令并创建新的镜像层,通常用于安装软件包
RUN apt-get update && apt-get install -y git
COPY <src> <dst>
用于从本地将文件复制到容器镜像中
支持Shell通配符,例如* ?等
COPY check* test?.sh /opt/scripts/
与上面命令等效,适用于路径中包含空格等特殊字符
COPY ["check*", "test?.sh", "/opt/scripts/"]
可以配合WORKDIR使用,这样相当于容器中的相对目录
WORKDIR /opt/scripts
COPY check.sh .
上述复制的是文件,这里复制目录
COPY scripts/ /opt
ADD <src> <dst>
支持上述的COPY方式,同时还支持一些常用功能,可以将ADD理解为COPY的超集
将压缩文件解压并添加到镜像中
ADD foobar.tar.gz /opt
下载远端的文件到镜像,不过不建议,会导致更多镜像层,建议通过wget/curl实现
ADD http://foobar.com/big.tar.gz /opt
RUN tar -xf /opt/big.tar.gz -C /opt/data
CMD <command> <param1> ... <paramN>
容器启动后执行的默认命令,可以在通过run命令启动的时候覆盖
CMD executable param1 param2 # Shell表示法,实际调用的是/bin/sh -c "executable param1 param2"
CMD ["executable", "param1", "param2"] # Exec表示法,直接调用命令
ENTRYPOINT <command> <param1> ... <paramN>
与CMD类似,但不会被run后的启动参数覆盖,如果需要覆盖则要添加--entrypoint参数
在通过 ADD
和 COPY
复制文件时,必须要在上述的上下文中。
示例
这里通过 BusyBox 中的 nc 命令作为一个 TCP 的 echo 服务器,通过本地的 3030
端口访问,容器内部监听 2000
。
创建一个目录,并添加 Dockerfile
文件,对应文件内容如下。
FROM busybox
CMD ["nc", "-lk", "-p", "2000"]
然后可以通过如下方式进行测试。
----- 构建镜像,在 Dockerfile 文件所在目录下执行
# docker build -t foobar .
# docker images
---- 指定使用Dockerfile,其中上下文在context目录(默认是当前目录)
podman build --no-cache -t hello:v1 -f Dockerfile context
----- 启动新创建的镜像后台运行,然后本地建立连接
# docker run -d -p 3030:2000 foobar
# nc 127.1 3030
----- 查看容器的标准输出
# docker logs -f e47ac47bd9af
----- 连接到容器,后者需要确保在执行sh命令
# docker exec -it e47ac47bd9af /bin/bash
# docker attach e47ac47bd9af
常见问题
ENTRYPOINT VS. CMD
都是在启动容器之后执行一个命令,多数情况下二选一即可,不过也可以相互配合,完成一些更加复杂的功能。
在运行容器时,可以通过参数覆盖原有的参数,例如。
----- 覆盖CMD
docker run demo hostname
----- 覆盖ENTRYPOINT
docker run --entrypoint hostname demo
可以看到 CMD
是最容易被直接覆盖的,如果想让用户只执行某个脚本,例如一个 Python 脚本,就可以通过 ENTRYPOINT
指定。
如果两者都指定,那么 CMD
将作为参数添加到 ENTRYPOINT
之后,那么此时建议两者都用 exec 模式。
参考
- Dockerfile reference 详细可以参考官方的文档。