Dokcer 的镜像和Dockerfile

Docker镜像原理

Docker镜像是由文件系统叠加而成,最底层是一个引导文件系统,即bootfs,类似于Linux/Unix的引导文件系统,当一个容器启动后,它将被移到内存中,而引导文件系统则会被卸载,以留出更多的内存。
Docker镜像的第二层是root文件系统rootfs,它位于引导文件系统之上。rootfs可以是一种或多种操作系统,如ubuntu。

  • 列出镜像

    # docker images  # 列出镜像
      REPOSITORY          TAG         IMAGE ID          CREATED             SIZE
      docker.io/python    3.7         db1c801f1c06      3 months ago        926 MB
      docker.io/mysql     latest      102816b1ee7d      3 months ago        486 MB
      docker.io/ubuntu    latest      ea4c82dcd15a      5 months ago        85.8 MB
    

    本地镜像都保存在 Docker 宿主机的 /var/lib/docker 目录下。

    镜像从仓库中下载下来,镜像保存在仓库中,而仓库存在于 Registry 中,默认的 Registry 是由 Dokcer 公司来运营的公共 Registry 服务,即 Docker Hub。

    Docker Hub 中有2种类型的仓库,用户仓库和顶层仓库,用户仓库的镜像都是由Docker用户创建的,而顶层仓库是由Docker内部的人来管理。

    用户仓库名的命名由用户名和仓库名两部分组成的。如 jamtur01/puppet。

    每个镜像仓库都可以存放很多镜像。为了区分同一仓库的不同镜像,Docker提供了标签的功能,通过在仓库名后面加上一个冒号和标签名来指定该仓库中的某一镜像。如果没有指定标签,那么Docker会自动下载latest标签的镜像。

    # docker run -ti --name new_container ubuntu:12.04 /bin/bash # 使用ubuntu:12.04镜像
    
  • 拉取镜像

    # docker pull ubuntu:12.04
    

    通过pull命令先将镜像拉取到本地,可以节省用一个新镜像启动一个容器的所需的时间(用Docker run命令从镜像启动一个容器时,如果该镜像不在本地,Docker会先从Docker Hub下载该镜像)

  • 查找镜像

    # docker search ubuntu
      INDEX       NAME                    DESCRIPTION                                     STARS    OFFICIAL  AUTOMATED
      docker.io   docker.io/ubuntu        Ubuntu is a Debian-based Linux operating s...   9369     [OK]       
      ....    
    

    可以利用该命令来查找所有Docker Hub上公共的可用镜像。

  • 删除镜像

    # docker rmi ubuntu:12.04
    

构建镜像

前面是拉取已经构建好的带有定制内容的 Docker 镜像,那么如何修改和管理自己的镜像,并且更新和管理这些镜像呢?有以下2种方法:

  • 使用 docker commit 命令
  • 使用 docker build 命令 和 Dockerfile文件
用Docker的commit命令创建镜像

使用commit命令,可以将此想像为我们往版本控制系统里面提交变更,先创建一个容器,并在容器里做出修改,就像修改代码一样,最后再将修改提交为一个新的镜像。

# docker run -i -t ubuntu /bin/bash   # 创建一个容器
# apt-get -yqq update && apt-get -y install apache2   # 安装apache2软件包(容器内的shell)
# docker commit jack/apche2:webserver # 提交定制容器
用Dockerfile构建镜像

并不推荐使用docker commit的方法来构建镜像,相反,推荐使用Dcokerfile的定义文件和 docker build命令来构建镜像。

# version: 0.0.1
FROM ubuntu:14.04
MAINTAINER xxx "[email protected]"
RUN apt-get update && apt-get install -y nginx
RUN echo "hi, I am in your container" > /usr/share/nginx/html/index.html
EXPOSE 80

Dockerfile 由一系列的指令和参数组成。每条指令,如FROM,都必须为大写字母。

Dockerfile 中的指令会按顺序从上到下执行,所以应该更具需要合理安排指令的顺序。

每条指令都会创建一个新的镜像层并对镜像进行提交。Docker 大体上按照如下流程执行Dockerfile中的指令:

  1. Docker 从基础镜像运行一个容器
  2. 执行一条指令,对容器做出修改
  3. 执行类似docker commit操作,提交一个新的镜像层
  4. Docker 再基于刚提交的镜像运行一个新的容器
  5. 执行Dockerfile中的下一条指令,直到所有指令都执行完毕
  • 构建镜像
    docker build -t="jack/static-web:v1" .
    
    每一步的构建过程中都会将结果提交为镜像,Docker的构造镜像的过程中,它会将之前的镜像层看作缓存。想略过缓存功能,可以使用--no-cache标志。
    docker build --no-cache -t="Jack/static_web:v1" 
    
    -t标志为新镜像设置了仓库和名称。

