zoukankan      html  css  js  c++  java
  • Docker从入门到精通<6>-使用Dockerfile构建镜像

    Dockerfile自动构建docker镜像

    Dockerfile 语法格式

    ENV

    格式:ENV <key> <value>或ENV <key>=<value> ...

    ENV指令可以为镜像创建出来的容器声明环境变量。并且在Dockerfile中,ENV指令声明的环境变量会被后面的特定指令(即ENV、ADD、COPY、WORKDIR、EXPOSE、VOLUME、USER)解释使用。其他指令使用环境变量时,使用格式为$variable_name或者${variable_name}。在变量前面添加斜杠可以转义,如$foo或者${foo},将会被分别转换为$foo和${foo},而不是环境变量所保存的值。另外,ONBUILD指令不支持环境替换。

    FROM [--platform=<platform>] <image>[@<digest>] [AS <name>] # 构建新镜像所依赖的基础镜像

    RUN  <command> |  ["executable", "param1", "param2"] 

    执行命令,这里有两种方式,第一种默认直接调用系统shell,第二种会转换为json,所以一定要用双引号。如果命令比较长可以使用反斜杠进行换行处理。

    shell形式不同exec形式不调用命令 shell。这意味着不会发生正常的 shell 处理。例如, RUN [ "echo", "$HOME" ]不会对 进行变量替换$HOME如果你想要 shell 处理,那么要么使用shell形式,要么直接执行 shell,例如:RUN [ "sh", "-c", "echo $HOME" ]当使用 exec 形式并直接执行 shell 时,就像 shell 形式一样,是 shell 进行环境变量扩展,而不是 docker。

    如果命令中需要转义,需要用反斜杠进行转义。

    ADD 

      ADD [--chown=<user>:<group>] <src>... <dest>

      ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]

    把文件、目录、或者远程的文件的url,从src 拷贝到 镜像 的文件系统中的dest位置。

    注意:

    1. --chown 仅适用于linux系统。

    2. src源文件等可以进行模糊匹配,指定go语言中的filepath.Match,支持 .*?

    3. dest 的位置,是相对于WORKDIR的位置,比如WORKDIR 为/data/, dest为app/,那么实际上的dest路径为/data/app/

    4. dest必须以斜杠结尾,否则将dest将被视为一个文件

    5. 如果src为可识别的压缩格式(identity、gzip、bzip2 或 xz)的压缩文件,复制到dest将被自动解压缩

    COPY

    COPY [--chown=<user>:<group>] <src>... <dest>
    COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]
    功能和ADD几乎相同,但是少了两种功能:
    1. 不支持src为url
    2. 不止src为压缩归档文件
    不过一般推荐使用COPY,COPY更加透明

    CMD

    CMD指令有3种格式:

    • CMD <command>(shell格式)
    • CMD ["executable", "param1", "param2"](exec格式,推荐格式)
    • CMD ["param1", "param2"](为ENTRYPOINT指令提供参数)

    CMD指令提供容器运行时的默认值,这些默认值可以是一条指令,也可以是一些参数。一个Dockerfile中可以有多条CMD指令,但只有最后一条CMD指令有效。CMD ["param1", "param2"]格式是在CMD指令和ENTRYPOINT指令配合时使用的,CMD指令中的参数会添加到ENTRYPOINT指令中。使用shell和exec格式时,命令在容器中的运行方式与RUN指令相同。不同在于,RUN指令在构建镜像时执行命令,并生成新的镜像;CMD指令在构建镜像时并不执行任何命令,而是在容器启动时默认将CMD指令作为第一条执行的命令。如果用户在命令行界面运行docker run命令时指定了命令参数,则会覆盖CMD指令中的命令。

    LABEL <key>=<value> <key>=<value> <key>=<value> ...   构建完镜像后,我们可以通过  docker image inspect --format='' myimage 查看标签信息

    MAINTAINER  作者信息,已经弃用,可以用label取代

    EXPOSE <port> [<port>/<protocol>...]

    指定docker容器在运行时侦听的端口,还可以指定协议是TCP,还是UDP,默认为TCP,例如:EXPOSE 80/TCP, 无论这个参数如何设置docker -p 都将覆盖这个参数,-P表示可以设置随机端口。 

    ENTRYPOINT

    ENTRYPOINT ["executable", "param1", "param2"] # 推荐使用格式

    ENTRYPOINT command param1 param2

    ENTRYPOINT指令和CMD指令类似,都可以让容器在每次启动时执行相同的命令,但它们之间又有不同。一个Dockerfile中可以有多条ENTRYPOINT指令,但只有最后一条ENTRYPOINT指令有效。当使用shell格式时,ENTRYPOINT指令会忽略任何CMD指令和docker run命令的参数,并且会运行在/bin/sh -c中。这意味着ENTRYPOINT指令进程为/bin/sh -c的子进程,进程在容器中的PID将不是1,且不能接受Unix信号。即当使用docker stop <container>命令时,命令进程接收不到SIGTERM信号。我们推荐使用exec格式,使用此格式时,docker run传入的命令参数会覆盖CMD指令的内容并且附加到ENTRYPOINT指令的参数中。从ENTRYPOINT的使用中可以看出,CMD可以是参数,也可以是指令,而ENTRYPOINT只能是命令;另外,docker run命令提供的运行命令参数可以覆盖CMD,但不能覆盖ENTRYPOINT.

    VOLUME 

    VOLUME ["/data"]

    VOLUME指令创建一个具有指定名称的挂载点,并将其标记为保存来自本机主机或其他容器的外部挂载卷点。该值可以是 JSON 数组、VOLUME ["/var/log/"]或带有多个参数的纯字符串,例如VOLUME /var/logVOLUME /var/log /var/db

    USER

    USER <user>[:<group>] 或者 USER <UID>[:<GID>]

    所述USER指令集运行的image和用于任何时要使用的用户名(或UID)和任选的所述用户组(或GID) RUNCMD和 ENTRYPOINT它后面的指令Dockerfile

    注意:当用户没有主要组时,映像(或下一个说明)将与该root一起运行

    WORKDIR

    WORKDIR 指令为 Dockerfile 中跟随它任何 RUN、CMD、ENTRYPOINT、COPY 和 ADD 指令设置工作目录。 如果 WORKDIR 不存在,即使它没有在任何后续 Dockerfile 指令中使用,它也会被创建。

    WORKDIR 指令可以在 Dockerfile 中多次使用。 如果提供了相对路径,它将相对于前一个 WORKDIR 指令的路径。 例如:

    WORKDIR /a

    WORKDIR b

    WORKDIR c

    RUN pwd

    最终pwd命令的输出Dockerfile将是/a/b/c.

    ONBUILD (when combined with one of the supported instructions above)
    用的比较少

    Dockerfile编写经验总结:

    • 在构建Dockefile镜像时最好加上标语识别的标签,docker buit -t  python3.8-flask:v1 .
    • 在选择基础镜像的时候,尽量选择小的镜像,便于快速构建,快速发布;前期或者测试环境为了方便排错,可以选择大一点的镜像作为基础镜像。
    • 充分利用缓存。Docker daemon会顺序执行Dockerfile中的指令,而且一旦缓存失效,后续命令将不能使用缓存。为了有效地利用缓存,需要保证指令的连续性,尽量将所有Dockerfile文件中相同的部分都放在前面,而将不同的部分放在后面
    • 不要在Dockerfile中做端口映射,否则一台机器上只能部署一个容器实例。因为在Dockerfile中做完端口映射,相当用Hostport被占用了。
    • CMD和ENTRYPOINT指令  CMD和ENTRYPOINT指令指定了容器运行的默认命令,推荐二者结合使用。使用exec格式的ENTRYPOINT指令设置固定的默认命令和参数,然后使用CMD指令设置可变的参数。
    • 为了使Dockerfile易读、易理解和可维护,在使用比较长的RUN指令时可以使用反斜杠分隔多行。大部分使用RUN指令的场景是运行apt-get命令,在该场景下请注意如下几点。❏ 不要在一行中单独使用指令RUN apt-get update。当软件源更新后,这样做会引起缓存问题,导致RUN apt-get install指令运行失败。所以,RUNapt-get update和RUN apt-get install应该写在同一行,如RUN apt-getupdate && apt-get install -y package-bar package-foo package-baz。❏ 避免使用指令RUN apt-get upgrade和RUN apt-get dist-upgrade。因为在一个无特权的容器中,一些必要的包会更新失败。如果需要更新一个包(如foo),直接使用指令RUN apt-get install -y foo。在Docker的核心概念中,提交镜像是廉价的,镜像之间有层级关系,像一颗树。不要害怕镜像的层数过多,我们可以在任一层创建一个容器。因此,不要将所有的命令写在一个RUN指令中。RUN指令分层符合Docker的核心概念,这很像源码控制。
    • 正确使用ADD与COPY指令  尽管ADD和COPY用法和作用很相近,但COPY仍是首选。COPY相对于ADD而言,功能简单够用。COPY仅提供本地文件向容器的基本复制功能。ADD有额外的一些功能,比如支持复制本地压缩包(复制到容器中会自动解压)和URL远程资源。因此,ADD比较符合逻辑的使用方式是ADD roots.tar.gz /。当在Dockerfile中的不同部分需要用到不同的文件时,不要一次性地将这些文件都添加到镜像中去,而是在需要时逐个添加,这样也有利于充分利用缓存。另外,考虑到镜像大小的问题,使用ADD指令去获取远程URL中的压缩包不是推荐的做法。应该使用RUN wget或RUN curl代替。这样可以删除解压后不再需要的文件,并且不需要在镜像中再添加一层。

    2048小游戏

    我们首先把2048这个小游戏的项目,下载到本地, 并编写Dockerfile

    [root@vm1 ~]# mkdir /root/docker/2048 -p
    [root@vm1 ~]#
    [root@vm1 ~]# cd /root/docker/2048/
    [root@vm1 2048]# ls
    [root@vm1 2048]#
    [root@vm1 2048]# wget https://github.com/gabrielecirulli/2048/archive/refs/heads/master.zip
    ...
    
    2021-07-15 16:20:54 (1.03 MB/s) - “master.zip” 已保存 [332945]
    [root@vm1 2048]# ls
    master.zip
    [root@vm1 2048]# unzip master.zip
    ...
    [root@vm1 2048]# mv 2048-master 2048
    [root@vm1 2048]# cat Dockerfile
    FROM nginx:1.20
    RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
    RUN echo 'Asia/Shanghai' >/etc/timezone
    COPY 2048 /usr/share/nginx/html/
    EXPOSE 80
    

    注意这里的Dockerfile

    FROM nginx:1.20   # 基础镜像
    RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime   # 设置容器时区信息
    RUN echo 'Asia/Shanghai' >/etc/timezone
    COPY 2048 /usr/share/nginx/html/    # 把项目代码部署到nginx server
    EXPOSE 80   # 监听80端口
    

      因为nginx官方本身已经设置好了,入口启动命令,所以我们无需再进行配置。

    开始构建镜像

    [root@vm1 2048]# docker build -t nginx-2048 .
    [+] Building 1.0s (9/9) FINISHED
     => [internal] load build definition from Dockerfile                                                                                                           0.2s
     => => transferring dockerfile: 258B                                                                                                                           0.0s
     => [internal] load .dockerignore                                                                                                                              0.3s
     => => transferring context: 2B                                                                                                                                0.0s
     => [internal] load metadata for docker.io/library/nginx:1.20                                                                                                  0.0s
     => [1/4] FROM docker.io/library/nginx:1.20                                                                                                                    0.0s
     => [internal] load build context                                                                                                                              0.2s
     => => transferring context: 4.17kB                                                                                                                            0.0s
     => CACHED [2/4] RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime                                                                                   0.0s
     => CACHED [3/4] RUN echo 'Asia/Shanghai' >/etc/timezone                                                                                                       0.0s
     => CACHED [4/4] COPY 2048 /usr/share/nginx/html/                                                                                                              0.0s
     => exporting to image                                                                                                                                         0.3s
     => => exporting layers                                                                                                                                        0.0s
     => => writing image sha256:747803a902f250a62eb3996ca5c0478835ff4884df4ac2163f2e7fff1c4287cc                                                                   0.0s
     => => naming to docker.io/library/nginx-2048                                                                                                                  0.0s
    [root@vm1 2048]# docker images |egrep nginx-2048
    nginx-2048                      latest              747803a902f2   15 minutes ago   134MB
    [root@vm1 2048]# docker run -d -p 80:80 --name=nginx-2048-server nginx-2048
    83d6be13b4b1f581a7afd057e4988125a1df812771f0a86a26ae30c130ffbdcf
    [root@vm1 2048]#
    [root@vm1 2048]# docker ps |egrep 'nginx-2048-server'
    83d6be13b4b1   nginx-2048      "/docker-entrypoint.…"   21 seconds ago      Up 19 seconds      0.0.0.0:80->80/tcp, :::80->80/tcp           nginx-2048-server  

    开始测试

    拥抱不确定,未来可期!喜欢该文章请不吝点赞推荐,如有疑问欢迎留言,我们一起探讨。
  • 相关阅读:
    验证视图状态 MAC 失败的处理办法总结![come from internet]
    在ie6上 让他显示png图片
    挑灯夜战 css hack 再次学习 IE浏览器常见的9个css Bug以及解决办法
    fileupload上传 and IE8 and VS2008 实现图片预览[new Name:经典的Fakepath错误]
    大项目开发语言的选择
    虚拟机安装linux:未找到任何驱动程序
    objectc中的bool
    关于数字内容网站的一些想法
    iphone开发论坛
    在centos5.3下安装mysql5启动时报错
  • 原文地址:https://www.cnblogs.com/yang-ning/p/15011125.html
Copyright © 2011-2022 走看看