Docker - Dockerfile - 常见命令简介

  1. 概述

    1. 感觉是个 比较重要的东西
  2. 有个疑问

    1. 我是先讲 docker build 还是 先讲 Dockerfile
      1. 穿插讲
        1. docker build

          1. 最基本的东西
            1. 原理
            2. -t
            3. -f
        2. docker file

          1. 各种命令
            1. 命令本身
            2. 如果需要 docker build 配合, 那就和 docker build 一起讲
  3. 准备

    1. os

      1. centos7
    2. docker

      1. client
        1. 18.09.6
      2. engine
        1. 18.09.6
    3. 知识

      1. docker
      2. docker 镜像
      3. shell 编程

1. Dockerfile

  1. 概述

    1. 简介 Dockerfile
  2. 回顾

    1. docker 镜像
      1. 概述

        1. docker 容器的模板
      2. 结构

        1. 由若干个 layer 组成
      3. 构建容器机制

        1. 构建时, 自底向上依次构造 layer
          1. 只读模式
        2. 向外提供一个读写层
      4. 创建方式

        1. docker commit

          1. 概述
            1. 将当前的容器, 构造成一个镜像
        2. docker build

          1. 概述
            1. 由 Dockerfile, 构建一个镜像
        3. 对比

          1. docker commit

            1. 方便构建
            2. 但是会缺失一些信息
          2. docker build

            1. 方便管理
              1. 环境及代码
                1. 可以用 git 管理
                2. 方便移动
                3. 方便修改, 结构清晰
      5. 建议

        1. 尽量用 Dockerfile 构建镜像
  3. Dockerfile

    1. 概述

      1. docker 构建镜像的源文件
    2. 机制

      1. docker 依次读取 Dockerfile 里的命令
      2. 指定的环境
      3. 逐层构建镜像
    3. 语法

      1. Dockerfile 语法想对较多
        1. 这个后面慢慢描述

2. docker build

  1. 概述

    1. docker client 构造镜像
  2. 准备

    1. 一个 Dockerfile
      1. 记录构建镜像的命令
    2. 一个上下文
      1. 准备构建镜像时需要的资源
  3. Dockerfile

    1. 例子

      # 最简单的 Dockerfile
      # 文件名为 Dockerfile
      FROM ubuntu:14.04
      RUN echo 'hello'
      
    2. 注意

      1. Dockerfile 的文件名
        1. 默认文件名是 Dockerfile

          1. 如果首字母没有大写, docker 可能会找不到文件
          2. 如果硬要执着名字, 需要 -f 参数来制定
            1. 这个后面会讲
        2. Dockerfile 里的 命令, 一定要 大写

          1. 小写了 docker 不认识
  4. docker build

    1. 概述

      1. 构建镜像的命令
      2. 这里简单讲下使用
        1. 其他的参数, 后面会跟 Dockerfile 的语法一起讲
    2. 准备

      1. context

        1. 作用
          1. 存放 Dockerfile
          2. 存放 image 需要的其他文件
      2. Dockerfile

        1. 作用
          1. 构建镜像的说明书
      3. 其他

        1. 执行命令时, 需要进入 context 目录
    3. 命令执行

      1. 最简单的那种

        1. 命令

          # 是的, 你没看错, 这就完了...
          # 格式: docker build <context>
          > docker build .
          
        2. 结果

          1. 镜像生成成功
        3. 问题

          1. 生成的镜像, 没有 仓库 和 tag 信息, 很难定位
      2. 添加 仓库信息 定位

        1. 命令

          # -t 选项, 可以提供 标签 的配置
          # 格式: docker build -t <repo>[:tag] <context>
          > docker build -t myrepo/image:0.0.1 .
          
        2. 结果

          1. 镜像生成成功
          2. 带有 repo 和 tag 信息
      3. 自定义 Dockerfile 和 context

        1. 命令

          # 手动指定 Dockerfile 和 context
          # 格式: docker build -t <repo>[:tag] -f <DockerfilePath> <context>
          > docker build -t myrepo/image:0.0.2 -f /root/myDockerfile /root/context
          
        2. 结果

          1. 镜像生成成功
          2. 使用的是 指定的资源
  5. 执行结果

    1. 结果

      > docker build -t <repo>/demo:0.0.2 -f Dockerfile .
      Sending build context to Docker daemon  2.048kB
      Step 1/2 : FROM ubuntu:latest
       ---> 7698f282e524
      Step 2/2 : RUN echo 'hello'
       ---> Using cache
       ---> 331b9ab46190
      Successfully built 331b9ab46190
      Successfully tagged <repo>/demo:0.0.2
      

