Dockerfile详解
FROM
指定基础镜像,必须是第一条指令
如果没有基础镜像,则以
FROM scratch
开头这条指令写入的东西为镜像首层
写法: FROM <images>:<tag>
USER
设置容器启动用户,可以是用户名或UID
如果容器以daemon用户运行,那么
RUN
,CMD
,ENTRYPOINT
都会以这个用户运行
语法:
USER daemo
USER UID
ENV 指令
设置容器环境变量
语法:
ENV <key> <value>
ENV <key>=<value> ... // 可以设置多个
WORKDIR
设置工作目录,对
RUN
,CMD
,ENTRYPOINT
,COPY
,ADD
生效。如果不存在则会创建, 也可以设置多次
可以指定绝对路径和相对路径,这里的路径是指容器中的路径
WORKDIR
会解析环境变量可以理解为cd 命令
语法:
WORKDIR /path/to/workdir
WORKDIR path
WORKDIR /$PATH
RUN
RUN命令在容器的可写入层执行命令,并commit容器为新的镜像。
上一步RUN命令生成的镜像被接下来RUN使用,每次RUN命令都会重新生成一个新的镜像
可以通过链式输入命令以减少创建镜像层的数量
镜像层过多,会导致镜像过大
可以通过
docker history 镜像名称
查看镜像层CMD 命令通常在文件最末尾处
写法: RUN <command>
或者 RUN ["executable", "param1", "param2"]
第二种方式类似函数调用,在linux下,自动使用脚本解析器: /bin/sh -c
,windows下则是 cmd /S /C
为了减少镜像层数,可以使用链式命令 RUN command1&& command2
并且,可以使用 \反斜线
换行。
CMD
CMD 命令用于指定启动容器时的命令
如果不指定CMD命令,则将使用基础镜像提供的默认命令
因为是启动命令,所以在创建容器时不会执行,只有启动容器时才会执行
也可以使用exec形式指定要执行的命令
可以使用
docker run -ti centos:7 echo "hello world"
的方式,替换默认命令写法:
CMD ["echo", "hello"]
只可以写一条,如果写多条,只有最后一条有效
ENTRYPOINT
功能是启动时默认命令,与CMD类似
语法:
ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2
相同点:
只可以写一条,如果有多条,只有最后一条有效
容器启动时相同
不同点:
ENTRYPOINT 指令不会被运行时command覆盖
COPY
COPY 指令从build上下文复制文件或者文件夹到容器文件系统
例如:
COPY xxx.jar /data/jar/
ADD
ADD指令和COPY指令类似,可以将文件复制到容器中
也可以从Internet下载文件并复制到容器中
并且,ADD命令可以自动解压压缩文件
通常使用COPY指令,除非明确需要ADD指令
ADD test relativeDir/
ADD test /relativeDir
ADD http://example.com/foobar /
VOLUME
可实现挂载
容器使用的是AUFS,这种文件系统不能持久化数据,当容器关闭后,所有的更改都会丢失
数据资源推荐挂载
语法:
VOLUME ["/data"]
VOLUME /var/log
VOLUME /var/log /var/db
LABEL
LABEL 指令为镜像指定标签, 一个镜像可以拥有多个标签
语法:
LABEL <key>=<value> <key>=<value>
或
LABEL <key>=<value>
LABEL <key>=<value>
可以使用 反斜杠换行,或者多个LABEL 标签
MAINTAINER
指定作者:
MAINTAINER <name>
ARG
设置变量命令
ARG命令定义一个变量,在docker build 使用Dockerfile构建镜像时,使用
--build-arg <varname>=<value>
来指定变量值可以给变量设置默认值
如果用户在build镜像时指定了一个参数没有定义在Dockerfile中,那么将有一个Warning
[Warning] One or more build-args [foo] were not consumed.
语法:
FROM busybox
ARG user1=someuser
ARG buildno # 给默认值
HEALTHCHECK
语法:
# 在容器内部运行一个命令进行健康检查
HEALTHCHECK [OPTIONS] CMD command
# 在基础镜像中取消健康检查命令
HEALTHCHECK NONE
OPTIONS 支持如下三个选项:
--interval=DURATION 两次检查默认的时间间隔为30秒
--timeout=DURATION 健康检查命令运行超时时长,默认30秒
--retries=N 当连续失败指定次数后,则容器被认为是不健康的,状态为unhealthy,默认次数是3
CMD命令的返回值,决定了本次健康检查是否成功:
0: success - 表示容器是健康的
1: unhealthy - 表示容器已经不能工作了
2: reserved - 保留值
比如:
HEALTHCHECK --interval=5m --timeout=3s \CMD curl -f http://localhost/ || exit 1
HEALTHCHECK 指令只可以出现一次,如果出现多次,最后一个生效。
ONBUILD
只对当前镜像的子镜像生效
比如当前镜像为A,在Dockerfile种添加: ONBUILD RUN ls -al
这个 ls -al
命令不会在A镜像构建或启动的时候执行
此时有一个镜像B是基于A镜像构建的,那么这个ls -al 命令会在B镜像构建的时候被执行。
语法:
ONBUILD [INSTRUCTION]
STOPSIGNAL 指令
语法:
STOPSIGNAL signalSTOPSIGNAL
命令是的作用是当容器推出时给系统发送什么样的指令
使用Dockerfile构建image
cd 到 Dockerfile 文件所在路径执行 docker build -t 镜像名称:版本 .
即可构建镜像
镜像构建缓存

