【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, 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"]
相关推荐
人生百态,人生如梦3 分钟前
Ubuntu在低版本下使用ccswitch+claudecode(CCSwitch+Docker+Claude)连调教程
linux·ubuntu·docker·claudecode·ccswitch
程序员老赵8 分钟前
Docker 部署 OpenViking:轻松搭建 AI Agent 上下文数据库平台
docker·开源·agent
吴声子夜歌1 小时前
Docker入门与实战——高级镜像构建
docker
坐看风云变幻2 小时前
Betaflight 开发环境搭建保姆级教程(Ubuntu / Windows+WSL / Docker 三方案 + 官方网址大全)
windows·ubuntu·docker·无人机·飞控·betaflight
零基础1232 小时前
Docker 部署实战:从入门到精通
docker·容器
Lvan的前端笔记2 小时前
docker:基于docker的前端部署方案
前端·docker·状态模式
承渊政道2 小时前
自建服务越来越多怎么管理?Docker部署Flare,搭一个自己的数字入口
运维·docker·容器·内网穿透·cpolar·nas·flare
龙腾-虎跃3 小时前
Docker 一键启动服务合集:Redis、MySQL、Kafka、MinIO、Prometheus 等(网盘转存防失效)
redis·mysql·docker·kafka·prometheus·小龙虾·miniio
芷栀夏3 小时前
极空间部署Photopea:Docker运行、网页修图与多设备使用
运维·docker·容器
JeJe同学13 小时前
Docker镜像导入、容器启动
linux·运维·docker