3. Dockerfile 命令简介

  1. 概述
    1. 简单介绍命令

1. 注释

  1. 概述

    1. Dockerfile 的注释
  2. 格式

    # 以 # 开头的行
    # 行中出现的 # 则一律不被视为 注释
    # 注释不支持 换行
    
  3. 特殊注释

    1. 概述

      1. 有部分特殊的注释, 会影响 Dockerfile 的构建
    2. 注意

      1. 一类特殊注释, 只能出现一次
      2. 出现的位置, 必须在 FROM 语句之前
      3. 而且格式必须 符合要求, 否则就是 普通注释
        1. 不能换行
        2. 不能随便加空格
          1. 后跟一个空格

          2. = 前后没有空格
          3. 下面给的例子, 肯定没问题
    3. syntax

      1. 概述

        1. Dockerfile 语法指定
      2. 例子

        # syntax=docker/dockerfile
        
      3. 其他

        1. 需要有 BuildKit 的支持
        2. 默认是 docker/Dockerfile
        3. 具体可用版本, 请查询官方文档
    4. escape

      1. 概述

        1. 指定 转义字符 符号
          1. 这个名字叫啥, 我也不确定
      2. 转义字符

        1. 默认
          1. \ 开头, 后面的一个字符会被转义
        2. 设置
          1. 可以配置成其他的
          2. windows 环境下, 常用 `
      3. 例子

        # 这个例子
        # escape=`
        

2. FROM

  1. 概述

    1. 指定一个 基础镜像
  2. 基础镜像

    1. 概述

      1. 在某个镜像的基础上, 再构建镜像
    2. 作用

      1. 方便构建
        1. 省去基础的准备
      2. 加快速度
        1. 构建直接从新内容开始
        2. 基础层沿用基础镜像的内容
      3. 发展快速
        1. 你的构建, 也可以成为别人构建的基础
  3. 示例

    FROM ubuntu:latest
    
  4. 其他

    1. 通常在 Dockerfile 第一句

      1. 例外
        1. 注释
          1. 常规注释
          2. syntax
          3. escape
        2. arg
          1. 指定参数
    2. from 一定要大写

    3. tag

      1. 最好指定明确版本, 不要用 latest

