【Docker】Dockerfile常用指令

参考官方文档: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, COPYADD等指令的工作目录。

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>"]

ADDCOPY的功能类似,唯一的区别在于如果复制的是一个gzip等压缩文件时,ADD会帮助我们自动去解压缩文件。

因此在COPYADD指令中选择的时候,可以遵循这样的原则,所有的文件复制均使用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所设置的命令是一定会被执行的。

ENTRYPOINTCMD可以联合使用,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"]
相关推荐
南猿北者6 小时前
docker Network(网络)
网络·docker·容器
yaosheng_VALVE7 小时前
稀硫酸介质中 V 型球阀的材质选择与选型要点-耀圣
运维·spring cloud·自动化·intellij-idea·材质·1024程序员节
sam-1237 小时前
k8s上部署redis高可用集群
redis·docker·k8s
Fanstay9858 小时前
在Linux中使用Nginx和Docker进行项目部署
linux·nginx·docker
death bell9 小时前
Docker基础概念
运维·docker·容器
网安_秋刀鱼10 小时前
java组件安全
web安全·网络安全·1024程序员节
earthzhang202110 小时前
《深入浅出HTTPS》读书笔记(7):安全的密码学Hash算法
网络·网络协议·http·https·1024程序员节
天幕繁星11 小时前
docker desktop es windows解决vm.max_map_count [65530] is too low 问题
windows·elasticsearch·docker·docker desktop
想学习java初学者12 小时前
Docker Compose部署Kafka(非Zookeeper)
docker·容器·kafka
程序员小海绵【vincewm】12 小时前
【设计模式】结合Tomcat源码,分析外观模式/门面模式的特性和应用场景
设计模式·tomcat·源码·外观模式·1024程序员节·门面模式