如果新的构建版本中,某些指令与之前的版本一致,则会使用缓存。
造成的问题:
如果是
yum update -y
命令,则不会执行,导致yum仓库源不是最新的
解决办法:
保证命令前后不一致,可以使用链式命令
使用 –no-cache=true
docker build -t centos . --no-cache=true
上传镜像至 DockerHub
docker login
docker push [OPTIONS] NAME[:TAG]
构建多CPU架构image
创建以下dockerfile:
FROM alpine:latest
LABEL maintainer="yangsx.yangsx95@qq.com"
RUN apk update && \
apk add git curl
安装buildx:
在mac与win的docker-desktop自带buildx,而linux需要安装:https://github.com/docker/buildx
创建并使用一个新的builder(默认builder可构建的cpu架构类型少):
$ docker buildx create --use --name mybuilder
mybuilder
查看所有的builder列表:
$ docker buildx ls
NAME/NODE DRIVER/ENDPOINT STATUS PLATFORMS
default * docker
default default running linux/amd64, linux/arm64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
查看当前使用的builder:
$ docker buildx inspect --bootstrap
docker buildx inspect --bootstrap
Name: mybuilder
Driver: docker-container
Nodes:
Name: mybuilder0
Endpoint: unix:///var/run/docker.sock
Status: running
Platforms: linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
使用buildx构建多cpu架构的镜像:
# --platform 指定支持的cpu架构
docker buildx build --push --platform linux/arm/v7,linux/arm64/v8,linux/amd64 -t <image_name> .
=>
docker buildx build --push --platform linux/arm/v7,linux/arm64/v8,linux/amd64 -t yangsx95/gitclient .
**成果:**https://hub.docker.com/repository/docker/yangsx95/gitclient
多阶段构建
可以使用Dockerfile拉取环境镜像,分阶段构建最终镜像。比如一个java应用,依次经过三个阶段:
git clone
拉取代码mvn clean package
打包放入tomcat容器
FROM yangsx95/gitclient:latest as cloner
MAINTAINER "yangsx.yangsx95@qq.com"
WORKDIR /opt
# 拉取代码
RUN git clone https://github.com/lizhenliang/tomcat-java-demo.git
FROM maven:3.8-openjdk-8 as builder
MAINTAINER "yangsx.yangsx95@qq.com"
WORKDIR /opt
# 将cloner阶段的opt/tomcat-java-demo这个文件拷贝到当前阶段的/opt/路径下
COPY --from=cloner /opt/tomcat-java-demo/ /opt/
# 添加阿里云maven镜像
RUN echo '<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd"><localRepository>/usr/share/maven/ref/repository</localRepository><mirrors><mirror><id>aliyunmaven</id><mirrorOf>*</mirrorOf><name>阿里云公共仓库</name><url>https://maven.aliyun.com/repository/public</url></mirror></mirrors></settings>' > /opt/settings.xml
# 执行构建
RUN mvn clean package --settings=/opt/settings.xml -Dmaven.test.skip=true
FROM tomcat:8-jdk8 as runner
MAINTAINER "yangsx.yangsx95@qq.com"
WORKDIR /usr/local/tomcat/webapps/
COPY --from=cloner /opt/ /opt/test
COPY --from=builder /opt/target/*.war /usr/local/tomcat/webapps/ROOT.war
--from可以指定名称,也可以指定索引,比如引用第一个阶段的结果,使用
--from=0
将上述内容保存到Dockerfile
文件中,使用下面的命令构建镜像:
docker build -t yangsx95/hello-girl .
测试:
docker run -p 8080:8080 --rm yangsx95/hello-girl
最后更新于
这有帮助吗?