• Docker学习笔记(三):Dockerfile及多步骤构建镜像


    Dockerfile指令

    官方文档地址:https://docs.docker.com/engine/reference/builder/
    Dockerfile是一个文本格式的配置文件,其内容包含众多指令,用户可以使用它快速的创建自定义镜像。

    部分指令列表

    指令 作用 备注
    FROM 指定基础镜像 任何Dockerfile中的第一条指令都必须是FROM
    一个文件中可以存在多个FROM指令。
    LABEL 为镜像添加元数据标签信息。
    ARG 定义创建镜像过程中使用的变量,编译成功后不存在。 在运行docker build时,指定--builder-arg为变量赋值。
    ENV 设置环境变量 在镜像启动时也会存在。
    docker run --env key=value 会覆盖同名变量
    WORKDIR 指定工作目录 可以使用多个,建议使用绝对路径。
    VOLUME 创建数据卷挂载点 例如VOLUME ["/data/a","/data/b"]
    EXPOSE 声明镜像内服务监听的端口 只起声明作用,不会自动完成映射。
    USER 指定运行容器时的用户名或ID 后续RUN指令也会以这个用户身份运行。
    STOPSIGNAL 指定所创建镜像启动的容器接收退出的信号值

    COPY/ADD

    COPY src dst / ADD src dst
    其相同点是:作用都是复制内容到镜像中;dst不存在时会创建;路径支持正则。
    不同点在于:

    • ADD的src可以是相对于Dockerfile的相对路径;也可以是一个URL;还可以是一个tar文件(自动解压)。
    • COPY的src只能是文件或者目录。

    除了目的明确是要将一个URL或者tar文件作为src的情况下,其他情况推荐使用COPY。

    CMD/ENTRYPOINT

    命令格式

    • exec方式: ["executable","param1","param2"](JSON数组,所以一定要是双引号)
    • shell方式: command param1 param2

    CMD与ENTRYPOINT两种方式都支持,但推荐使用exec方式。

    作用

    在任意一个Dockerfile下:

    • 只有最后一条CMD才会被执行。用来指定容器启动时默认执行的命令及参数。但是会被docker run命令行参数覆盖。
    • 只有最后一条ENTRYPOINT才会被执行。用来配置容器启动时的执行命令。并且会将docker run的命令行参数或者CMD的所有参数追加在ENTRYPOINT指令后作为参数。运行时可以被--entrypoint参数覆盖。

    伪代码

    finallyCommand = ""
    if exists(ENTRYPOINT) {
          finallyCommand = ENTRYPOINT
          if exists(dockerRunCommandParam){
                // 情景一
               finallyCommand += dockerRunCommandParam 
          }elseif exists(CMD) {
                // 情景二。除了CMD指令本身,包括后面JSON数组所有
               finallyCommand += CMDParams 
          }
          // 情景三
    }elseif exists(dockerRunCommandParam){
          // 情景四
          finallyCommand = dockerRunCommandParams 
    }elseif exists(CMD){
          // 情景五
          finallyCommand = CMD 
    }
    

    总结起来一句话:有ENTRYPOINT,CMD和docker run指定的命令都作为参数追加到ENTRYPOINT的参数后;没有ENTRYPOINT,docker run指定了命令就执行,否则执行CMD(如果有的话)。

    实操

    Dockerfile内容、构建镜像

    FROM alpine:latest
    ENTRYPOINT ["/bin/echo","entrypoint"]
    
    -> [feifei@ffmac.local] [~/work/docker] docker build -t test .
    
    // 情景三
    -> [feifei@ffmac.local] [~/work/docker] docker run --rm test
    entrypoint
    
    // 情景一
    -> [feifei@ffmac.local] [~/work/docker] docker run --rm test 12 34
    entrypoint 12 34
    

    Dockerfile添加CMD指令、构建镜像

    FROM alpine:latest
    ENTRYPOINT ["/bin/echo","entrypoint"]
    CMD ["/bin/echo","cmd"]
    
    -> [feifei@ffmac.local] [~/work/docker] docker build -t test .
    
    // 情景二:CMD中的 "/bin/echo" 没有被当做命令执行,而是与"cmd"一起成为了ENTRYPOINT的参数。
    -> [feifei@ffmac.local] [~/work/docker] docker run --rm test
    entrypoint /bin/echo cmd
    

    Dockerfile删除ENTRYPOINT指令、构建镜像

    FROM alpine:latest
    CMD ["/bin/echo","cmd"]
    
    -> [feifei@ffmac.local] [~/work/docker] docker build -t test .
    
    // 情景五
    -> [feifei@ffmac.local] [~/work/docker] docker run --rm test
    cmd
    
    // 情景四
    -> [feifei@ffmac.local] [~/work/docker] docker run --rm test echo 33
    33
    

    RUN

    exec方式:RUN ["executable","param1","param2"]
    shell方式:RUN command param1 param2
    每条RUN指令将在当前镜像基础上执行指令,并且提交为新的镜像层。当命令较长时可以使用来换行

    ONBUILD

    ONBUILD [INSTRUCTION]
    作为父镜像被使用时自动执行的命令。对孙子镜像无效。可用于自动编译,检查等。
    假如父镜像ParentImage的Dockerfile中有如下指令:

    ONBUILD RUN mkdir /root/test
    

    使用docker build基于ParentImage创建子镜像ChildImage的时候,会先执行ParentImage中的ONBUILD指令。等价于在ChildImage中添加了:

    RUN mkdir /root/test
    

    HEALTHCHECK

    健康检查
    HEALTHCHECK [OPTIONS] CMD command :根据执行命令返回值判断,0是成功,1是不健康。
    HEALTHCHECK NONE :禁止健康检查
    OPTIONS参数如下:

    • --interval=DURATION (default: 30s) 多长时间检查一次
    • --timeout=DURATION (default: 30s) 检查一次的超时时间
    • --start-period=DURATION (default: 0s) 开始阶段时长,此阶段内第一次成功之前的失败不计入retries。
    • --retries=N (default: 3) 确定最终失败的重试次数

    构建镜像

    docker build

    docker build [OPTIONS] PATH | URL | -
    该命令默认读取指定路径下的Dockerfile(也可使用 -f 指定),并将该路径下的所有数据作为上下文发送给Docker服务端。逐条执行指令,生成镜像。

    选择父镜像

    一般情况下都需要使用FROM来指定父镜像,所以父镜像会影响到新生成镜像的大小和功能。
    通常有两种镜像可作为父镜像:基础镜像和普通镜像(由第三方创建,基于基础镜像)。基础镜像一般是基于scratch或者Dockerfile中不存在FROM指令。

    多步骤构建

    对于编译型语言通常需要编译环境和运行环境两个镜像:

    • 编译环境镜像:包括完整的编译环境、依赖库等,体积较大。作用是将代码编译为二进制程序。
    • 运行环境镜像:运行二进制程序,而不需要与编译环境,体积比较小。

    app.go

    package main
    
    import "fmt"
    
    func main() {
    	fmt.Println("Hello World")
    }
    

    Dockerfile中使用两次FROM

    FROM golang:1.14-alpine as builder
    WORKDIR /go/src/test
    COPY app.go .
    RUN CGO_ENABLED=0 GOOS=linux go build -o app app.go
    
    FROM alpine:latest
    COPY --from=builder /go/src/test/app /root/  #此处 --from=builder 也可以改为 --from=0
    CMD ["/root/app"]
    

    构建、运行

    -> [feifei@ffmac.local] [~/work/docker] docker build -t hello .
    
    -> [feifei@ffmac.local] [~/work/docker] docker run --rm hello
    Hello World
    

    小技巧

    清理untagged镜像

    多阶段构建会生成编译环境镜像,也会将之前的同名镜像变为<none>:<none>,清理此类镜像可执行以下命令:

    docker rmi $(docker images --filter dangling=true -q)
    

    COPY --from指定其他镜像

    COPY指令的--from选项也可以指定本地或者远程仓库的镜像
    准备一个Dockerfile,内容是从ubuntu镜像中COPY一个文件到新镜像的/root/下

    FROM alpine:latest
    COPY --from=ubuntu:latest /bin/bash /root/
    CMD ["/bin/ls","/root/"]
    

    dokcer build 构建镜像

    -> [feifei@ffmac.local] [~/work/docker] docker build -t test .
    Sending build context to Docker daemon  19.46kB
    Step 1/3 : FROM alpine:latest
     ---> f70734b6a266
    Step 2/3 : COPY --from=ubuntu:latest /bin/bash /root/
    latest: Pulling from library/ubuntu
    d51af753c3d3: Pull complete
    fc878cd0a91c: Pull complete
    6154df8ff988: Pull complete
    fee5db0ff82f: Pull complete
    Digest: sha256:747d2dbbaaee995098c9792d99bd333c6783ce56150d1b11e333bbceed5c54d7
    Status: Downloaded newer image for ubuntu:latest
     ---> Using cache
     ---> 082f95ffaa69
    Step 3/3 : CMD ["/bin/ls","/root/"]
     ---> Using cache
     ---> 76fa9d9a1abd
    Successfully built 76fa9d9a1abd
    Successfully tagged test:latest
    

    dokcer run 运行镜像

    -> [feifei@ffmac.local] [~/work/docker] docker run --rm test
    bash
    

    注意事项

    • 使用.dockerignore文件,避免发送不必要的数据
    • 提供注释和维护者信息
    • 正确使用镜像版本号
    • 每条RUN都会提交为新的镜像层,尽量合并RUN指令
    • 删除缓存和临时文件
  • 相关阅读:
    [置顶] Spring的自动装配
    BZOJ2831(小强的金字塔系列问题--区域整点数求法)
    国际跆拳道联盟
    Linux如何查找某个时间点后生成的空文件
    ORACLE中关于外键缺少索引的探讨和总结
    ORA-12514, TNS:listener does not currently know of service requested in connect descriptor案例2
    SQL Server 2005 sp_send_dbmail出现Internal error at FormatRowset (Reason: Not enough storage is available to complete this operation)
    SQL Server数据库邮件发送异常案例
    MySQL二进制日志总结
    OSWatcher使用过程中小问题解决方法
  • 原文地址:https://www.cnblogs.com/flhs/p/12906162.html
Copyright © 2020-2023  润新知