Dockerfile 中的常用命令
  • FROM
    Dockerfile文件的第一条指令必须是FROM,其后可以是各种镜像的操作指令,最后是CMD或ENTRYPOINT指定容器启动时执行的命令。

  • MAINTAINER

  • CMD 和 ENTRYPOINT
    CMD指令和ENTRYPOINT指令的作用都是为镜像指定容器启动后的命令。

    • CMD
      支持三种格式:

      1. CMD ["executable", "param1", "param2"] 使用 exec 执行,推荐方式。
      2. CMD command param1 param2 在 /bin/sh 中执行,提供给需要交互的应用。
      3. CMD ["param1", "param2"] 提供给 ENTRYPOINT 的默认参数。

      启动容器时执行的命令,每个 Dockerfile 只能有一条 CMD 命令,如果指定了多条命令,只有最后一条会被执行。
      如果用户启动容器时候指定了运行的命令,则会覆盖掉 CMD 指定的命令。

    • ENTRYPOINT
      支持两种格式:

      1. ENTRYPOINT ["executable", "param1", "param2"]
      2. ENTRYPOINT command param1 param2(shell中执行)

      配置容器启动后执行的命令,并且不可被 docker run 提供的参数覆盖,而是将docker run指定的参数当做ENTRYPOINT指定命令的参数。
      每个 Dockerfile 中只能有一个 ENTRYPOINT,当指定多个时,只有最后一个起效。

    • 测试1

      • test.sh
        #!/bin/bash
        echo "args: ${@}"
        
      • Dockerfile
        FROM ubuntu
        MAINTAINER [email protected]
        
        ADD test.sh /
        RUN chmod +x /test.sh
        
        CMD ["/test.sh"]
        
      • 测试结果
        # docker build -t=test1:latest .
        # docker run --rm -ti test1
          args:  
        # docker run --rm -ti test1 /bin/bash -c "echo hello world"
          hello world
        
        可见docker run命令启动容器时指定的运行命令可以覆盖Dockerfile文件中CMD指令指定的命令。
    • 测试2

      • Dockerfile
        FROM ubuntu
        MAINTAINER [email protected]
        
        ADD test.sh /
        RUN chmod +x /test.sh
        
        ENTRYPOINT ["/test.sh"]
        
      • 测试结果
        # docker build -t=test2:latest .
        # docker run --rm -ti test2
          args:  
        # docker run --rm -ti test2 /bin/bash -c "echo hello world"
          args: /bin/bash -c echo hello world
        
        docker run命令指定的容器运行命令不能覆盖Dockerfile文件中ENTRYPOINT指令指定的命令,反而被当做参数传递给ENTRYPOINT指令指定的命令。
    • 测试3

      • Dockerfile
        FROM ubuntu
        MAINTAINER [email protected]
        
        ADD test.sh /
        RUN chmod +x /test.sh
        
        ENTRYPOINT ["/test.sh", "arg1"]
        CMD ["arg2"]
        
      • 测试结果
        # docker build -t=test3:latest .
        # docker run --rm -ti test3
          args: arg1 arg2  
        # docker run --rm -ti test3 arg3
          args: arg1 arg3
        
        上面第一个容器的运行结果可以看出CMD指令为ENTRYPOINT指令设置了默认参数;从第二个容器的运行结果看出,docker run命令指定的参数覆盖了CMD指令指定的参数。
    • 注意:
      CMD指令为ENTRYPOINT指令提供默认参数是基于镜像层次结构生效的,而不是基于是否在同个Dockerfile文件中。意思就是说,如果Dockerfile指定基础镜像中是ENTRYPOINT指定的启动命令,则该Dockerfile中的CMD依然是为基础镜像中的ENTRYPOINT设置默认参数。

  • COPY 和 ADD

  • EXPOSE

  • VOLUME

  • ENV

  • LABEL

利用Dockerfile制作镜像
  • centos
FROM centos

RUN yum update -y
RUN yum install -y vim tcpdump  iproute iproute-doc nc
  • 构建镜像
    docker build --no-cache -t="centos_net" ./

你可能感兴趣的:(Dokcer 的镜像和Dockerfile)