3. ARG

  1. 概述

    1. 给 指定镜像参数
  2. 参数

    1. 镜像在 构建中 使用的变量
    2. 构建完成后就会 无效
    3. 构建中如果声明了 同名的环境变量, 就会被 替代
      1. 环境变量后面会提到
  3. 示例1: 定义一个变量, 用来定义 基础镜像的版本

    1. Dockerfile

      # Version 0.0.4
      ARG version
      FROM ubuntu:$version
      
    2. 命令

      # 通过 --build-arg 指定了 version 参数
      # -f 指定了 Dockerfile
      > docker image build --build-arg version=19.04 -t repo/demo:0.0.4 -f Dockerfile04 .
      
    3. 结果

      1. 构建成功

      2. 版本正确

        > docker image inspect -f '{{.RepoTags}}' repo/demo:0.0.4 
        
    4. 其他

      1. 构建中
        1. 命令行中的 step 里, 看到的还是 $version
    5. 问题: 万一我忘了加参数, 会怎么样呢

      1. 结果

        1. 生成会报错
      2. 有没有什么好办法呢

        1. 当然有啦, 加默认值
  4. 示例2: 为 arg 添加默认值

    1. Dockerfile

      # Version 0.0.5
      ARG version=19.04
      FROM ubuntu:${version}
      
    2. 命令

      > docker image build -t repo/demo:0.0.5 -f Dockerfile05 .
      
    3. 结果

      1. 创建成功
    4. 问题1: 如果我又想指定值了, 有办法吗?

      1. 当然有啦
        1. 还是用 --build-arg 指定
    5. 问题2: 这个 arg 除了指定 from 的版本信息, 还能干别的吗?

      1. 也可以在其他地方用啊
        1. 马上就开始讲了
  5. 示例3: arg 的其他使用

    1. Dockerfile

      # Version 0.0.6
      ARG version=19.04
      FROM ubuntu:${version}
      RUN echo ${version}
      
    2. 命令

      > docker image build -t repo/demo:0.0.6 -f Dockerfile06 .
      
    3. 结果

      1. 镜像成功创建
      2. echo 那行, 却没有显示出 版本号
    4. 问题1: 为什么版本号不见了?

      1. 结果

        1. 作用域问题
          1. from 前面的 arg, 作用域只能到 from 语句
          2. 之后就消失了
        2. ref
          1. 官方文档
          2. Dockerfile 中RUN 命令的ARG 为空问题。
      2. 后续

        1. 如何使用 from 前的 arg

          1. 重新声明即可

            # Version 0.0.7
            ARG version=19.04
            FROM ubuntu:${version}
            ARG version
            RUN echo "hello ${version}"
            
        2. 或者说, 在 from 后面使用 arg

        3. 再者, 还可以直接使用 env

  6. 问题: 既然在 构建完就无法使用了, 能不能用来存放 密码 之类的东西

    1. 不建议
      1. 虽然重新起来的容器看不到了
      2. 但是可以通过 'docker image history' 查看这个东西
  7. 预定义 arg

    1. 概述

      1. docker 预定义了一些 变量
    2. 列表

      # 本质上只有 四个
      # 具体干啥, 我现在还不知道
      # 但是乍一看, 是跟 网络相关的
      # 这个等以后有机会, 再讲吧
      HTTP_PROXY
      http_proxy
      HTTPS_PROXY
      https_proxy
      FTP_PROXY
      ftp_proxy
      NO_PROXY
      no_proxy
      

4. ENV

  1. 概述

    1. 镜像对应容器的 环境变量
  2. 环境变量

    1. 概述

      1. 由镜像启动容器后, 默认会带一些 环境变量
    2. 作用

      1. 环境变量可以改变环境的很多东西
        1. 或者说, 改变环境变量, 就能改变系统行为
      2. 而且环境变量这种东西, 一般是 所有用户 都能获取到的
  3. 示例1: 简单使用 环境变量

    1. Dockerfile

      # Version 0.0.8
      ARG version=19.04
      FROM ubuntu:${version}
      ARG version
      RUN echo "hello ${version}"
      ENV var="docker"
      RUN echo "hello ${var}"
      
    2. 命令

      > docker image build -t repo/demo:0.0.8 -f Dockerfile08 .
      
    3. 结果

      1. 镜像创建成功
      2. 变量成功使用
    4. 问题1: 为啥这次一上来就设置 env 的默认值, 不设置可以吗?

      1. 当然可以啦

        1. 但是, 弥补时机, 不太一样
      2. 弥补时机

        1. arg
          1. docker image build
            1. --build-arg
        2. env
          1. docker container run
            1. -e / --env
            2. 这个后面应该会 找机会讲, 还是有点用的
    5. 问题2: 会不会有这种场景, 我的某个 arg 和 env, 值其实是一样的

      1. 场景

        1. arg 和 env 值是一样的
        2. 我想在 build 时确认, 以免 后面忘了
      2. 当然可以

        1. arg 和 env 可以联动的
  4. 示例2: arg 联动 env

    1. Dockerfile

      # Version 0.0.9
      ARG version=19.04
      FROM ubuntu:${version}
      ARG version
      RUN echo "hello ${version}" 
      ENV var=${version}
      RUN echo "hello ${var}"
      
    2. 命令

      > docker image build -t repo/demo:0.0.9 -f Dockerfile09 .
      
    3. 结果

      1. 镜像正常产生
      2. var 也被赋予了 verison 的值
    4. 其他

      1. 在这种场景下, env 甚至可以和 arg 重名
        1. 结果
          1. env 被赋予 arg 的值
          2. arg 就没了
    5. 问题1: env 可以取消吗

      1. 这个在 shell 里是可以的
      2. 但是 Dockerfile 里, 是否有, 我暂时还没找到...

