【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"]
相关推荐
意疏8 小时前
【Linux 篇】Docker 的容器之海与镜像之岛:于 Linux 系统内探索容器化的奇妙航行
linux·docker
墨鸦_Cormorant8 小时前
使用docker快速部署Nginx、Redis、MySQL、Tomcat以及制作镜像
redis·nginx·docker
Code_Artist8 小时前
Docker镜像加速解决方案:配置HTTP代理,让Docker学会科学上网!
docker·云原生·容器
惜.己9 小时前
Jmeter中的断言(二)
测试工具·jmeter·1024程序员节
wanmei0029 小时前
Dockerfile复制目录进入镜像里
docker
inter_peng9 小时前
[Docker-显示所有容器IP] 显示docker-compose.yml中所有容器IP的方法
tcp/ip·docker·eureka
Linux运维日记10 小时前
k8s1.31版本最新版本集群使用容器镜像仓库Harbor
linux·docker·云原生·容器·kubernetes
一名路过的小码农11 小时前
ceph 18.2.4二次开发,docker镜像制作
ceph·docker·容器
xiangshangdemayi14 小时前
Windows环境GeoServer打包Docker极速入门
windows·docker·容器·geoserver·打包·数据挂载
程序员JerrySUN15 小时前
熟悉的 Docker,陌生的 Podman
linux·docker·容器·系统架构·podman