Dockerfile详解

FROM

  1. 指定基础镜像,必须是第一条指令

  2. 如果没有基础镜像,则以 FROM scratch 开头

  3. 这条指令写入的东西为镜像首层

写法FROM <images>:<tag>

USER

  1. 设置容器启动用户,可以是用户名或UID

  2. 如果容器以daemon用户运行,那么RUN, CMD, ENTRYPOINT 都会以这个用户运行

语法

USER daemo
USER UID

ENV 指令

  1. 设置容器环境变量

语法

ENV <key> <value>
ENV <key>=<value> ... // 可以设置多个

WORKDIR

  1. 设置工作目录,对 RUN, CMD, ENTRYPOINT, COPY, ADD 生效。

  2. 如果不存在则会创建, 也可以设置多次

  3. 可以指定绝对路径和相对路径,这里的路径是指容器中的路径

  4. WORKDIR 会解析环境变量

  5. 可以理解为cd 命令

语法

WORKDIR /path/to/workdir
WORKDIR path
WORKDIR /$PATH

RUN

  1. RUN命令在容器的可写入层执行命令,并commit容器为新的镜像。

  2. 上一步RUN命令生成的镜像被接下来RUN使用,每次RUN命令都会重新生成一个新的镜像

  3. 可以通过链式输入命令以减少创建镜像层的数量

  4. 镜像层过多,会导致镜像过大

  5. 可以通过docker history 镜像名称 查看镜像层

  6. CMD 命令通常在文件最末尾处

写法RUN <command> 或者 RUN ["executable", "param1", "param2"]

第二种方式类似函数调用,在linux下,自动使用脚本解析器: /bin/sh -c ,windows下则是 cmd /S /C

为了减少镜像层数,可以使用链式命令 RUN command1&& command2 并且,可以使用 \反斜线 换行。

CMD

  1. CMD 命令用于指定启动容器时的命令

  2. 如果不指定CMD命令,则将使用基础镜像提供的默认命令

  3. 因为是启动命令,所以在创建容器时不会执行,只有启动容器时才会执行

  4. 也可以使用exec形式指定要执行的命令

  5. 可以使用docker run -ti centos:7 echo "hello world" 的方式,替换默认命令

  6. 写法:CMD ["echo", "hello"]

  7. 只可以写一条,如果写多条,只有最后一条有效

ENTRYPOINT

功能是启动时默认命令,与CMD类似

语法

ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2

相同点

  1. 只可以写一条,如果有多条,只有最后一条有效

  2. 容器启动时相同

不同点

  1. ENTRYPOINT 指令不会被运行时command覆盖

COPY

  1. COPY 指令从build上下文复制文件或者文件夹到容器文件系统

  2. 例如: COPY xxx.jar /data/jar/

ADD

  1. ADD指令和COPY指令类似,可以将文件复制到容器中

  2. 也可以从Internet下载文件并复制到容器中

  3. 并且,ADD命令可以自动解压压缩文件

  4. 通常使用COPY指令,除非明确需要ADD指令

ADD test relativeDir/
ADD test /relativeDir
ADD http://example.com/foobar /

VOLUME

  1. 可实现挂载

  2. 容器使用的是AUFS,这种文件系统不能持久化数据,当容器关闭后,所有的更改都会丢失

  3. 数据资源推荐挂载

语法

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

  1. 设置变量命令

  2. ARG命令定义一个变量,在docker build 使用Dockerfile构建镜像时,使用 --build-arg <varname>=<value> 来指定变量值

  3. 可以给变量设置默认值

  4. 如果用户在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

  1. 只对当前镜像的子镜像生效

比如当前镜像为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 镜像名称:版本 . 即可构建镜像

镜像构建缓存

如果新的构建版本中,某些指令与之前的版本一致,则会使用缓存。

造成的问题

  1. 如果是yum update -y 命令,则不会执行,导致yum仓库源不是最新的

解决办法

  1. 保证命令前后不一致,可以使用链式命令

  2. 使用 –no-cache=truedocker build -t centos . --no-cache=true

上传镜像至 DockerHub

  1. docker login

  2. 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应用,依次经过三个阶段:

  1. git clone 拉取代码

  2. mvn clean package 打包

  3. 放入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

最后更新于