【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"]
相关推荐
桂花很香,旭很美14 分钟前
Qanything-docker-compose yaml文件(内含GPU 配置,备用学习)
docker
人生匆匆1 小时前
docker安装elasticesarch-head
运维·docker·jenkins
洛阳泰山2 小时前
Docker 镜像国内加速下载教程
docker·容器
盏灯3 小时前
🚢🚢🚢云服务器Docker快速通关——从部署到实战
docker
shark_西瓜甜4 小时前
shark云原生-日志体系-ECK
elasticsearch·docker·云原生
林鸿群5 小时前
Docker运行MSSQL2022
运维·docker·容器
A-刘晨阳5 小时前
ELFK 8.12.2 部署 -- docker部署方式⚽
linux·运维·elk·docker·容器
清华kenny5 小时前
docker部署redis/mongodb/
redis·mongodb·docker
繁星日月6 小时前
利用docker搭建漏洞环境,使用SSRF+Redis写入centos以及ubuntu的公钥,实现免密登录
redis·安全·ubuntu·docker·容器·centos·渗透
Roc-xb9 小时前
Failed to get D-Bus connection: Operation not permitted
docker·wsl·centos7