参考官方文档:https://docs.docker.com/engine/reference/builder/
Dockerfile常用指令
指令 | 说明 |
---|---|
from | 基础镜像,当前镜像基于(依赖)哪个镜像 |
maintainer | 镜像的维护者和邮箱 |
run | 镜像构建时需要执行的命令 |
workdir | 镜像的工作目录 |
expose | 对外暴露的端口 |
env | 设置环境变量 |
add | 将宿主机的文件复制到镜像中,并自动解压 |
copy | 将宿主机的文件复制到镜像中 |
volume | 容器数据卷,用于数据的保存和持久化 |
cmd | 运行命令,多条CMD只会执行最后一条,参数会被RUN的参数覆盖 |
entrypoint | 运行命令,会把RUN的参数追加到后面 |
volume | 容器数据卷,用于数据的保存和持久化 |
cmd | 运行命令,多条CMD只会执行最后一条,参数会被RUN的参数覆盖 |
entrypoint | 运行命令,会把RUN的参数追加到后面 |
Dockerfile指令的使用
FROM
shell
FROM [--platform=<platform>] <image> [AS <name>]
FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]
FROM
指令初始化了一个新的构建阶段,并指定了这个构建阶段的基础镜像,每一个Dockerfile都要以FROM
指令开始。
例如:
shell
FROM centos:7
MAINTAINER
MAINTAINER
用来指定Dockerfile的作者,官方已不推荐使用,推荐使用LABEL
。
shell
maintainer morris131<morris131@163.com>
LABEL
shell
LABEL <key>=<value> <key>=<value> <key>=<value> ...
LABEL
用来为镜像添加元数据,是一个key-value
结构。
例如:
shell
LABEL "com.example.vendor"="ACME Incorporated"
LABEL com.example.label-with-value="foo"
LABEL version="1.0"
LABEL description="This text illustrates \
that label-values can span multiple lines."
一个镜像可以指定多个label,可以指定在一行指定多个label。
shell
LABEL multi.label1="value1" multi.label2="value2" other="value3"
LABEL multi.label1="value1" \
multi.label2="value2" \
other="value3"
父镜像的label会被继承。
可以使用docker image inspect
来查看镜像的label。
shell
$ docker image inspect --format='{{json .Config.Labels}}' centos:7
{"org.label-schema.build-date":"20201113","org.label-schema.license":"GPLv2","org.label-schema.name":"CentOS Base Image","org.label-schema.schema-version":"1.0","org.label-schema.vendor":"CentOS","org.opencontainers.image.created":"2020-11-13 00:00:00+00:00","org.opencontainers.image.licenses":"GPL-2.0-only","org.opencontainers.image.title":"CentOS Base Image","org.opencontainers.image.vendor":"CentOS"}
RUN
shell
RUN <command>
RUN ["executable", "param1", "param2"]
RUN
主要用于在镜像里执行指令,比如安装软件,下载文件等。在Linux下默认的shell是/bin/sh -c
,在windows下默认的shell是cmd /S /C
。
例如:
shell
run yum install -y wget gcc gcc-c++ automake autoconf libtool make
run wget https://download.redis.io/releases/redis-6.2.5.tar.gz
run tar xzf redis-6.2.5.tar.gz && cd redis-6.2.5 && make
WORKDIR
shell
WORKDIR /path/to/workdir
WORKDIR
指定运行RUN
, CMD
, ENTRYPOINT
, COPY
和ADD
等指令的工作目录。
WORKDIR
可以使用多次,如果指定的是一个相对路径,那么会自动拼接上前面的WORKDIR
指令指定的路径。
shell
WORKDIR /a
WORKDIR b
WORKDIR c
最终的工作路径将变为/a/b/c
。
COPY
shell
COPY [--chown=<user>:<group>] [--chmod=<perms>] <src>... <dest>
COPY [--chown=<user>:<group>] [--chmod=<perms>] ["<src>",... "<dest>"]
COPY
指令可以把本地的文件复制到镜像里,如果目标目录不存在,则会自动创建。
例如:
shell
COPY /foo /bar
COPY hom* /mydir/
COPY hom?.txt /mydir/
COPY test.txt relativeDir/
ADD
shell
ADD [--chown=<user>:<group>] [--chmod=<perms>] [--checksum=<checksum>] <src>... <dest>
ADD [--chown=<user>:<group>] [--chmod=<perms>] ["<src>",... "<dest>"]
ADD
与COPY
的功能类似,唯一的区别在于如果复制的是一个gzip等压缩文件时,ADD会帮助我们自动去解压缩文件。
因此在COPY
和ADD
指令中选择的时候,可以遵循这样的原则,所有的文件复制均使用COPY
指令,仅在需要自动解压缩的场合使用ADD
。
如果要在容器内部复制文件,可以使用run copy xx oo
。
ARG
shell
ARG <name>[=<default value>]
ARG
用于定义一个变量,可以在Dockerfile中使用,可以在构建时指定构建参数来覆盖这个变量的值。
shell
FROM busybox
ARG username
USER $username
在构建时修改这个变量:
shell
$ docker build --build-arg username=what_user .
ENV
shell
ENV <key>=<value> ...
ENV
设置的变量不仅可可以在镜像的构建阶段使用,还会出现在容器中的环境变量里。
例如:
shell
ENV MY_NAME="John Doe"
ENV MY_DOG=Rex\ The\ Dog
ENV MY_CAT=fluffy
ENV设置的变量可以通过docker image inspect
命令来查看:
shell
$ docker image inspect --format='{{json .Config.Env}}' openjdk:8-jre-alpine
["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/jvm/java-1.8-openjdk/jre/bin:/usr/lib/jvm/java-1.8-openjdk/bin","LANG=C.UTF-8","JAVA_HOME=/usr/lib/jvm/java-1.8-openjdk/jre","JAVA_VERSION=8u212","JAVA_ALPINE_VERSION=8.212.04-r0"]
可以在运行时使用run --env <key>=<value>
来改变环境变量的值。
CMD
shell
CMD ["executable","param1","param2"] (exec form, this is the preferred form)
CMD ["param1","param2"] (as default parameters to ENTRYPOINT)
CMD command param1 param2 (shell form)
CMD
可以用来设置容器启动时默认会执行的命令。
如果docker container run
启动容器时指定了其它命令,则CMD命令会被忽略。
如果定义了多个CMD,只有最后一个会被执行。
例如:
shell
CMD echo "This is a test." | wc -
CMD ["/usr/bin/wc","--help"]
默认进入到shell是因为在ubuntu的基础镜像里有定义CMD
shell
$ docker container run -it centos:7
[root@ea4a8eb97765 /]# exit
exit
$ docker history centos:7
IMAGE CREATED CREATED BY SIZE COMMENT
eeb6ee3f44bd 24 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 24 months ago /bin/sh -c #(nop) LABEL org.label-schema.sc... 0B
<missing> 24 months ago /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4... 204MB
ENTRYPOINT
shell
ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2
ENTRYPOINT
也可以设置容器启动时要执行的命令,但是和CMD是有区别的。
CMD
设置的命令,可以在docker container run
时传入其它命令,覆盖掉CMD
的命令,但是ENTRYPOINT
所设置的命令是一定会被执行的。
ENTRYPOINT
和CMD
可以联合使用,ENTRYPOINT
设置执行的命令,CMD传递参数。
CMD测试
cmd.Dockerfile
shell
FROM centos:7
CMD ["echo", "hello cmd"]
把上面的Dockerfile构建成一个叫cmd
的镜象:
shell
$ docker build -f cmd.Dockerfile -t cmd .
Sending build context to Docker daemon 327.2MB
Step 1/2 : FROM centos:7
---> eeb6ee3f44bd
Step 2/2 : CMD ["echo", "hello cmd"]
---> Running in 4bddfcb6153c
Removing intermediate container 4bddfcb6153c
---> c92160d2a1d6
Successfully built c92160d2a1d6
Successfully tagged cmd:latest
运行容器时如果不指定运行时的命令,则会默认执行CMD所定义的命令,打印出hello cmd
shell
$ docker run --rm -it cmd
hello cmd
如果运行容器的时候指定命令,则该命令会覆盖掉CMD的命令,如:
shell
$ docker run --rm -it cmd echo hello docker
hello docker
ENTRYPOINT测试
entrypoint.Dockerfile
shell
FROM centos:7
ENTRYPOINT ["echo", "hello entrypoint"]
把上面的Dockerfile构建成一个叫entrypoint
的镜象:
shell
$ docker build -f entrypoint.Dockerfile -t entrypoint .
Sending build context to Docker daemon 327.2MB
Step 1/2 : FROM centos:7
---> eeb6ee3f44bd
Step 2/2 : ENTRYPOINT ["echo", "hello entrypoint"]
---> Running in b74fa51c63a8
Removing intermediate container b74fa51c63a8
---> b3f6c3c624e0
Successfully built b3f6c3c624e0
Successfully tagged entrypoint:latest
运行容器时如果不指定运行时的命令,则会默认执行ENTRYPOINT所定义的命令,打印出hello entrypoint
shell
$ docker run --rm -it entrypoint
hello entrypoint
但是容器里ENTRYPOINT所定义的命令则无法覆盖,一定会执行,如:
shell
$ docker run --rm -it entrypoint echo hello docker
hello entrypoint echo hello docker
实战构建redis
shell
$ cat redis.dockerfile
from centos
maintainer morris131<morris131@163.com>
env WORK_DIR /usr/local
workdir $WORK_DIR
run yum install -y wget gcc gcc-c++ automake autoconf libtool make
run wget https://download.redis.io/releases/redis-6.2.5.tar.gz
run tar xzf redis-6.2.5.tar.gz && cd redis-6.2.5 && make
expose 6379
env REDIS_HOME $WORK_DIR/redis-6.2.5
env PATH $PATH:$REDIS_HOME/src
entrypoint ["redis-server"]