5. run

  1. 概述

    1. 执行命令
  2. 执行

    1. 表面
      1. 执行命令
    2. 实际
      1. 将上一层的镜像, 启动为一个容器
      2. 在容器里执行命令
      3. 将执行命令后的容器, 再整成一层新的镜像
  3. 模式

    1. shell 模式

      1. 概述

        1. 启动一个 shell, 然后执行命令
      2. 默认shell

        1. linux
          1. /bin/sh -c
        2. win
          1. cmd /S /C
      3. 切换 shell

        1. 这个可以通过后面的 SHELL 命令来做
      4. 命令

        # RUN <command> [<options and args>]
        RUN echo "hello, docker."
        
    2. exec 模式

      1. 概述

        1. 不启动 shell, 直接执行命令
      2. 不启动 shell

        1. 这个我也看不懂

          1. 官网说的很模糊
          2. 强调的, 也只有 exec 模式取不到 环境变量
        2. 好吧, 那我就理解为

          1. 取不到 环境变量
          2. 原因可能是害怕某种干扰吧
      3. 命令

        # 1. 使用 json 的 数组格式
        # 2. 命令和参数作为数组的成员
        # 3. 空格隔开的, 就是一个参数
        # 4. 每个参数, 都要用 "" 引起来
        RUN ["echo", "hello, docker."]
        # 如果硬要 环境变量
        RUN ["/bin/sh", "-c", "echo", "hello, docker."]
        
  4. 建议

    1. 加速
      1. 因为执行一个 run, 会生成一个容器和镜像
        1. run 越多, 构造时间就越长
      2. 解决
        1. 将多个命令, 写到一个 run 里

          FROM ubuntu:16.04
          RUN apt-get update \
              && apt-get install -y curl \
              && rm -rf /var/lib/apt/lists/*
          

6. shell

  1. 概述

    1. 指定 运行命令 的 shell
  2. shell

    1. 默认 shell

      1. 上一部分提过
    2. 切换 shell

      1. Dockerfile 中可以随时切
    3. 问题

      1. 切换 shell, 会不会导致 环境变量 丢失
  3. 命令

    # linux
    SHELL ["/bin/bash"]
    # win
    SHELL ["powershell", "-command"]
    

7. copy

  1. 概述

    1. 将文件从 宿主机 拷贝到 镜像
  2. 拷贝

      1. 拷贝的源, 必须在 context 下
        1. 所以路径信息, 都是 以context为根 的路径
      2. 内容
        1. 文件
        2. 目录
      3. 原内容支持 通配符
        1. 通配符 不是 正则表达式
      4. 解压
        1. 不会做
    1. 目的

      1. 拷贝的目的

        1. 文件
          1. 结尾不带 /
        2. 目录
          1. 结尾带 /
      2. 路径

        1. 如果路径不存在, 会自动创建
    2. dest 文件权限

      1. 默认

        1. uid 和 gid 都为 0
      2. 命令

        # 官网上给的例子
        # 其他的搭配, 估计只有自己尝试了...
        --chown=<userId>:<groupName> 
        --chown=<userName> 
        --chown=<userId>
        --chown=<userId>:<groupId> 
        
    3. 权限

      1. 默认 0755
        1. 这个需要用 命令 改
  3. 命令

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

8. add

  1. 概述

    1. 将文件拷贝到 镜像
      1. 来源丰富
      2. 可以解压
  2. 拷贝

      1. 拷贝的源

        1. context 下, 同 copy
        2. url
      2. 解压

        1. 不会做
      3. 其他

        1. 同 copy
    1. 目的

      1. 解压

        1. 源是 压缩包
          1. gz 等
          2. 需要去 官网 确认
        2. 目的
          1. 一个 目录
        3. 如果目的有同名文件
          1. 不会覆盖
      2. 其他

        1. 同 copy
    2. dest 文件归属

      1. 同 copy
    3. 权限

      1. 默认 0755
        1. 这个需要用 命令 改
  3. 命令

    # 从 url 获取(不解压)
    ADD http://wordpress.org/latest.zip /root/wordpress.zip
    # 解压
    ADD http://wordpress.org/latest.zip /root/wordpress/
    

9. cmd

  1. 概述

    1. 容器启动命令
    2. 配合 entrypoint
      1. 这个后面再说
  2. 启动命令

    1. 启动命令

      1. 时机

        1. 容器启动时执行的命令
      2. 只会有 一个

        1. 所以 cmd 命令只有 最后一个 会生效
      3. 替代

        1. 如果 docker run 指定了 启动命令的话
          1. cmd 的命令, 不会再执行
    2. 执行模式

      1. shell 模式

        1. 命令

          # 类似 RUN 
          CMD command param1 param2
          
      2. exec 模式

         ```
         # 类似 RUN 
         CMD ["executable","param1","param2"]
         ```
        
    3. docker run

      1. 没有命令
        1. 执行 cmd
      2. 有 命令
        1. 执行 docker run 的命令

10. entrypoint

  1. 概述

    1. 优先级更高的 启动命令
    2. 配合 cmd 可以指定 命令的默认参数
  2. 启动命令

    1. 工作模式

      1. shell 模式
        1. 同 run
      2. exec 模式
        1. 同 run
    2. 单独使用 entrypoint

      1. 同 单独使用 cmd
    3. 配合使用

      1. entrypoint

        1. 使用 exec 模式
          1. 第一个参数为, 可执行命令
          2. 后面的参数, 为 稳定的参数 或者 选项
      2. cmd

        1. 使用 exec 模式
          1. 所有参数, 都是 entrypoint 的 参数
          2. 如果 cmd 可以执行, 则会 覆盖 entrypoint
    4. docker run

      1. 没有命令
        1. 执行 entrypoint + cmd
      2. 有命令
        1. 执行 entrypoint + docker run 后面跟的 参数
  3. ref

    1. 6 Dockerfile指令详解 && ENTRYPOINT 指令

11. label

  1. 概述

    1. 添加 描述信息
  2. 描述信息

    1. 镜像元数据
  3. 命令

    LABEL maintainer='repo'
    
  4. 查看

    > docker image inspect -f '{{json .ContainerConfig.Labels}}' repo/demo:0.0.1
    

12. user

  1. 概述

    1. 指定默认用户
  2. 默认用户

    1. 默认执行命令的用户

    2. 默认值

      1. root
    3. 命令

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

13. workdir

  1. 概述

    1. 指定默认目录
  2. 默认目录

    1. docker 启动后的 pwd

      1. 命令如果不指定路径, 都会以 那里为 pwd
    2. 默认值

      1. /root/
    3. 路径

      1. 绝对路径

        1. / 开头
      2. 相对路径

        1. 直接是 路径开头
          1. 相对的是 上一个 workdir
      3. 可以解析环境变量

      4. 如果指定到一个 空路径

        1. 会主动创建
    4. 命令格式

      WORKDIR /absolutePath
      WORKDIR relativePath
      

14. onbuild

  1. 概述

    1. 触发器
  2. 触发器

    1. 触发场景

      1. 该镜像察觉到自己作为其他镜像的 基础镜像
    2. 结果

      1. 执行以 ONBUILD 开头的命令
        1. 可以理解为 在 from 语句后, 按顺序执行 onbuild 语句
        2. 然后再执行 Dockerfile 里的语句
  3. 命令

    ONBUILD <otherInstruction>
    

15. volume

  1. 概述

    1. 添加 挂载点
  2. 挂载点

    1. 概述

      1. 一个路径
      2. 但这个路径下, 会 挂载一个 卷
    2. 机制

      1. Dockerfile
        1. 指定挂载点
      2. 创建镜像
      3. 生成容器
        1. 默认行为

          1. 在 host 生成一个 卷
            1. 卷名随机
          2. 将这个卷挂载到 容器的挂载点
        2. -v

          1. 将 -v 指定的内容, 对接到挂载点
    3. 其他

      1. 如果 路径不存在, 会在容器里创建
  3. 命令

    # 列表式
    VOLUME /myvol /root/test
    # json 式
    VOLUME ["/myvol", /root/test]
    

16. expose

  1. 概述

    1. 暴露 容器端口
  2. 暴露容器端口

    1. 概述

      1. 指定某个容器端口
      2. 让这个端口 在默认的情况下, 暴露出来
    2. 暴露

      1. 对容器外可见
    3. 机制

      1. expose 某个端口
      2. 启动容器
  3. 命令

    # 指定端口和协议
    # 默认协议是 tcp
    # 可以指定 多个
    expose <port>[:<protocol>]
    
  4. 创建容器

    # 一定要加 -P
    # 这样 expose 的端口, 会随机映射到 host 的可用端口上
    # 如果没有, 则会别 映射到 null
    # 不影响 -p 选项来暴露端口
    > docker container run --rm --name demo03 -it -P -p 32769:90/tcp repo/demo:0.0.1
    
  5. 验证

    # 可以在 ports 那里, 看到暴露端口
    > docker container ls 
    

17. healthcheck

  1. 概述

    1. 健康检查
  2. 健康检查

    1. 机制

      1. 定期在容器中 执行命令,
      2. 根据 执行结果 判断容器是否健康
      3. 将健康情况, 反馈到 docker container ps 的 status 栏里
    2. 执行机制

      1. 参数

        1. 时间间隔
          1. --interval
          2. 默认值 30 s
        2. 超时时间
          1. --timeout
          2. 默认值 30s
        3. 重试次数
          1. --retries
          2. 默认值 3
      2. 健康状态

        1. starting
          1. 开始状态
        2. healthy
          1. 健康状态
        3. unhealthy
          1. 不健康状态
      3. 注意

        1. 一个镜像, 只能有一个 生效的 checkhealth
        2. 如果当前 Dockerfile 里没写, 会继承父镜像的
        3. 如果 当前 和 父镜像都有, 则以当前为准
    3. 命令

      # 拒绝继承, 
      CHECKHEALTH NONE
      # 简单示例
      # 注意, 那个 CMD 是格式, 跟 CMD 命令要区别开
      # curl 如果失败, 则容器状态变为 不健康
      checkout --interval=10s --timeout=3s --retries=3 CMD curl http://192.168.30.5:5000/v2
      

ps

  1. ref

    1. Dockerfile reference
    2. docker build
    3. Dockerfile HEALTHCHECK详解
    4. 书籍
      1. 第一本 docker 书(修订版)
      2. docker 容器与容器云
      3. spring 微服务实战
      4. docker 实践
  2. 后续

    1. 整理

      1. 花了一晚上整理的内容, 感觉还是有点乱
      2. 想把它 拆开
        1. 放一块的话, 内容可能会不全
    2. 搭建一些环境, 稍微实战一下

    3. 学习容器编排

      1. compose
      2. k8s
posted @ 2019-11-27 18:44  轩辕拾銉  阅读(490)  评论(0编辑  收藏  举报