zoukankan      html  css  js  c++  java
  • Dockerfile 浅析

    一、Dockerfile 简介

    1、Dockerfile 是什么

    Dockerfile 是用来构建 Docker 镜像的构建文件,它是由一系列命令和参数构成的脚本

    2、镜像实例化为容器的三个步骤

    2.1、编写 Dockerfile 文件

    2.2、根据 Dockerfile 文件,使用 docker build 命令来构建镜像

    2.3、docker run 命令启动容器

    3、Dockerfile 内容和格式

    我们这里以 centos 为例,登录 docker hub 官网: https://registry.hub.docker.com/

    3.1、搜索 centos

    3.2、选择官方镜像

    3.3、Dockerfile 具体内容如下:

    • 每条保留字指令都必须为大写字母且后面要跟随至少一个参数
    • 指令按照从上到下,顺序执行
    • # 表示注释
    • 每条指令都会创建一个新的镜像层,并对镜像进行提交

     

    二、Dockerfile 、Docker 镜像、Docker 容器的区别

    从应用软件的角度来看, Dockerfile、Docker 镜像与 Docker 容器分别代表软件的三个不同阶段
    Dockerfile 是软件的原材料
    Docker 镜像是软件的交付品
    Docker 容器则可以认为是软件的运行态
    Dockerfile 面向开发, Docker 镜像成为交付标准, Docker 容器则涉及部署与运维,三者缺一不可,合力充当 Docker 体系的基石

    2.1、Dockerfile:需要定义一个 Dockerfile ,Dockerfile 定义了进程需要的一切东西, Dockerfile 涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道,这时需要考虑如何设计 namespace 的权限控制)等等.

    2.2、Docker 镜像,在用 Dockerfile 定义一个文件之后, docker build 时会产生一个 Docker 镜像,当运行 Docker 镜像时,会真正开始提供服务.

    2.3、Docker容器,容器是直接提供服务的.

    三、Dockerfile 构建过程解析

    Docker 保留字及其代表含义

    Dockerfile 保留字 说明
    FROM  当前新镜像是基于哪个镜像的
    MAINTAINER 镜像维护者的姓名和邮箱地址
    RUN 容器构建时需要运行的命令
    EXPOSE 当前镜像对外暴露的端口
    ENV 镜像构建过程中的环境变量
    WORKDIR 容器启动后,终端默认登录进来的工作目录(启动容器时的一个落脚点)
    ADD 将宿主机目录下的文件拷贝进镜像且 ADD 命令会自动处理 URL 和解压 tar 压缩包
    COPY 类似 ADD ,拷贝文件和目录到镜像中.将从构建上下文目录中<源路径>的文件/目录复制到新的一层的镜像内的<目标路径>位置
    VOLUME 容器数据卷,用于数据保存和持久化工作
    CMD 指定一个容器启动时要运行的命令, Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效, CMD 会被 docker run 之后的参数替换
    ENTRYPOINT 指定一个容器启动时要运行的命令, ENTRYPOINT 的目的和 CMD 一样,都是在指定容器启动程序及参数
    ONBUILD 当构建一个被继承的 Dockerfile 时运行命令,父镜像在被子继承后父镜像的 ONBUILD 被触发

    3.1、案例一(自定义 mycentos 镜像)

    我们先看一下官方拉取的镜像,存在如下的问题

    针对上面的问题,我们是否可以自定义一个 centos , 这个自定义的镜像可以支持 vim 、ifconfig 命令

    centos 官方镜像的 Dockerfile 定义如下:

    FROM scratch
    ADD centos-7-x86_64-docker.tar.xz /
    
    LABEL 
        org.label-schema.schema-version="1.0" 
        org.label-schema.name="CentOS Base Image" 
        org.label-schema.vendor="CentOS" 
        org.label-schema.license="GPLv2" 
        org.label-schema.build-date="20201113" 
        org.opencontainers.image.title="CentOS Base Image" 
        org.opencontainers.image.vendor="CentOS" 
        org.opencontainers.image.licenses="GPL-2.0-only" 
        org.opencontainers.image.created="2020-11-13 00:00:00+00:00"
    
    CMD ["/bin/bash"]
    

    我们可以参考官方镜像的 Dockerfile 来自定义 Dockerfile ,然后通过自定义的 Dockerfile 来构建符合我们要求的镜像

    3.1.1、新建一个目录,编写自定义 Dockerfile 文件

    // 继承 centos 镜像
    FROM centos 
    // 环境变量路径
    ENV MYPATH /usr/local/mydocker
    // 进入容器的时候,默认会进入该入境
    WORKDIR $MYPATH
    // 支持 vim 命令
    RUN yum -y install vim
    // 支持 curl 命令
    RUN yum -y install curl
    // 支持查询 ip
    RUN yum -y install net-tools
    // 容器启动之后对外暴露的端口
    EXPOSE 80
    // Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效
    CMD echo $MYPATH
    CMD echo "mycentos for xiao mao mao is ok"
    // 实际生效的命令
    CMD [ "curl", "-s", "http://www.baidu.com" ]
    

    3.1.2、使用 docker build 命令构建镜像

    // -f 参数是为了指定 Dockerfile 的位置(可以是绝对路径,也可是相对当前操作路径),默认的情况下标准的命名就是 Dockerfile,如果文件的命名是 Dockerfile ,可以省略不写
    // /root/mydocker 是构建镜像的构件存放目录, Dockerfile 中通过 ADD 来将该目录下的构件添加进容器(它与 Dockerfile 存在的路径不是一回事)
    // 整体的含义就是通过 /root/mydocker/Dockerfile 文件来构建镜像
    docker build -f /root/mydocker/Dockerfile -t xiaomaomao/centos:use-cmd /root/mydocker
    

    3.1.3、运行镜像使之成为容器

    docker run -it --name mycentos xiaomaomao/centos:use-cmd

    3.1.4、我们这里是通过命令 docker run -it --name mycentos xiaomaomao/centos:use-cmd 来运行容器的,还记不记得我们自定义的 Dockerfile 里面有编写 CMD 命令,这个命令就是我们运行 Docker 镜像的默认命令,并且多个 CMD 命令只有最后一个生效,实际上是相当于运行如下的命令

    docker run -it --name mycentos xiaomaomao/centos:use-cmd curl -s http://www.baidu.com
    

    也就是运行镜像的时候就会直接去访问百度的首页

    3.1.5、下面我们又有了新的需求,希望访问百度首页的时候能够返回报文头(需要在 curl 命令后面加上参数 -i),如果想要完成需求,完整的命令应该如下

    docker run -it --name mycentos xiaomaomao/centos:use-cmd curl -s -i http://www.baidu.com
    

    执行上述的命名确实是能够完成需求,因为 curl -s -i http://www.baidu.com 命令会覆盖我们在 Dockerfile 里面默认的 curl -s http://www.baidu.com 命令

    但是呢,我现在不想去覆盖 Dockerfile 里面的命令,只想通过添加参数 -i 的方式去实现需求,也就是执行下面这条命令实现需求

    docker run -it --name mycentos xiaomaomao/centos:use-cmd -i
    

    执行完命令之后,结果出现了报错,因为 docker run 命令的标准形式是这样的

    docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
    

    -i 不是具体的 CMD 命令,所以会出现报错

    那么有没有其它办法呢,答案是有的,这个时候就需要是用 ENTRYPOINT 保留字来代替 CMD 保留字

    重写修改 Dockerfile 如下,把 CMD 换成 ENTRYPOINT

    FROM centos
    ENV MYPATH /usr/local/mydocker
    WORKDIR $MYPATH
    RUN yum -y install vim
    RUN yum -y install curl
    RUN yum -y install net-tools
    EXPOSE 80
    CMD echo $MYPATH
    CMD echo "mycentos for xiao mao mao is ok"
    // 将 CMD 改为 ENTRYPOINT
    ENTRYPOINT [ "curl", "-s", "http://www.baidu.com" ]
    

    重新构建奖项,然后运行镜像,此时加上参数 -i 就返回了头部信息

    总结 CMD 和 ENTRYPOINT 的区别

    CMD: 运行容器的时候,最后加的参数 -i 会覆盖 Dockerfile 里面 CMD 保留字定义的命令,使整个命令变成如下(这种命令是错误的,因为 -i 不是 CMD 命令)

    docker run -it --name mycentos xiaomaomao/centos:use-cmd -i

    ENTRYPOINT: 运行容器的时候,最后加的参数 -i 会被当做参数追加到 Dockerfile 里面 ENTRYPOINT 保留字定义的命令里面,也就是当使用如下命令时

    docker run -it --name mycentos xiaomaomao/centos:use-entrypoint -i
    

    就相当于

    docker run -it --name mycentos xiaomaomao/centos:use-entrypoint curl -s -i http://www.baidu.com
    

      

    3.2、案例二、自定义 tomcat 镜像

    3.2.1、编写 Dockerfile 文件

    tomcat-dockerfile 文件内容如下

    # 继承基础镜像
    FROM centos
    # 维护者姓名和邮箱地址
    MAINTAINER xiaomaomao<xiaomaomao@163.com>
    # 环境变量
    ENV MYPATH /usr/local
    # 把 java 与 tomcat 添加到容器中指定目录下
    ADD jdk-8u261-linux-x64.tar.gz $MYPATH/
    ADD apache-tomcat-8.5.60.tar.gz $MYPATH/
    # 安装 vim 编辑器
    RUN yum -y install vim
    # 设置工作访问时候的 WORKDIR 路径,进入容器时的默认工作目录
    WORKDIR $MYPATH/apache-tomcat-8.5.60/
    # 配置 java 与 tomcat 环境变量
    ENV JAVA_HOME /usr/local/jdk1.8.0_261
    ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
    ENV CATALINA_HOME $MYPATH/apache-tomcat-8.5.60
    ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
    # 把宿主机当前上下文的 xiaomaomao.txt 拷贝到容器 /usr/local/webapps 路径下
    COPY xiaomaomao.txt $CATALINA_HOME/webapps/
    # 添加容器数据卷
    VOLUME $CATALINA_HOME/webapps/
    # 容器运行时监听的端口
    EXPOSE  8080
    # 启动时运行tomcat 并打印日志
    CMD $CATALINA_HOME/bin/startup.sh && tail -F $CATALINA_HOME/logs/catalina.out

    3.2.2、使用 docker build 构建镜像

    构建成功信息如下

    3.2.3、查看镜像

    3.2.4、启动镜像

    3.2.5、查看镜像是否启动成功,启动成功后进入容器

    3.2.6、查看 tomcat 容器的挂载的容器数据卷

    宿主机目录

    容器目录

    对比可以发现,容器的挂载目录是我们在 Dockerfile 中定义的,宿主机挂载的目录是 Docker 帮我们随机生成的,两个目录里面的内容是相同的,并且经过测试,数据可以同步

    3.2.7、宿主机的挂载目录新建一个 test 目录,在 test 目录下新建一个 a.jsp 文件,写入如下内容

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Insert title here</title>
      </head>
      <body>
        hello i am xiao mao mao, when will you back?
      </body>
    </html>
    

    3.2.8、此时,由于通过容器数据卷同步信息,在容器的 webapps 下会有 test 目录

    3.2.9、访问 a.jsp

    3.2.10、同理,比如我们以后部署 war 包,也可以只通过操作宿主机,就可以将 war 包部署到容器内的 tomcat 中

  • 相关阅读:
    忍者X2简介+安装包+安装环境说明 [复制链接]
    拖拽的功能,可以看看这个
    openNI驱动控制kinect马达
    室内机器人漫游
    石头剪子布 C++多态实现
    PCL的KinectFusion开源实现
    Microsoft Kinect SDK中的Event Model
    小说下载阅读器_章节保存为XML并显示
    面试题:猫叫、老鼠跑、人醒的一点看法
    JQuery EasyUI之treegrid级联勾选的简单改进版
  • 原文地址:https://www.cnblogs.com/xiaomaomao/p/14202525.html
Copyright © 2011-2022 走看看